Yichuan Shen

Blog

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.

Pure CSS text reflection in Safari, Firefox and Opera

Try it out

9 comments

  1. Leave your opinion
  2. jean says:

    There’s so many cool things happening in webdesign now. Including your site. Thanks!

  3. Bryce says:

    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?

  4. steph says:

    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!

  5. Gareth says:

    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.

    http://modernizr.com/

  6. Jason says:

    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-sized border-radius, and used

    box-shadow: 0px 0px 10px 5px #color;

    This gave a relatively decent “bubble” to frame my reflected text. #color was 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…

  7. Allen Hartwig says:

    Works great!

    To have it be a bit more dynamic, and keep the content in the HTML, try this:

    Reflected Text!

    .reflected:before { content: attr(data-value); }

  8. Allen Hartwig says:

    It ate my HTML…

    <. h1 class=”reflected” data-value=”Reflected Text!”>Reflected Text!<. /h1>

  9. Allen Hartwig says:

    Also, to keep the reflection gradient from interfering with other page content, add this:

    .reflected:before { z-index: -10; } .reflected:after { z-index: -5; }

  10. JP Hellemons says:

    Nice article, I have added the suggestions of Allen Hartwig to my code, but somehow my padding-left and line-height give me strange issues…

Leave your opinion