[css] How to create a drop shadow only on one side of an element?

Is there a way to drop the shadow only on the bottom?. I have a menu with 2 images next to each other. I don't want a right shadow because it overlaps the right image. I don't like to use images for this so is there a way to drop it only on the bottom like:

box-shadow-bottom: 10px #FFF; or similar?

-moz-box-shadow: 0px 3px 3px #000;
-webkit-box-shadow: 0px 3px 3px #000;
box-shadow-bottom: 5px #000;
/* For IE 8 */
-ms-filter: "progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=180, Color='#000000')";
/* For IE 5.5 - 7 */
filter: progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=180, Color='#000000');

This question is related to css

The answer is


Another idea based on the answer of @theengineear where I will use inset instead of polygon. It's easier since it works the same way as margin or padding. I will also rely on CSS variable to easily define all the different cases.

_x000D_
_x000D_
.shadow {
  box-shadow: 0 0 8px 5px rgba(200, 0, 0, 0.5);
  clip-path:inset(var(--t,0) var(--r,0) var(--b,0) var(--l,0))
}

.top { --t:-100%; }
.right { --r:-100%;}
.bottom { --b:-100%; }
.left { --l:-100%;}


/* layout for example */

.box {
  display: inline-block;
  vertical-align: top;
  background: #338484;
  color: #fff;
  width: 4em;
  height: 2em;
  margin: 1em;
  padding: 1em;
}
_x000D_
<div class="box">none</div>
<div class="box shadow top right left bottom">all</div>
<div class="box shadow top">top</div>
<div class="box shadow right">right</div>
<div class="box shadow bottom">bottom</div>
<div class="box shadow left">left</div>
<div class="box shadow bottom right">bottom right</div>
<div class="box shadow bottom top">top bottom</div>
<div class="box shadow left top right">top left right</div>
<div class="box shadow left right"> left right</div>
_x000D_
_x000D_
_x000D_


You can do that like this:

General syntax:

selector {
   box-shadow: topBoxShadow, bottomBoxShadow, rightBoxShadow, leftBoxShadow
}

Example: we want to make only a bottom box shadow with red color,

so to do that we have to set all the sides options where we have to set the bottom box shadow options and set all the others as empty as follow:

.box {
     -moz-box-shadow: 0 0 0 transparent ,0 0 10px red, 0 0 0 transparent, 0 0 0 transparent
     -o-box-shadow: 0 0 0 transparent ,0 0 10px red, 0 0 0 transparent, 0 0 0 transparent
     -webkit-box-shadow: 0 0 0 transparent ,0 0 10px red, 0 0 0 transparent, 0 0 0 transparent
     box-shadow: 0 0 0 transparent ,0 0 10px red, 0 0 0 transparent, 0 0 0 transparent
}

It is better to look up shadow:

.header{
    -webkit-box-shadow: 0 -8px 73px 0 rgba(0,0,0,0.2);
    -moz-box-shadow: 0 -8px 73px 0 rgba(0,0,0,0.2);
    box-shadow: 0 -8px 73px 0 rgba(0,0,0,0.2);
}

this code is currently using on stackoverflow web.


inner shadow

_x000D_
_x000D_
 .shadow {_x000D_
   -webkit-box-shadow: inset 0 0 9px #000;_x000D_
   -moz-box-shadow: inset 0 0 9px #000;_x000D_
   box-shadow: inset 0 0 9px #000;_x000D_
 }
_x000D_
<div class="shadow">wefwefwef</div>
_x000D_
_x000D_
_x000D_


If your background is solid (or you can reproduce it using CSS), you can use linear gradient that way:

_x000D_
_x000D_
div {_x000D_
  background-image: linear-gradient(to top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.3) 5px, #fff 5px, #fff 100%)_x000D_
}
_x000D_
<div>_x000D_
<p>Foobar</p>_x000D_
<p>test</p>_x000D_
</div>
_x000D_
_x000D_
_x000D_

This will generate a 5px gradient at the bottom of the element, from black at 30% opacity to completely transparent. The rest of the element has white background. Of course, changing the last 2 color stops of the linear gradient, you could make the background completely transparent.


It's always better to read the specs. There is no box-shadow-bottom property, and as Lea points out you should always place the un-prefixed property at the bottom, after the prefixed ones.

So it's:

_x000D_
_x000D_
.shadow {_x000D_
  -webkit-box-shadow: 0px 2px 4px #000000;_x000D_
  -moz-box-shadow: 0px 2px 4px #000000;_x000D_
  box-shadow: 0px 2px 4px #000000;_x000D_
}
_x000D_
<div class="shadow">Some content</div>
_x000D_
_x000D_
_x000D_


I also needed a shadow but only under an image and set in slightly left and right. This worked for me:

.box-shadow {
   -webkit-box-shadow: 5px 35px 30px -25px #888888;
      -moz-box-shadow: 5px 35px 30px -25px #888888;
           box-shadow: 5px 35px 30px -25px #888888;
}

The element this is applied to is a page-wide image (980px x 300px).

If it helps when fiddling with the settings, they run as follows:

horizontal shadow, vertical shadow, blur distance, spread (i.e. shadow size), and color.


I think this is what you're after?

_x000D_
_x000D_
.shadow {_x000D_
  -webkit-box-shadow: 0 0 0 4px white, 0 6px 4px black;_x000D_
  -moz-box-shadow: 0 0 0 4px white, 0 6px 4px black;_x000D_
  box-shadow: 0 0 0 4px white, 0 6px 4px black;_x000D_
}
_x000D_
<div class="shadow">wefwefwef</div>
_x000D_
_x000D_
_x000D_


Just use the spread parameter to make the shadow smaller:

_x000D_
_x000D_
.shadow {_x000D_
  -webkit-box-shadow: 0 6px 4px -4px black;_x000D_
  -moz-box-shadow: 0 6px 4px -4px black;_x000D_
  box-shadow: 0 6px 4px -4px black;_x000D_
}
_x000D_
<div class="shadow">Some content</div>
_x000D_
_x000D_
_x000D_

Live demo: http://dabblet.com/gist/a8f8ba527f5cff607327

To not see any shadow on the sides, the (absolute value of the) spread radius (4th parameter) needs to be the same as the blur radius (3rd parameter).


You could also just do a gradient on the bottom - this was helpful for me because the shadow I wanted was on an element that was already semi-transparent, so I didn't have to worry about any clipping:

&:after {
      content:"";
      width:100%;
      height: 8px;
      position: absolute;
      bottom: -8px;
      left: 0;
      background: linear-gradient(to bottom, rgba(0,0,0,0.65) 0%,rgba(0,0,0,0) 100%);
    }

Just make the "bottom" and "height" properties match and set your rgba values to whatever you want them to be at the top / bottom of the shadow


How about just using a containing div which has overflow set to hidden and some padding at the bottom? This seems like much the simplest solution.

Sorry to say I didn't think of this myself but saw it somewhere else.

Using an element to wrap the element getting the box-shadow and a overflow: hidden on the wrapper you could make the extra box-shadow disappear and still have a usable border. This also fixes the problem where the element is smaller as it seems, because of the spread.

Like this:

#wrapper { padding-bottom: 10px; overflow: hidden; }
#elem { box-shadow: 0 0 10px black; }

Content goes here

Still a clever solution when it has to be done in pure CSS!

As said by Jorgen Evens.


update on someone else his answer transparant sides instead of white so it works on other color backgrounds too.

_x000D_
_x000D_
body {_x000D_
  background: url(http://s1.picswalls.com/wallpapers/2016/03/29/beautiful-nature-backgrounds_042320876_304.jpg)_x000D_
}_x000D_
_x000D_
div {_x000D_
  background: url(https://www.w3schools.com/w3css/img_avatar3.png) center center;_x000D_
  background-size: contain;_x000D_
  width: 100px;_x000D_
  height: 100px;_x000D_
  margin: 50px;_x000D_
  border: 5px solid white;_x000D_
  box-shadow: 0px 0 rgba(0, 0, 0, 0), 0px 0 rgba(0, 0, 0, 0), 0 7px 7px -5px black;_x000D_
}
_x000D_
<div>_x000D_
</div>
_x000D_
_x000D_
_x000D_


You could also use clip-path to clip (hide) all overflowing edges but the one you want to show:

.shadow {
  box-shadow: 0 4px 4px black;
  clip-path: polygon(0 0, 100% 0, 100% 200%, 0 200%);
}

See clip-path (MDN). The arguments to polygon are the top-left point, the top-right point, the bottom-right point, and the bottom-left point. By setting the bottom edge to 200% (or whatever number bigger than 100%) you constrain your overflow to only the bottom edge.

Examples:

example of boxes with top right bottom and left box-shadow isolated with clip-path

_x000D_
_x000D_
.shadow {
  box-shadow: 0 0 8px 5px rgba(200, 0, 0, 0.5);
}
.shadow-top {
  clip-path: polygon(0% -20%, 100% -20%, 100% 100%, 0% 100%);
}
.shadow-right {
  clip-path: polygon(0% 0%, 120% 0%, 120% 100%, 0% 100%);
}
.shadow-bottom {
  clip-path: polygon(0% 0%, 100% 0%, 100% 120%, 0% 120%);
}
.shadow-left {
  clip-path: polygon(-20% 0%, 100% 0%, 100% 100%, -20% 100%);
}

.shadow-bottom-right {
  clip-path: polygon(0% 0%, 120% 0%, 120% 120%, 0% 120%);
}

/* layout for example */
.box {
  display: inline-block;
  vertical-align: top;
  background: #338484;
  color: #fff;
  width: 4em;
  height: 2em;
  margin: 1em;
  padding: 1em;
}
_x000D_
<div class="box">none</div>
<div class="box shadow shadow-all">all</div>
<div class="box shadow shadow-top">top</div>
<div class="box shadow shadow-right">right</div>
<div class="box shadow shadow-bottom">bottom</div>
<div class="box shadow shadow-left">left</div>
<div class="box shadow shadow-bottom-right">bottom right</div>
_x000D_
_x000D_
_x000D_


If you have a fixed color on the background, you can hide the side-shadow effect with two masking shadows having the same color of the background and blur = 0, example:

box-shadow: 
    -6px 0 white,         /*Left masking shadow*/
    6px 0 white,          /*Right masking shadow*/
    0 7px 4px -3px black; /*The real (slim) shadow*/

Note that the black shadow must be the last, and has a negative spread (-3px) in order to prevent it from extendig beyond the corners.

Here the fiddle (change the color of the masking shadows to see how it really works).

_x000D_
_x000D_
div{_x000D_
    width: 100px;_x000D_
    height: 100px;_x000D_
    border: 1px solid pink;_x000D_
    box-shadow: -6px 0 white, 6px 0 white, 0 7px 5px -2px black;_x000D_
}
_x000D_
<div></div>
_x000D_
_x000D_
_x000D_

enter image description here


This code pen (not by me) demonstrates a super simple way of doing this and the other sides by themselves quite nicely:

box-shadow: 0 5px 5px -5px #333;

https://codepen.io/zeckdude/pen/oxywmm