CSS Box-Shadow:Inset

You’ve gotta appreciate the imageless design elements the CSS box-shadow property makes possible. No more slicing up 3 jpgs to recreate the depth so easily gained in Photoshop. Lately, we’ve been using box-shadow:inset on some Paravel jobs, and I’ve seem some clever uses out there on the intertubes. This property is compatible with Webkit (Safari & Chrome), Firefox, Opera, and IE9, so there’s no reason to hold off using it as an enhancement on the page you’re working on right now.

box-shadow: inset
When building Camp Wapo, we used inset on the action item buttons.
box-shadow: inset
Lettering.js has an inset hover state on each of the linked images.
box-shadow: inset
The feature box on A Book Apart has a nice vignette shadow framing the div.
box-shadow: inset
When logged out, the Rdio homepage employs inset shadows on their features list.

Now, what about images? It’d be nice to be able to add a vignetting effect to photos sans-Photoshop, but the way browsers interpret box-shadow:inset is to throw the shadow behind the image, rendering it invisible. While this seems pretty useless, it does make sense when you consider other kinds of content. For example, if you inset a shadow you probably wouldn’t want it overshadowing the text within.

box-shadow: inset

A reasonable way to circumvent this issue would be to wrap the image in a div or a span element and employ some basic z-indexing. See the example code provided below. While this method gets the job done, I wonder if it’d be sensible to update the CSS Working Draft to allow for inset shadows to be displayed on top when applied directly to an image. Despite the inconsistency, it seems intuitive to me and would ultimately lead to cleaner, simpler markup.

<div class="vignette">
<img src="mustang.png" alt="mustang" class="car_photo"/>
</div>

.vignette{
box-shadow:inset 0px 0px 85px rgba(0,0,0,.5);
-webkit-box-shadow:inset 0px 0px 85px rgba(0,0,0,.5);
-moz-box-shadow:inset 0px 0px 85px rgba(0,0,0,.5);
}

img.car_photo{
z-index: -1;
position: relative;
}

49 Responses

Leave a comment or contact me via Twitter @TrentWalton

  • Yaron Schoen

    Thanks for this Trent. Your short notes are so much better than all the crappy “tutorials” out there. This past weekend I have been trying to refresh my HTML skills, so I know a thing or two about crappy tutorials.

  • Ben Shoults

    Great workaround for the images, thanks.

  • Tom

    I recently found that complex multiple shadows (some outer and some inset shadows on the same element) don’t play nicely in Chrome, but work fine in Safari. In particular the inset shadow doesn’t work with border-radius... Which is very odd.

    I guess it’s a little bit more time before they’re perfect, but definitely start using them :)

    (Example of it on http://www.nomensa.com - the blue button will look different & better in FF, but simpler in Webkit browsers for now)

  • Chris Coyier

    My favorite use is that “pressed” look on the active state of buttons.

    .button:active {
    box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.5);
    /* Plus vendor extensions */
    }

    The vignette idea is clever =). It even provides super rudimentary dont-steal-this-image protection since you can’t right-click it or drag it to the desktop.

  • Trent

    @Chris Coyier: Me too! we’ve got some of that going on at Wapo.

    It even provides super rudimentary dont-steal-this-image protection since you can’t right-click it or drag it to the desktop.

    I think you’re the king of multitasking CSS. Good thinking :)

  • Rasmus Kalms

    Great piece! We similarly just started using it at the company I work for (that and a lot of other CSS3 features) - I guess that’s what you get for attending FOWD. Lot’s of inspiration!

    It really does make CSS fun again.

  • Oliver Edwards

    Indeed applying inset box-shadow would be logical, because z-indexing a div above the image removes the possibility of having the image opacity transition to see an image behind on :hover.

  • Adam Reece

    I had the intention of using this for a project as well, but I noticed in Chrome on a PC, the inset doesn’t play nice with rounded corners. It looks great in FF though.

    See: http://adam-reece.com/temp/camp_wapo.jpg

    I haven’t found any work around for this. Does this happen on Chrome on a Mac?

    Either way, I love these little tidbits. Keep em coming.

  • Ted Goas

    Trent, interesting angle in applying this to images! I wonder if you can start to achieve Instagram-like effects by playing with the size, opacity, and color.

  • Trent

    @Adam Reece: Wow, that sure doesn’t happen on Chrome for Mac... Curious- I’m going to do some digging here. Thank you for the heads up.

    @Ted Goas: I like where your head’s at :)

  • Kyle Fox

    Box shadow rules can contain multiple values for extra a really inset look:
    http://dl.dropbox.com/u/780754/inset_button/index.html

    But I’m sure everyone already knows about that.

  • Paul Mason

    @Chris Coyier: nope until you disable the stylesheet..hihi ;)

  • Simon Foster

    @Adam Reece. Yeah I found that too with Chrome on Windows, I’ve been searching for a fix too, but so far to no avail. Will let you know if I find a solution :)

  • Jordan Dobson

    Inset box shadows are awesome. I’m glad they are finally supported in iOS 4.2. I was a bit hesitant to use them before that release.

    I took your post here and Chris’s post and worked on a few other ways to create some vignette style photos and posted the details and code here: http://cl.ly/3Nxc

    I hope you all can find some use with them. :)

  • Adriaan Pelzer

    What happens if you make the image the background of the container? Haven’t tried it yet, but will tmr if there’s time

  • Nicolas Gallagher

    Beautifully subtle use of box-shadows. Unfortunately, as mentioned by others, Chrome on Windows won’t round inset shadows when you specify a border-radius. It’s been a problem since at least Chrome 5. Placing the non-prefixed version of box-shadow after the prefixed properties should help increase the chance that a site automatically ‘upgrades’ the rendering of inset box-shadows when non-experimental implementations creep into webkit/moz browsers.

  • Ahmed El Gabri

    @Chris Coyier: I have used it on my Contact form a long time ago http://gabri.me/contact/ , i think it‘s a nice way to give a user an immediate feedback.

  • Ed Melly

    The Chrome bug (combining inset box shadows with border radius) can be viewed here: http://code.google.com/p/chromium/issues/detail?id=29427

    It’s been open for a while, and only impacts Windows and Linux as Chrome uses a different graphics library on those systems. Comment 45 at the link above explains the problem, but doesn’t inspire much confidence in the issue being resolved any time soon.

  • Dale Rogers

    Hey, thanks, I have picked up a new trick. I used the .vignette class on my body element. The website has an old paper feel and I thought that would finish things off nice. Unfortunately I’m noticing that the effect has significantly affected things like scrolling and resizing. My browser, though it likes it visually, doesn’t seem to handle the effect efficiently.
    Do you have more info on how these effects use resources?

    Thanks for the great tip.

    Dale Rogers.

  • Matthew Smith

    I was feeling this issue yesterday! Bummer.

  • Thibaut Ninove

    I encountered that recently too.

    In my case it was really simple to solve because the image had to be a link. So instead of playing with the z-index (I personally don’t like it so much), I just display the inset styled ‘a’ above the image.

    div {
    position: relative;
    }

    img {
    -webkit-box-shadow: 0 0 2px rgba(0, 0, 0, .5);
    }

    img + a {
    -webkit-box-shadow:
    0 1px rgba(255, 255, 255, .65) inset,
    0 1px 2px rgba(0, 0, 0, .5);
    position: absolute;
    (...)
    }

    Ref. : http://repo.wooconcept.com/ic.html

  • Vesa

    Inset shadows are great for replacing the age old image elements. Love ‘em... and also ran into the problem on Chrome on Windows a while ago.

    But if I want a static vignette on a photo I’d much rather do it in Photoshop/Lightroom. You just can’t get the same burn feel and control with css than you get with brushes and blending modes. Also if someone’s to use (with permission of course) the photo you vignetted with css don’t have the vignette in the photo. But I see how the shadows can be useful for hover stuff and other visual trickery.

  • Paul Irish

    btw ya’ll: the Chrome/Windows inset box-shadow bug has been resolved!

    As of today, it’s fixed and available in the dev channel! (It’ll be a max of just 10 weeks when it hits everyone in the stable channel)

    More details: http://paulirish.com/2011/chrome-inset-box-shadow-bug-fixed/

  • Jon Hadley

    Your approach works well in isolation, but has problems on my production site, where the background settings for a parent div override the z-index on the image - live jsFiddle demo - related Stack Overflow question.

    The second approach - mentioned in the comments above and included in the demos above - works well, but my image has to be wrapped in the anchor tag - it can’t be below it.

  • Zimm

    Why not just drop the image file in the background of the div and apply your inset box-shadow rules to it? Works like a charm, no mess.

    • Trent

      That’d work, but not as easily on dynamic sites where images couldn’t or shouldn’t be treated as background images.

  • Philip Renich

    Trent,
    I breezed the comments, but I don’t think I missed anything. Wouldn’t a simple ::after declaration work?
    You’d probably need to know the width of your image, which may throw a monkey wrench in making it fully dynamic, but it’s a good start.

    Philip

  • derek anderson

    I’ve been using :before and :after to get around this issue:
    img { position:relative; }
    img:after {
    content:””;
    display:block;
    position:absolute;
    top:0; right:0; bottom:0; left:0;
    [ box shadow stuff here ]
    }

  • Drew

    :after on the image was the same idea I had, but it doesn’t seem to work (and it sort of makes sense that it doesn’t): do you have a working example or fiddle?

    I think the reason is simply because img tags with actual images in them don’t really have/show inner content per se, and :before/:after are methods for affecting the inner content of a given page element.

    It’s as if you were doing this:
    Hi, I’m pseudo-class content, but you’ll never see me!

    Wrapping the image in something else that has a psuedo-class seems like the only solution. It’s a shame though, because the usual semantically informative thing to wrap an image in is , but if you’re going to include a in there as well, the vignette effect is going to wrap over that too (since it’s attached to the figure block, not the image), instead of just going over the image.

  • Nate

    (Posted this on CSS-Tricks as well but found this in my searching so figured I would update here as well)

    I was unable to get a solid box shadow (no blur) on Android (HTC Incredible [2.3.4] and Motorola Droid 1 [2.2.3]).

    This was not working:
    -moz-box-shadow: 0px 0px 0px 4px red;
    -webkit-box-shadow: 0px 0px 0px 4px red;
    box-shadow: 0px 0px 0px 4px red;

    Setting the blur to 1px was the closest I could get to solid and still have it render on Android devices:

    -moz-box-shadow: 0px 0px 1px 4px red;
    -webkit-box-shadow: 0px 0px 1px 4px red;
    box-shadow: 0px 0px 1px 4px red;

    Hopefully this helps some other responsive developers!

    Love your work Trent!

  • Ian

    I’m having a problem with box-shadow: inset. I used it on the body element of a wordpress site to show a small shadow margin and recreate a gradient at the top. It won’t display full width on ios though and I’m stumped. Any ideas?

    Code:
    -moz-box-shadow: inset 0 0 20px 5px rgba(0,0,0,0.5),
    inset 0 200px 200px -50px rgba(0,0,0,0.8);
    -webkit-box-shadow:inset 0 0 20px 5px rgba(0,0,0,0.5),
    inset 0 200px 200px -50px rgba(0,0,0,0.8);
    box-shadow: inset 0 0 20px 5px rgba(0,0,0,0.5),
    inset 0 200px 200px -50px rgba(0,0,0,0.8);

  • Trent

    @Ian: Yo! Maybe put this on http://codepen.io or http://jsfiddle.net/ so we can take a closer look.

  • Ian

    I put it up on jsfiddle (http://jsfiddle.net/P2TQ8/3/), but it works there. That makes sense though since the display screen is contained within the rest of the page.
    I left a link on the jsfiddle page to the actual site.
    Any suggestions most welcome.
    Ian.

  • Mario

    Nice. But what do you do if you have a background color in any element underneath the image? Through the z-index the image disappears behind the background color. Played around with the positioning of the image holding container, but didn’t get a solution yet. Anyone any ideas?

  • Trent

    @Ian: Didn’t have a ton of time to debug in iOS... was wondering if you ever got a solution.

    @Mario: Howdy Mario! Is there a live version of this we could take a look at somewhere?

  • dia oc

    thanks nice tip for image

  • Tiago Couto

    Not working with link so i’ve made this quick solution for

    ex.:
    a:hover:after {
    bottom: 0;
    -moz-box-shadow:inset 0 0 0 4px rgba(0,0,0,1);
    -webkit-box-shadow:inset 0 0 0 4px rgba(0,0,0,1);
    box-shadow:inset 0 0 0 4px rgba(0,0,0,1);
    content: ”;
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
    }

  • John

    Nice tip, thanks !

  • James Nowland

    @derek anderson:

    Just a heads up you can’t (currently) put pseudo elements on img tags:
    http://stackoverflow.com/questions/7396469/why-dont-pseudo-elements-work-with-img-elements.

  • Nicholas Burge

    I’m having a strange issue where the z-index is moving the image behind the outer div (I’m also using border radius) - has anyone else had this problem?

    Thanks in advance.
    Nick

  • Karan

    Probably inset works on chrome and other browser but inset does not work on ie9

  • Karan

    as above said “inset not working in ie9” only when we use gradient color in ie9
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=’#E6E6E6’,endColorstr=’#E8E8E8’,Gradient Type=0);
    but with solid color inset show its effect in ie9

  • wilson

    Hey if i give div with class clearfix background color #fff the image goes behind the inset shadow ??
    why does this happen??
    Please explain

  • Rohit

    Its Great ‚But i am facing a problem with event handling. i want to apply mouseover event on image. but after applying this effect , event wont trigger at all. what i actually need is ‚when user move mouse over image . it glow back as original image

  • Andy Hullinger

    Neat trick! Got me thinking about using the figure element and it’s accompanying figcaption instead of pseudo selectors. Inspiring to consider how much “Photoshop in the Browser” is possible.

    I posted a few experiments here.
    http://codepen.io/andyhullinger/pen/Dzhfi
    http://codepen.io/andyhullinger/pen/BEhlq

  • Antonio

    More CSS shadow effects..

    http://davidwalsh.name/css-box-shadow

    css tutorial

  • Maneksh

    Try simple guide to create box shadow #simple guide to create box shadow

Leave a Reply