开发者

Rendering CSS3 inset shadow with an image

I would like to take advantage of the new CSS3 box-shadow feature for a site I am working on. The problem is that Chrome 9.0.5 and Opera 10 do not render the inset border correctly if there is an img inside (the borders are hiddden around the image area).

I understand box-shadow is still work in progress, but I would expect browsers to fully support it or fully ignore it.

<!doctype html>
<html>
  <head>
    <style>
        di开发者_运维百科v {
            border: 1px solid black;
            width: 300px;
            height: 200px;
            overflow: hidden;

            // CSS3 inset shade
            -moz-box-shadow: inset 0 0 20px red;
            -webkit-box-shadow: inset 0 0 20px red;
            box-shadow: inset 0 0 20px red;
        }
    </style>
  </head>
  <body>
        <div>
            <img src="http://www.google.com/images/logos/ps_logo2.png" width="364" height="126" alt="" />
        </div>
  </body>
</html>

Does one know some workaround to render the red shade correctly?

Thanks!

Edit: I am happy with the answer, but just wanted to add a live link to help other folks out there. Here it is


Box-shadow is just above the background on the stacking order when using inset. Therefore, any image you have inside the div will cover the shadow.

Per the W3C Specs

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 other words, Chrome and Opera are doing it correctly (FTR, FF 3.6.13 does the same thing as Opera).

If you want the shadow to overlap the image, you have a few different options, depending on your needs:

  1. Set the image to the background property of the div.
  2. Absolutely position a div over the one with the image, make it the same size, and put the shadow there (not really recommended, as it's convoluted and adds non-semantic markup).
  3. Make sure the backgrounds of the images are transparent (this will allow the shadow to show through, but non-transparent pixels will still cover the shadow).
  4. Consider using border-image and gradient, instead. (This one is also a little convoluted, but puts the gradient in the border itself, and you can fade to transparent using RGBA.)


There's a better solution – just set this CSS on your img.

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

Example: http://trentwalton.com/2010/11/22/css-box-shadowinset/


Use a pseudo-element to apply the shadow over the image. This avoids adding an extra, un-semantic sibling to your markup, works regardless of other elements' backgrounds (unlike setting z-index: -1), and doesn't require JavaScript.

Simple live example: http://jsfiddle.net/4qvzqajq/

OP's example: http://jsfiddle.net/AWaVC/138/

Assuming this markup:

<div class="container">
    <img src="http://stackoverflow.com/content/stackoverflow/img/apple-touch-icon.png" />
</div>

This CSS will apply an inset shadow over the div's content (including the image):

.container {
    position: relative;
}
.container:after {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: 100%;
    content: '';
    -moz-box-shadow:    inset 0 0 5px #000000;
    -webkit-box-shadow: inset 0 0 5px #000000;
    box-shadow:         inset 0 0 5px #000000;
}


Yesterday I've got a solution with single DIV and background-image property. If we are talking about a dynamic site with image dimensions unknown or not-so-clear, we may utilize JavaScript Image class. Really this is no "monkey wrench" nor rocket science about setting correct width and height.

Look at this with JQuery loaded:

<style type="text/css">
  #ribbon div {
    display: inline-block; /* no hacks about left-floating images */
    border: none;
    border-radius: 8px; /* just for test inset shadow with rounded borders */
    -webkit-border-radius: 8px;
    -moz-border-radius: 8px;

    // CSS3 inset shade
    -moz-box-shadow: inset 0 0 20px red;
    -webkit-box-shadow: inset 0 0 20px red;
    box-shadow: inset 0 0 20px red;
  }
</style>

<script type="text/javascript">
  $(function(){

    // Here's our images. We can load a list with AJAX.
    var sources = ['1.jpg','2.jpg','3.jpg'];
    var imgs = [];

    var ribbon = $('#ribbon'); // Image list container

    // Add images to the ribbon
    for (var i=0, len=sources.length; src=sources[i], i<len; i++) {

      var div = $('<div>'); // Create an empty DIV
      div.attr('id','thumbimg'+i); // Name our DIV for async access
      div.css('display','none'); // Make it hidden while loading the image
      div.appendTo(ribbon); // Add to container

      imgs[i] = new Image(); // Empty Image object
      imgs[i].id = 'img'+i; // Name it for DIV match

      // We can get the dimensions only after the image is loaded
      imgs[i].onload = function() {
        var myDiv = $('#thumb'+this.id); // Matching 'thumbimgX'
        myDiv.css({
          'display': '', // Clear display property = show hidden DIV
          'width': this.width + 'px', // Set DIV.width = Image.width
          'height': this.height + 'px', // Same for height
          'background-image': 'url('+this.src+')', // draw our image in background
          // Note the image already loaded and the div is inserted before
          // so picture just appears without lags
        });
      }

      // Load image
      imgs[i].src = src;
    }

  }
</script>

<body>
   ...
  <div id="ribbon"></div>
   ...
</body>

So we can display an image list with various inset shadow effects: vignetting (

inset 0 0 60px rgba(0,0,0,0.8)

), buttonize / fridge magnet (

inset -4px -4px 8px rgba(0,0,0,0.2), inset 4px 4px 8px rgba(255,255,255,0.8)

) and whatever you want. There's no IMG tag so right mouse click doesn't show you "save image" or "copy image address" options.

p.s. oops, fixed image load


The Problem with the negative z-index solution ist that if there is an element behind the image which has a background, the image gets overlapped. So this solution only works on white sites. My solution ist to put the shadow on a div which is a sibling of the img. This is div gets position: absolute; and is placed exactly above the image:

http://jsfiddle.net/E3hFM/

HTML:

<div class="teaserimage">
  <img src="http://placehold.it/300x200">
  <div class="shadow"></div>
</div>

SCSS:

.teaserimage {
    position: relative;
    float: left;
    img {
        vertical-align: middle; // to remove standard margin-bottom: 3px; of the image
    }
    .shadow {
        -webkit-box-shadow: inset 10px 10px 10px 0px rgba(0, 0, 0, 0.5);
        -moz-box-shadow: inset 10px 10px 10px 0px rgba(0, 0, 0, 0.5);
        box-shadow: inset 10px 10px 10px 0px rgba(0, 0, 0, 0.5);
        position: absolute;
        top: 0px;
        width: 100%;
        height: 100%;
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜