Recently I was asked to find a CSS-only solution for image (or anything) reflections, and since the only browsers that support box reflections (-webkit-reflect) out of the box are Google Chrome and Apple Safari, I had to find a crossbrowser solution, and this is what I would like to present today.
The Markup
Actually we need just a single element. A <div /> will do the job:
<div class="css-reflection"></div>
The CSS
In order to save myself from using nested tags, I decided to utilize the ::before and ::after pseudo elements. The ::before element will hold the actual reflection, and the ::after – the gradient blur.
The Reflection
In the ::before element, I set border and background to inherit, so the properties get their values from the parent element. Then I just flipped the element and offest it to 100% top:
transform: scaley(-1); top: 100%;
The Reflection Gradient
In the first implementation I used CSS3 gradients to achieve the gradient blur, but since the application was supposed to run only on latest browsers, I decided to switch to SVG and keep the gradient definitions in a single place rather than boosting my CSS with vendor-specific -bula-bula-linear-gradients:
The SVG
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="gradient-to-white" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0" stop-color="#fff" stop-opacity=".7"/>
<stop offset="60%" stop-color="#fff" stop-opacity="1"/>
</linearGradient>
</defs>
<rect width="100%" height="100%" style="fill:url(#gradient-to-white); " />
</svg>
The CSS
.css-reflection::after
{
background: url("gradient-to-white.svg");
}
The above is pretty straightforward – we create a rectangle that occupies 100% of its parent, then define a white semi-transparent to fully opaque white gradient. The SVG file is then set as background image to the ::after pseudo element of .css-reflection. Actually in the SVG file we can define any gradient color(s) that will match the parent of the element with reflection.
Displaying Pictures as Background Images
In order to display different images, I set a secondary class name to the .css-reflection reflection element:
<div class="css-reflection kitten-01"></div>
… And the following CSS:
.kitten-01
{
background: url("images/kitten-01.jpg");
}
So, that was it – quick and dirty. And a few ideas for consideration and maybe inspiration:
- You can set the border-radius of the ::before and ::after elements to inherit, so the reflection will get the border-radius of the parent.
- If you wish to have text which can be also flipped, you can use two nested elements with the same content, and flip vertically the second one and position it according to the reflection.
- You may play with the -moz-element() property of Firefox to draw arbitrary elements as background to other elements, it’s very cool and can also be used to create CSS-only reflections.
- You can use <img /> tag, clone it, and then flip the clone and again play with the SVG/CSS3 gradients if you wish to have a real image reflection.
The demo is available on this page, or you can download the example from this link. Find more experiments here.
Related Posts
- CSS3 Driven Slides Viewer Without any JavaScript
- HTML5 Resume Generator and Onepager Website
- Selecting only the first element occurence out of siblings with the same class name with CSS3
- Fully Functional CSS3-only Tabstrip Without JavaScript
- Imageless CSS3 Custom Checkboxes and Radio Buttons
- Creating Gaussian Blur Effect With CSS3
- Fancy CSS3 Tooltip (Yeah, Without JavaScript)
- How to Style Select Boxes with CSS3
- CSS3 Element Reflections
- CSS3 Treeview. No JavaScript.
- CSS3 iPhone Toggle Buttons
- CSS3 Background Image Cropping
