CSS3: spread value and box-shadow on one side only

by Stephanie Rewis on September 8, 2011

This morning I awakened with a question in my twitter stream from @deebeefunky. He was frustrated by the fact that when he sets a blur on box-shadow, it shows on two sides of the box. He wants it to show on only one side. Of course, that got me thinking. I did come up with one solution—it won’t work in every situation—but it may work in yours.

The spread value

There’s a little talked about value in the box-shadow property called “spread”. That value, when used, comes after the blur value and moves the shadow away from the box equally all the way around. It doesn’t add a blur, it simply spreads out in all directions. You’ll get different effects based on whether the blur value is a greater than the spread value or whether the spread is greater than the blur. The color defined will be solid right next to the box, and then blur for the rest (based on the difference between the two values). Before it gets too confusing, let’s have a look at the property:

box-shadow: (inset) x-value y-value blur spread color;

div {
-webkit-box-shadow: 0 0 6px 4px black;
   -moz-box-shadow: 0 0 6px 4px black;
        box-shadow: 0 0 6px 4px black;
}
Blur larger than spread

Blur larger than spread

If the spread value has a higher value, you get a different effect with the full spread and only a little blur.

div {
-webkit-box-shadow: 0 0 4px 6px black;
   -moz-box-shadow: 0 0 4px 6px black;
        box-shadow: 0 0 4px 6px black;
}
Spread value greater than blur

Spread value greater than blur

Though the differences above are subtle, you can actually create some really interesting effects with this value. If you don’t move the box-shadow on the x or y axis and provide no blur value at all, you can create one, or more, multiple borders for your element.

Create the look of multiple borders

div {
border: 3px solid orange;
-webkit-box-shadow: 0 0 0 3px black, 0 0 0 6px red;
   -moz-box-shadow: 0 0 0 3px black, 0 0 0 6px red;
         box-shadow: 0 0 0 3px black, 0 0 0 6px red;
}
Spread radius with no blur

Spread radius with no blur

Notice it appears there are three borders on this element. A single (orange) border was added, then a black border (created with the 3px of spread) and then a red border (the 3 px border is created by 6px of spread since you must allow for the first box-shadow). It’s unlikely you’d actually need more borders than this, but you can create an unlimited number this way. Remember that when using multiple box-shadows, the first one is applied closest to the element.

How does this apply to @deebeefunky’s question?

I’m glad you asked! Sometimes I get off track (you know, that simple little blog post you were gonna write…). The issue with box-shadow is, even if you only move the shadow on the x or y axis, you’ll see a hint of the shadow on at least two sides of your element.

div {
-webkit-box-shadow: 1px 0 2px black;
   -moz-box-shadow: 1px 0 2px black;
        box-shadow: 1px 0 2px black;
}
2px blur moved 1px on the x-axis

2px blur moved 1px on the x-axis

I came up with an idea that works as long as A) the element is a solid color and B) you’re not also using border on the element. It involves applying two box-shadows, one with spread in the same color as the box itself and another without. Like so:

div {
background: white;
-webkit-box-shadow: 0 0 0 4px white, 0 6px 4px black;
   -moz-box-shadow: 0 0 0 4px white, 0 6px 4px black;
        box-shadow: 0 0 0 4px white, 0 6px 4px black;
}
Use two box-shadows for a single side effect

Use two box-shadows for a single side effect

Why does this work?

In a nutshell, what you’re doing is creating the first box-shadow (0 0 0 4px white) which doesn’t move on the X or Y axis, doesn’t provide any blur, and has the 4px of spread set in the same color as the background of the element. This basically renders it invisible but makes the element 4px wider than it was (box-shadow does NOT add to the box model, so you’re element will appear 4px closer to the elements around it as well). Remember the order I mentioned before? The first box-shadow is placed on top—or closest to the element? That’s what helps us here. The second box-shadow (0 6px 4px black) is moving 6px on the Y-axis, has 4px of blur, no spread and is black. We’ve moved this vertically—though you could use the same technique on the X-axis.

Where is the real border?

Just to illustrate why you can’t use a border with this technique, here’s a look at the addition of a red border to our previous example.

Red border shown on actual outside of box

Red border shown on actual outside of box

The thing to remember when using this technique is A) you can only move on one axis— X or Y and B) your blur value cannot exceed the spread value given in the first box-shadow. If it does, you’ll start to see it peek out on the sides (an effect we were avoiding in the first place). You can, however, move as much or as little on either the X or Y axis as your effect requires. And as always, using RGBA or HSLA color values will give you a more realistic shadow if that’s what you’re after.

Update: Method Two

If you have a patterned background on the element or need to use a border, Joseph Silber had another idea in the comments below. Use a negative spread radius. Nice thinking, Joseph! Playing with this method, I came up with the following:

div {
	-webkit-box-shadow: 0 8px 6px -6px black;
	   -moz-box-shadow: 0 8px 6px -6px black;
	        box-shadow: 0 8px 6px -6px black;
}
Negative spread radius with equal blur value

Negative spread radius with equal blur value

The issue to be aware of with this method is, the negative spread value should be equal to, or greater than, the blur value or you’ll end up with a slight blur on the other two sides of the element. Also, very little of the box-shadow will show if you don’t give the X or Y a value equal to, or greater than, the blur. Otherwise, the blur is slightly hidden behind the edge of the element since the spread value is negative.

With the negative spread value, a border can be added

With the negative spread value, a border can be added

Notice the element isn’t “expanding” like it did using the first method (the box size is what you’d expect), but the shadow doesn’t quite go to each edge due to the negative spread value. Based on the interaction with other elements on your page, one of these two methods might just work for you!

Update Oct 2

Due to an Android bug when the box-shadow has no blur, you’ll likely want to use the second method if you want the shadow to appear on an Android device. Let’s hope they fix this one soon. (Thanks, Luís Carmona!)

Do you have a method you use to create the same effect? Share it in the comments. Happy coding!

{ 24 comments… read them below or add one }

Chris Coyier September 8, 2011 at 3:53 pm

clever clever.

Jorgen Evens September 8, 2011 at 4:07 pm

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!

Joseph Silber September 8, 2011 at 4:21 pm

Why not simply a negative spread?

div {
height: 100px;
width: 100px;
box-shadow: 5px 0 7px -5px black;
background: #E4FCE4;
}

http://jsfiddle.net/MceL6/

Stephanie (Sullivan) Rewis September 8, 2011 at 4:44 pm

Thanks Chris… it’s one way to do it. :)

Jorgen – I try to avoid extra elements, but in some situations you’re better not to. Nice technique.

Joseph – I like this. I hadn’t thought about a negative spread. It gives a little different effect since it pulls in on the top and bottom a bit… that may or may not be desirable, but in certain situations it would be awesome. Good work!

Stephanie (Sullivan) Rewis September 8, 2011 at 4:47 pm

Actually Joseph, if you make the background of the element the same color as the container, you’ll see a slight line on the top and bottom. I found if you make sure the blur and the negative spread match exactly, you can get rid of that. :)

Hans Kuijpers September 9, 2011 at 1:45 am

This one is great! Thanks
I was searching for this kind of solution.

Christian Schröder September 9, 2011 at 1:57 am

We put together some examples using the neglected spread attribute: http://conceptboard.github.com/box-shadow-spread-examples/

Stephanie (Sullivan) Rewis September 9, 2011 at 11:41 am

Christian – that’s awesome. I so rarely see people talk about spread… it’s as if it doesn’t exist. Nice work. :)

Jan September 15, 2011 at 3:14 pm

Hey Stephanie, thanks for this hint. Didn’t even know about the spread value before! The last example will be of great use to create with just a little shadow to divide elements :) CSS3 is just great. Really.

Shekhar September 15, 2011 at 10:20 pm

Loved it. nice trick.

Luís Carmona September 29, 2011 at 10:42 am

Hey Stephanie, have you ever heard about box-shadow not working on android, unless you set a non-zero value for the blur?

Stephanie (Sullivan) Rewis September 29, 2011 at 11:40 am

Luis – I have not! Do you have an example page? I have a couple Androids I could test it on for you. Let me know…

Luís Carmona September 29, 2011 at 11:53 am

You can temporarily test it here: 1.4q.8h.sl.pt
It’s just an HTML mockup in progress, but the news items should have a bevel between them, made with box-shadow.

Stephanie (Sullivan) Rewis September 29, 2011 at 12:26 pm

Your URL didn’t come through as a URL, BUT, I used one of mine: http://w3conversions.com/sandbox/css3/box-shadow/mult-borders.html

That should show a dashed border with several multiple borders created with spread—and no blur. None of the multiple shadows created that way show up on my Atrix in the default browser (or the Dolphin browser).

Great catch… and good gawd. :(

Luís Carmona September 30, 2011 at 4:05 am

Sorry, this is the correct URL: 1.4p.8h.sl.pt
I was almost pulling my hair out with this one because it was working on chrome, on iOS but not on any Android I have. Not even tablets… so indeed it must be a bug.

Stephanie (Sullivan) Rewis October 2, 2011 at 6:42 pm

It is. I even found it already filed when I went to file the bug:
http://code.google.com/p/android/issues/detail?id=7531&q=box-shadow&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars

Maybe you can log in and add to it and beg them to fix it (I did). It’s been filed since April 2010. :(

Andy May 3, 2012 at 3:25 pm

Does anyone know how to apply inset box shadow to a single edge without the spread displaying unwanted inner shadow on other edges?

For example, I want to use this code to create a left inner shadow, but the other three sides are being affected.
box-shadow: inset 1px 0px 6px #ccc;

M Best September 19, 2012 at 6:44 pm

Using two divs allows you create a shadow on only one side with the shadow going completely to each edge.

http://jsfiddle.net/mbest/mSmmp/

Luisa Ambros Costa November 24, 2012 at 3:18 am

Great solution! This article became a great code resource for box-shadow styling!
I couldn’t find yet how to make a inset box shadow without blur and only on the bottom of a div :(

Tom February 21, 2013 at 12:54 pm

Is it possible to make a box-shadow with CSS that has the full with of the div?

AskApache July 18, 2013 at 6:21 pm

Really enjoyed this post, also nice looking text-shadows!

Thoufeeq September 8, 2013 at 6:51 pm

wasn’t knowing abt the existence of ‘spread’. :)

Hamid September 27, 2013 at 4:01 am

What nice article. tnx guys :)

Kyle Marimon May 13, 2014 at 7:39 am

“the negative spread value should be equal to, or greater than, the blur value”
I believe you mean the absolute value of whatever that negative spread value is.

Leave a Comment

{ 4 trackbacks }