Reflecting text with pure CSS3

While designing some new site, I’ve decided to use some text reflections on the header in my designs… I’ve already created the header using @font-face and I didn’t want to create an header image, so I thought… hey, just try to imitate the reflection with CSS only.
The HTML code is very straight forward and semantic:
<!-- HTML code -->
<h1 class="reflected">Reflected Text!</h1>
Flipping the text vertically
I used the :after and :before pseudo-elements to insert the reflection. The tricky part is where you have to flip the reflection-text vertically. This can be done with a CSS 2D transformation. One could write a transformation matrix which does the flipping. However this requires knowledge of Linear Algebra and too difficult for us to handle. The trick is simply using a negative value for scaleY.
For the mathematically challenged who are reading my blog: Here’s an excellent article how those transformation matrices work → and how to create them.
/* CSS code */
.reflected {
position: relative;
}
.reflected:after {
content: 'Reflected Text!';
display: block;
position: absolute;
bottom: -.55em; /* You should change this value to fit your font */
left: 0;
right: 0;
opacity: .5;
/* This is how the text is flipped vertically */
-webkit-transform: scaleY(-1);
-moz-transform: scaleY(-1);
-o-transform: scaleY(-1);
}
Fading reflection…
Now we have to fade the reflection out. One could use a fade-out png image with alpha transparency, but what’s the fun in that? I researched on cross-browser CSS gradients and found an interesting article at WebDesignerWall →.
/* CSS code */
.reflected:after {
/* Fading using CSS gradient */
/* Don't forget to change the colors to your background color */
background: -webkit-gradient(linear, left top, left center, from(rgba(255,255,255,0)), to(rgb(255,255,255)));
background: -moz-linear-gradient(top, rgba(255,255,255,0), rgb(255,255,255));
/* I left out the `filter` property,
because IE doesn't know `:before` and `:after` pseudo-elements anyway */
content: ' ';
display: block;
height: 1em;
position: absolute;
bottom: -.8em;
left: 0;
right: 0;
}
And finally you can simplify the whole CSS by grouping common properties together:
/* CSS code */
.reflected {
position: relative;
}
.reflected:before, .reflected:after {
display: block;
position: absolute;
bottom: -.8em; /* You should change this value to fit your font */
left: 0;
right: 0;
}
.reflected:before {
content: 'Reflected Text!';
opacity: .3;
/* This is how the text is flipped vertically */
-webkit-transform: scaleY(-1);
-moz-transform: scaleY(-1);
-o-transform: scaleY(-1);
}
.reflected:after {
/* Fading using CSS gradient */
/* Don't forget to change the colors to your background color */
background: -webkit-gradient(linear, left top, left center, from(rgba(255,255,255,0)), to(rgb(255,255,255)));
background: -moz-linear-gradient(top, rgba(255,255,255,0), rgb(255,255,255));
/* I left out the `filter` property,
because IE doesn't know `:before` and `:after` pseudo-elements anyway */
content: ' ';
height: 1em;
}
Some inconveniences
As you can see, one can actually make a text reflection with CSS3 only. It just comes with some inflexibleness.
- It only works on a non-changing plain-color background.
- The reflection text is generated using CSS. Which means you have to change the CSS file if you change the corresponding text in the HTML file.
- It doesn’t work on all browsers (e.g. Opera)
- It looks differently on different browsers (see figure below)

Try it out
5 comments
- Leave your opinion
-
This is great, not clear on how I can turn off for IE… looks terrible but commenting it out would work, can you provide any update for this?
-
YOU ARE A GENIUS! Been looking and looking. Other sites really need to look up the word “mirror” before posting solutions. If I wanted vertical or 90 degrees, that’s what i would say! Mirror is THIS and it works perfectly!!!!
NOW-as Bryce asked, how to turn off for IE?? thanks!
-
How to turn it off? You can probably use Modenizr to detect the reflection feature and fork your css depending on whether the feature is supported or not.
-
Thank you very much for this! I looked for this a few months back and couldn’t find it. Looks like you’ve had it out for a while, though.
Two quick comments;
About backgrounds – To overcome a textured background, I wrapped “
.reflected” in a div with a solid background to match the “.reflected:after” color (#color), gave it an over-sizedborder-radius, and usedbox-shadow: 0px 0px 10px 5px #color;This gave a relatively decent “bubble” to frame my reflected text.
#colorwas just a tad off from my textured background and provided decent relief.@ steph ~ for IE, use a conditional statement and add a short stylesheet for IE after your other stylesheets with:
.reflected:before { display:none; } .reflected:after { display:none; }I’ve not used Modernizr, so I can’t comment. When the client isn’t paying extra for IE perfection, I just degrade the experience. Nothing says the web must be consistent for all browsers; some reputable sources even suggest otherwise…
There’s so many cool things happening in webdesign now. Including your site. Thanks!