CSS reflections for Firefox, with -moz-element() and SVG masks

We all know about the proprietary (and imho, horrible) -webkit-box-reflect. However, you can create just as flexible reflections in Firefox as well, by utilizing -moz-element(), some CSS3 and Firefox’s capability to apply SVG effects to HTML elements. And all these are actually standards, so eventually, this will work in all browsers, unlike -webkit-box-reflect, which was never accepted by the CSS WG.

First and foremost, have a look at the demo:

How it works

  • For every element, we generate an ::after pseudoelement with the same dimensions and a position of being right below our original element.
  • Then, we make it appear the same as our element, by giving it a background of ‑moz-element(#element-id) and no content.
  • Reflections are flipped, so we flip it vertically, by applying transform: scaleY(‑1);
  • If we want the reflection to have a little distance from the element (for example 10px like the demo), we also apply a transform of translateY(10px)
  • We want the reflection to not be as opaque as the real element, so we give it an opacity of around 0.3-0.4
  • At this point, we already have a decent reflection, and we didn’t even need SVG masks yet. It’s essentially the same result -webkit-box-reflect gives if you don’t specify a mask image. However, to really make it look like a reflection, we apply a mask through an SVG and the mask CSS property. In this demo, the SVG is external, but it could be a data URI, or even embedded in the HTML.

Caveats

  • Won’t work with replaced elements (form controls, images etc).
  • If you have borders, it gets a bit more complicated to size it properly
  • Doesn’t degrade gracefully, you still get the pseudoelement in other browsers, so you need to filter it out yourself
  • Bad browser support (currently only Firefox 4+)
  • You need to set the reflection’s background for every element and every element needs an id to use it (but this could be done automatically via script)

Further reading

Credits: Thanks to Christian Heilmann for helping me debug why SVG masks for HTML elements weren’t originally working for me.

  • @acielouvert

    Brilliant, thank you Lea.

  • @kevindeedavis

    Thank you, been wondering how to do this.

  • Paul

    Same example there: https://hacks.mozilla.org/2010/08/mozelement/ (with some more stuff)

    • http://leaverou.me Lea Verou

      Yeah, Christian just sent it to me. I guess the only thing I did different was not using extra markup but generated content instead. The upside of using extra markup though is that it will work with replaced elements as well. Nice examples there though, thanks for the link!

    • http://leaverou.me Lea Verou

      And post edited, to include a link to your examples :)

  • Pingback: xhtml css templates – CSS reflections for Firefox, with -moz-element() and SVG masks … | XHTML CSS - Style sheet and html programming tutorial and guides

  • Nahuel

    Awesome demo :)
    I particulary like  how it even reflects text selection.

  • http://twitter.com/rik24d Anthony Ricaud

    Regarding sizing with borders, maybe -moz-calc() can help?

    Regarding degrading the pseudo-element, when I played with this a few months ago, I “prefixed” the selector with “-moz-any(body)” so that only Firefox 4+ sees the pseudo-element. I don’t like it because it ties one CSS feature to another but at least it gets the job done.

    • http://leaverou.me Lea Verou

      There are many ways around the border issue, I just said it’s “a bit more complicated”, not impossible. I just didn’t want to complicate the demo.

      Regarding degradation, I’ve been thinking it’s not so bad even as it currently stands. Yes, they will still get the pseudo, but it will be transparent and empty, so it won’t show. And if the presence of the pseudo itself causes trouble, it will do so in Firefox as well. It’s just redundant, but doesn’t break anything.

  • Pingback: Some links for light reading (1/7/11) | Max Design

  • http://rolling-webdesign.com Theo

    Once more, great stuff, thanks!

  • Pawel

    You can add a little blur to the mask: http://pastie.org/2151401

  • Pingback: CSS3 を使った鏡面反射効果 : Serendip - Webデザイン・プログラミング

  • Stan Rogers

    I truly hope that if a reflection method is made standard that it uses the far more sensible -webkit-style solution. There’s no need to explicitly create an additional element to contain the reflection, and the mask is created using an existing scalable gradient — involving an additional syntax that is native neither to HTML nor CSS is an unnecessary complication to a solution that can be accomplished in a very few characters using native CSS.

  • http://beben-koben.myopenid.com/ Beben Koben

    interesting my master…this is awesome
    in .reflect:after to make it look part of it…maybe can add
    margin-bottom:50px;

    so good master, ty^^

  • Clément

    Can I use it with attr() ?

    somethink like this:

    ‑moz-element(‘#’attr(‘id’))

    to avoid to add style for each element ?

    • http://lea.verou.me/ Lea Verou

      Unfortunately not. But there will be better ways to reference elements in the future.

  • Ahs

    Thanks for the straightforward rundown. I am currently trying to infuse the nav menu items in a WordPress theme with this effect, and the items do not use an ID. Can you enlighten me as to how this could be scripted, as someone who has a basic knowledge of JS? Much thanks.