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.