Drop Shadows - The Responsive Way

Back in the olden golden days of fixed-width web design, adding a drop shadow to an element used to be a matter of exporting an image containing the shadow from Photoshop and placing it as a background image on the element. Deal done.

However, if you want some flexibility (as many of us have always wanted) it isn’t quite that easy. Sure, if you have a straight drop shadow that can be created with a CSS box-shadow declaration, it will expand and contract as necessary to fit the width of the element it is applied to. But if the design calls for a slightly more complex shadow you need to do a bit more.

Repeatable background

If the shadow contains a repeatable section you can use older techniques where you create an over-wide shadow image and apply it to two overlapping elements, creating the effect of a flexible shadow.

It’s much more maintainable and flexible if the drop shadow doesn’t depend on the background being a solid colour. The problem here is that if you use an image with transparency and layer it to create the illusion of flexibility, there will be problems where it overlaps. The tricks I just mentioned can avoid this because the drop shadow is regular and can easily be repeated (see the blog posts for details).

But drop shadows aren’t always repeatable, which leads us to more recent tricks. Which will be described below:

Using background-size and an image with alpha transparency

One option is to scale the background image containing the drop shadow. The background-size property comes in handy for this. Browser support is surprisingly good, with IE8 and below being the only relevant exception. Since the actual scaling may be needed the most inside media queries, which IE8 and older know nothing about anyway, that isn’t really much of an issue.

Using background-size you can specify if and how the background image should be scaled in relation to the element it is applied to. On the demo page there are three examples using background-size.

Pseudo-element, not proportional scaling

The first example uses an absolutely positioned pseudo-element and background-size:100% 100%, which stretches the image to always cover the entire background positioning area:

.box:after {
	position: absolute;
	right: 0;
	bottom: -37px;
	left: 0;
	content: '';
	height: 37px; /* The intrinsic height of the image */
	background: url(shadow.png) no-repeat;
	background-size: 100% 100%;
}

In most cases this will scale the image disproportionately, which may or may not look acceptable.

Pseudo-element, proportional scaling

The second example is identical to the first, but uses background-size:100% auto (you don’t really need to specify “auto” here since if only one value is given the second is assumed to be “auto”, but I’ve added it for clarity). This will stretch the image to match the width of the background positioning area while proportionally scaling its height.

.box:after {
	position: absolute;
	right: 0;
	bottom: -37px;
	left: 0;
	content: '';
	height: 37px; /* The intrinsic height of the image */
	background: url(shadow.png) no-repeat;
	background-size: 100% auto;
}

Depending on the look of the shadow this may look better than the previous example.

Padding, proportional scaling

For the third example I have applied the image to the background positioning area of the box element itself instead of using a pseudo-element. To prevent the box element’s content from covering the drop shadow and to be able to give the content area itself borders or other styling I’ve had to add a wrapping element to the markup:

<div class="box">
	<div class="box-content">
		…
	</div>
</div>

I then gave the box element a padding-bottom in percent, calculated by dividing the image’s intrinsic height by its width, in this case 37 by 992 pixels, and used background-size to ensure that the image is scaled proportionally like in the previous example:

.box {
	padding-bottom: 3.729838709677%; /* 37 / 992 * 100 */
	background: url(shadow.png) no-repeat 50% 100%;
	background-size: 100% auto;
}

The difference between this method and the previous is that in this case the box element’s total height (which includes the bottom padding) will change with its width. Sometimes you want that, sometimes not.

A pseudo-element, box-shadow and border-radius

For a truly flexible solution you can try creating the shadow completely with CSS. The easiest is to use a plain box-shadow, but that will only let you create a rather “boxy” looking drop shadow. But if you combine box-shadow with border-radius you can get some interesting results.

.box {
	position: relative;
}

.box:after {
	position: absolute;
	right: 10px; /* Positioned some distance in from the left and right edges to avoid the box-shadow blur from peeking through on the sides of the box */
	bottom: 0;
	left: 10px;
  content: '';
	height: 20px;
	border-radius: 0 0 50% 50% / 0 0 20px 20px;
	box-shadow: 0 10px 10px rgba(0, 0, 0, 0.5);
}
/* The content needs to be in an element with a non-transparent background to cover parts of the drop shadow. */
.box-content {
	position: relative;
	z-index: 1; /* Make sure it’s rendered on top of the pseudo-element */
	padding: 10px;
	background: #fff;
}

The most interesting part of this is the border-radius declaration. What it does is create bottom-right and bottom-left corners that are 50% wide and 20px tall. In the example I’ve used shorthand, but it could also be written like this:

border-bottom-right-radius: 50% 20px;
border-bottom-left-radius: 50% 20px;

The pseudo element is positioned absolutely at bottom:0, which means that only the shadow protrudes from the bottom of the box element. A wrapper element for the content is necessary to cover the parts of the pseudo-element that are inside the box.

While you aren’t as free to create any kind of look for drop shadows created like this, you can play around with the border-radius values and the offset and blur of the box-shadow (or add multiple box-shadows) and get some nice effects that will scale well.

Think flexibly

It’s obviously important to keep flexibility in mind while designing. It’s also important to remember that it doesn’t necessarily mean that you have to rely only on what can be done with a plain box-shadow declaration. Hopefully these examples might help you solve some problems or give you some ideas to build on.