23

Im trying to achieve an inner-shadow effect on a simple box, something like: alt text http://gotinsane.com/test.jpg

where the green box is the content inside another box.

My problem is that if i give the content box any kind of background, the outer box box-shadow effect vanish!

Here an example of my problem (with markup and css), i've set the content height smaller to evidence the problem - atm i really dont care about IE*, this is just a test.

Any idea?

UPDATE

The content inside the box is a somewhat kind of slide, here an example (original problem). thirtydot's answer does the trick, but it forces me to make a little hack, changing the wrapper background in function of the content: example here (thirtydot trick).

This can be a solution, but i dont like it too much and still dont understand why the outer box shadow get behind the inner box background (color, image)

UPDATE 2

Talking about this problem on another forum, i found another way: basically, instead of use box-shadow on the wrapper, that will act as a mask, I use box-shadow and border-radius directly on the content (.step elements) However, the 'mask' effect is exactly what i was trying to accomplish, so this isnt the solution neither.

I still don't understand how and why an inner element background interfere with an outer element design, or why the shadow dropped from the outer element get behind the inner one. Could this be a css bug?

UPDATE3

Someone opened a bug on mozilla, and got this answer that clearify the 'problem':

From http://www.w3.org/TR/css3-background/#the-box-shadow :

In terms of stacking contexts and the painting order, the outer shadows of an element are drawn immediately below the background of that element, and the inner shadows of an element are drawn immediately above the background of that element (below the borders and border image, if any).

In particular, the backgrounds of children of the element would paint above the inset shadow (and in fact they paint above the borders and background of the element itself).

So the rendering is exactly what the spec calls for.

UPDATE4

Fabio A. pointed out another solution, with css3 pointer-events. Looks good and works on IE8 too ;)

Strae
  • 18,807
  • 29
  • 92
  • 131
  • You just want something that looks like your image? – thirtydot Mar 23 '11 at 02:24
  • yes - but the inner box background should be indipendent from the outer - as it can be everythings, an image, a color radius, etc.. – Strae Mar 23 '11 at 04:04
  • You're going to have to stick to what you have. I [tried this](http://jsfiddle.net/sMDsX/10/), but it's unusable because you can't click stuff inside the inner box shadow. I did try to find a way several times to do it how you wanted, but I just don't think it exists. I made your version of my fix slightly cleaner: [http://jsfiddle.net/sMDsX/11/](http://jsfiddle.net/sMDsX/11/) - you can pass nothing to `removeClass()` to remove all classes. – thirtydot Mar 23 '11 at 11:51
  • @thirtydot: i just got a solution on another forum, i'll post now - thanks for the tip about `removeClass()`, i didnt know and i used to do `$("#foo").attr('class', '');` to remove all classes at once ;) – Strae Mar 23 '11 at 13:20
  • 1
    'I still don't understand how and why an inner element background interfere with an outer element design' - I imagine this is because inner elements are effectively drawn *above* their parents (parent drawn first, then children drawn on top of). Usuaally that's the intuitive thing (e.g. blotting out a background image, overlapping border corners on daring `position:relative` trickery, etc). So, by proxy, what you're expecting is the border shadow falling on items *above* the bordered box. – pinkgothic Mar 23 '11 at 13:41
  • 1
    I did a quick sketch, what with a picture being worth a thousand words: http://pandora.pinkgothic.com/why-shadow.png - "side-on" visualisation of greatly exaggerated HTML layers. :) – pinkgothic Mar 23 '11 at 13:53
  • @pinkgothic: thanks for the clarification, I was believed exact the opposite ;) The problem is that if i use the `position:relative` trick to bring up the wrapper, the content inside the inner box will no more be clickable.. i guess i'll go with thirtydot solution then – Strae Mar 23 '11 at 14:01
  • Yeah, thirtydot's solution is probably the best you can do. :) Good luck! – pinkgothic Mar 23 '11 at 15:25

6 Answers6

17

Since I am having this problem too and I too don't see this behaviour being normal, I filed a bug report over at mozilla

I can reproduce the problem in Google Chrome too, though, so I wonder whether this is really a bug. But it could be.

edit:

Indeed it's not a bug, but just the way it's meant to work. So, on the basis of this information, I forked your jfiddle example and came up with this solution:

The markup now looks like this:

<div id="box">
    <div id="wrapper">
        <div id="box_content">
            Content here
        </div>
        <div id="mask"></div>
    </div>
</div>

The mask becomes another div, which is layered on top of the #box_content one by means of being absolutely positioned. This is the CSS:

#wrapper{
    position: relative;
    display: inline-block;
    width: 280px;
    height: 280px;
    border-radius: 5px;
    margin: 10px;
}
#mask {
    position: absolute;
    top: 0px; left: 0px;
    width: 100%;
    height: 100%;

    pointer-events: none; /* to make clicks pass through */

    box-shadow: 0 0 10px #000000 inset;
}
#box_content{
    background-color: #0ef83f;
    height: 100%;
}
Fabio A.
  • 2,517
  • 26
  • 35
  • Take a look at pinkgothic image into my question comments, looks like the behavior is normal (just not intuitive to understand) – Strae Mar 25 '11 at 07:33
  • Oh - i noticed they give the same answer on bugmozilla too ;) – Strae Mar 25 '11 at 07:34
  • Yes, thinking of it it makes sense, and based on that answer I came up with this solution: http://jsfiddle.net/8FkE3/ . I'll edit my reply above. – Fabio A. Mar 25 '11 at 10:51
  • Argh, I see this solution was already given and dismissed because the link becomes unclickable. Sorry 'bout that. – Fabio A. Mar 25 '11 at 11:24
  • 2
    Right, I knew there must have been a solution: the css property pointer-events set to 'none'. Here's [thirtydot's solution forked to make use of this feature](http://jsfiddle.net/HPkd3/) – Fabio A. Mar 25 '11 at 11:39
  • @DaNieL: Good solution! I'd *completely* forgotten about `pointer-events`, it's very useful in certain situations. – thirtydot Mar 29 '11 at 12:23
  • `pointer-events` is not supported on default android 4.3 browser on Galaxy S4, as opposed to every other android 4.3 device. This renders this answer unfeasible, unfortunately. – Razor Mar 13 '14 at 17:19
3

I'm a little confused what you're actually after. If it's not quite right, let me know :)

This is my best guess.

Live Demo

CSS:
(I added in the vendor prefix rules.)

#box {
    -moz-border-radius: 5px;
    border-radius: 5px; 

    -webkit-box-shadow: 0 0 10px #000;
    -moz-box-shadow: 0 0 10px #000;
    box-shadow: 0 0 10px #000;

    width: 280px;
    height: 280px;
    padding: 10px
}

#wrapper {
    background-color: #0ef83f;

    -moz-border-radius: 5px;
    border-radius: 5px; 

    -webkit-box-shadow: inset 0px 0px 18px #000;
    -moz-box-shadow: inset 0px 0px 18px #000;
    box-shadow: inset 0px 0px 18px #000;

    width: 240px;
    height: 240px;
    padding: 20px
}

HTML:

<div id="box">
    <div id="wrapper">
        Content here
    </div>
</div>
thirtydot
  • 224,678
  • 48
  • 389
  • 349
0

Just make sure the child background property is specified with rgba, like in this fiddle.

Give the parent a background-color to prevent whatever's underneath showing through.

ul {
    box-shadow : inset 0 0 10px 10px gray;
    background-color: white;
}

li:nth-child(even) {
    background : rgba(255,0,0,0.2);
}
reentim
  • 11
  • 2
0

This works great for me without any additional DOM elements (like 'wrapper' etc.):

div.img {
  display: inline-block;
  position: relative;
  width: 400px;
  height: 280px;
  background-image: url(/images/anyimage.png);
}

div.img:after {
  display: inline-block;
  width: 100%;
  height: 300px; //parent height +20px
  position: absolute;
  top: -10px;
  left: 0;
  box-shadow(inset -25px 0 25px -25px rgba(0,0,0,.2), inset 25px 0 25px -25px rgba(0,0,0,.2));
  content: ' ';
  pointer-events: none;

}

0

the problem is layered is overlapped, you can avoid it using margin or padding. Try http://jsfiddle.net/pramendra/FEk3c/5/

#box{
    background-color: #FFFFFF;
    border-radius: 10px 10px 10px 10px;
    box-shadow: 0 0 10px #000000;
    width: 300px;
    height: 300px;
}
#body{
    margin: 0px;
}


#wrapper{
    display:inline-block;
    width: 280px;
    height: 280px;
    border-radius: 5px;
    box-shadow: 0 0 10px #000000 inset;
      box-shadow:inset 0 0 10px 0 #000000;
        margin: 10px;
}

#box_content{
    background-color: #f00;
    margin:5px;
}
Pramendra Gupta
  • 14,667
  • 4
  • 33
  • 34
0

Check this fiddle: http://jsfiddle.net/FEk3c/6/

#box{
    background-color: #FFFFFF;
    border-radius: 10px 10px 10px 10px;
    box-shadow: 0 0 10px #000000;
    width: 300px;
    height: 300px;
}
#body{
    margin: 0;
}

#wrapper{
    display: inline-block;
    width: 280px;
    height: 280px;
    border-radius: 5px;
    box-shadow: 0 0 10px #000000 inset;
    margin: 10px;
}
#box_content{
    background-color: #0ef83f;
    height: 100px;
}
Eric Fortis
  • 16,372
  • 6
  • 41
  • 62
  • nah - i need inner box and outer box with differents backgrounds - anyway, this could be a solution (as thirdydot answer), i updated my question. – Strae Mar 23 '11 at 03:51