Code and Stuff

May 27, 2012

CSS3 Reflection (Webkit & Firefox)

This effect will only work with recent versions of firefox and webkit based browsers.


Given following HTML:
<div id="someid">
   <img src="image url" />
we want "someid" to have a reflection below. The method uses only CSS to implement the effect. No changes to the HTML and no javascript required.

In the following example the image is 300px wide and 247px high.


Webkit browsers (for instance safari and google chrome) have the very simple yet apparently not standard, -webkit-box-reflect css property.
#someid {
   /* need some space for the reflection */
   margin-bottom: 120px;

   /* the gradient makes the reflection fade out */
   -webkit-box-reflect: below 0px -webkit-linear-gradient(bottom, rgba(255,255,255,0.3) 0%, transparent 40%, transparent 100%);


With firefox we can use the element image (an images of a dom element) as background of the vertically flipped before pseudo element.
#someid {
   position: relative;
   /* need some space for the reflection */
   margin-bottom: 120px;

#someid:before {
   content:""; /* needed or nothing will be shown */

   background: -moz-linear-gradient(top, white, white 30%, rgba(255,255,255,0.9) 65%, rgba(255,255,255,0.7)) 0px 0px, 
               -moz-element(#someid) 0px -127px no-repeat;

   -moz-transform: scaleY(-1); /* flip the image vertically */
   width: 360px; /* should be > image width + margin + shadow */
   top: 247px;
To make the before pseudo element coordinates relative to the someid div we have to change the positioning. The offset of the element background (-127px) is the height of before pseudo element (140px) - (the height of image (247px) + border of div (20px)). Note that the firefox solution works only when the page has a solid background. The color of the background has to be the same as the one of the :before pseudo element's gradient.

Since all properties that have been used for the reflection, and that have a visible effect, are all vendor specific, the two method don't mess with each other.


Specs say that the two different methods will update if the content changes. Therefore they should work with video, and they do!

Firefox Glitch

Sometimes, firefox will render the gradient slightly smaller than the element background, resulting in a small line after the reflection fade out. To avoid that we can use a 1px padding on the top and bottom of the pseudo element and set the clipping and origins of the two backgrounds differently:
padding: 1px 0px;
background-origin: border-box, content-box;
background-clip: border-box, content-box;

No comments: