Grow your CSS skills. Land your dream job.

Frosting Glass with CSS Filters

Published by Guest Author

The following is a guest post by Bear Travis, a Web Standards Engineer at Adobe. I'm a fan of how Adobe is pushing the web forward with new design capabilities, and doing it in a responsible way. CSS filters is a good example. They knew they were desired because Photoshop paved the way. They brought them to the web with a sensible syntax and they helped with both the spec and browser implementation. Now we're seeing them in stable browsers, and they are advocating use through responsible progressive enhancement. Hallelujah. Here's Bear with a tutorial about just that.

While filters such as contrast, saturate, and blur have existed in image editors for some time, delivering them on the web has historically required serving images with those filters already applied. As browsers begin to incorporate filters as part of the web platform, we can begin breaking down complex visual effects into their component parts, and implementing them on the web. This article will examine one such effect, frosted glass, and how CSS filters provide a cleaner, more flexible solution than static images.

Old School: Frosted Glass with Images

The frosted glass effect has been kicking around the internet for a while; we even saw it here on CSS-Tricks back in 2008. The idea behind the effect is relatively simple: just blur and lighten the area behind overlaid content. The content gains higher contrast with its background, but you still maintain a rough idea of what's going on behind it. The CSS-Tricks article uses two images: a standard version and a frosted version (blurred with a white tint). In our example, a card slides up to reveal content, while frosting over the background.

Demo

See the Pen Frosted Glass Effect Using Multiple Images by Adobe Web Platform (@adobe) on CodePen.

The HTML

The markup is relatively simple. We only have a single article that contains content.

<article class="glass down">
  <h1>Pelican</h1>
  <p>additional content...</p>
</article>

The CSS

We first size everything to the viewport. Then, we overlay a blurred version of the background on top of the original background. Finally, we add a white tint. The overflow is hidden to prevent scrolling and to clip the effect to the .glass element.

html, body, .glass {
    width: 100%;
    height: 100%;
    overflow: hidden;
}
body {
    background-image: url('pelican.jpg');
    background-size: cover;
}
.glass::before {
    display: block;
    width: 100%;
    height: 100%;
    background-image: url('pelican-blurry.jpg');
    background-size: cover;
    content: ' ';
    opacity: 0.4;
}
.glass {
    background-color: white;
}

The above CSS will create our blurred and lightened overlay. We also need to shift the overlay down to the bottom of the page, leaving just enough space to view the header text. Since the blurred image is a child of the overlay, we also need to shift it back up by the opposite amount in order to keep it aligned with the body background. Because the demo uses transitions, I chose to use CSS transforms rather than the background-attachment property, as CSS transforms can be hardware accelerated.

.glass.down {
    transform: translateY(100%) translateY(-7rem);
}
.glass.down::before {
    transform: translateY(-100%) translateY(7rem);
}
.glass.up, .glass.up::before {
    transform: translateY(0);
}

Notes

If you'd like a further breakdown, I built a deconstructed version of the effect.

The above technique is straightforward, and has solid browser support. Although I spruced up the demo a bit with transitions, the other required features – generated content, opacity, transforms and background-size – all have solid browser support ranging back to IE 9 (with the exception of Opera Mini).

New School: Frosted Glass with Filters

The duplicate image technique requires maintaining a blurred image along with the original, which can become a pain if you need to reuse the effect for multiple images. For example, responsive designs may require swapping in different images at different screen sizes. Or, template layouts may drop in images dynamically (eg, a different header image for every blog post). For these cases, it would be nice to generate the effect using only the source image. After all, we're just blurring it.

This is where CSS Filters come in handy. They allow us to apply the blur in the browser, using the CSS filter property.

The CSS

We can adjust the CSS for the frosted glass overlay to be the original image with a blur filter applied.

.glass::before {
    background-image: url('pelican-blurry.jpg');
}
.glass::before {
    background-image: url('pelican.jpg');
    filter: blur(5px);
}

Demo

See the Pen Frosted Glass Effect Using Filter Effects by Adobe Web Platform (@adobe) on CodePen.

Caveats

Easy peasy, right? Unfortunately, CSS Filters are somewhat new. That means they may be vendor prefixed, and that their browser support is not yet universal. However, filters have a longer history in SVG, and applying SVG filters to HTML content via CSS has wider browser support. You can easily add them as a fallback for when CSS filters are not supported. The above demo actually does just that.

To add an SVG filter, we include some inline SVG in our HTML markup, and reference the filter with a url(). Pro tip: An alternative is to encode the SVG filter and reference as a data url, but that format is a bit more difficult to read in an article.

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <defs>
    <filter id="blur">
      <feGaussianBlur stdDeviation="5" />
    </filter>
  </defs>
</svg>
.glass::before {
    background-image: url('pelican.jpg');
    /* Fallback to SVG filters */
    filter: url('#blur');
    filter: blur(5px);
}

There will still be cases where neither CSS nor SVG Filters are supported by a browser. In that case, the user will see text on a lightened (tinted but unblurred) background, which isn't too shabby.

Conclusion

Filters allow us to use effects in the browser that were previously only available in image editors. As an element's style, rather than a rendered image, they are easier to alter and reuse. You can use CSS Filters in current versions of Chrome, Safari, and Opera, and they are under active development in Firefox (no word yet on Internet Explorer). With a little care towards fallback behavior, you can start using them today.

Comments

  1. Jared Christensen
    Permalink to comment#

    In the new school css before example. Did you want pelican.jpg and not pelican-blurry.jpg? If I’m wrong feel free to delete my comment.

    • @Jared: in the “new school” example, he’s using ‘filter: blur(5px);’, so pelican-blurry.jpg isn’t needed. That’s why it’s new school.

    • Strve
      Permalink to comment#

      Yes, I agree it’s a typo

    • Bear Travis
      Permalink to comment#

      @Jared, @Strve: Are you referring to the “CSS Before” and “CSS After” sections beginning the New School section? I should have divided this more clearly, but the “CSS Before” is supposed to represent the old-school (pelican-blurry.jpg) syntax, while the “CSS After” demonstrates the adjusted, new-school (pelican.jpg + blur filter) syntax. I suppose it doesn’t help that I’m also using the ::before pseudo-element in the CSS.

  2. msz900
    Permalink to comment#

    nice :)

  3. dtjftkftufd
    Permalink to comment#

    Would of been cool when skeuomorphic design was all the rage but nowadays kinda dated. Impressive nevertheless.

  4. Permalink to comment#

    I think the biggest problem still with CSS filters is performance. I remember recently I was trying to do a similar frosted effect on a full frame, retina, image and even on my 12 core mac pro all of sudden chrome really struggled to scroll the page and any CSS transitions became impossible.

    • Had the exact same issue about a week ago. Pulled the effect out of the app I was creating. It is great when used sparingly but can really drain the CPU when not looked after.

    • Bear Travis
      Permalink to comment#

      @ryab, @mike: The effect can become costly, especially with large images. If either of you have examples you can share where the effect’s performance started to become an issue, I would be very interested in taking a look. The only tip I can give is for animations and transitions, where making the effect more GPU friendly can sometimes help.

    • @Bear if only there was a write once run anywhere solution for the web that already supported all of these effects ;P

  5. I did something similiar with the filter expression (http://codepen.io/jamespr/pen/aipgo). Glad to see that this kind of effects.

  6. Shouldn’t I use prefix for browser?

    -webkit-filter: blur(10px);
    -moz-filter: blur(10px);
    -o-filter: blur(10px);
    -ms-filter: blur(10px);
    filter:progid:DXImageTransform.Microsoft.Blur(PixelRadius='10');
    
  7. Excellent! I’ve been looking for easier ways to integrate the iPhone effect of blurred backgrounds with scrolling. Can’t wait for it to be more widely accepted!

  8. I think I found a flaw… I cannot see the blur effect on my Android 4.4 KitKat version using the new Google Chrome? does anyone else have this issue?

  9. Permalink to comment#

    Key (unwanted) difference: feathered edges. The CSS-filtered image produces soft feathered edges, and AFAIK, there is no way to clip them. The browser applies the blur to the visible part of the image, even when cropped inside a smaller element with overflow:hidden. The only solution I’ve found for a nice clean blur is to use canvas to import the image data, run a blur filter on the data, and export the blurred image using toDataURL, or alternatively, use the canvas itself.

    Check here for some good blurs: https://github.com/Quasimondo/QuasimondoJS/tree/master/blur

    #protip – import the image into a smaller canvas (it’s a lossy process anyway), but it gets past a narrow bottleneck in Safari.

    I’ve used this trick to great effect with video getting a full 60fps across the board. Bug me on Twitter (@furf) and I’ll post the code samples.

    • Permalink to comment#

      Samples canvas blur implementation over video (as mentioned above).

      http://www.furf.com/exp/video-blur/

    • Bear Travis
      Permalink to comment#

      I agree the feathered edges can be kind of frustrating. In certain cases, you can clip a slightly larger blurred image element to its parent to get a crisp edge. I did a quick mock up of what this would look like with the demo in this article.

    • Permalink to comment#

      Nice. For some reason I was never able to get the crop to work. Will have to revisit my demo :) Thanks!

  10. CSS blur filter gives ugly gradients towards the frame.

  11. Very cool stuff. Interestingly, the old school version isn’t working for me in Safari 6.1.

  12. Nicklas
    Permalink to comment#

    Wouldn’t you be able to use inherit for the background-image value to prevent repeating the URL if you used filter:blur()?

    • Bear Travis
      Permalink to comment#

      Unfortunately not in this case, as .glass::before’s parent is .glass, and the background image is set on body.

  13. Some time ago I was playing with filters Css and scroll.
    Two pens for enyoy css:
    Dynamyc Inside blur
    Dynamyc Outside blur

  14. Michael
    Permalink to comment#

    I don’t like the new school version at all. The blur property ruins the crisp edge and adds a halo around the image.

    I really hate the Blur property

    • “and adds a halo around the image”

      I don’t see this. What browser? I’m on Chrome 33.

    • Michael
      Permalink to comment#

      The halo is very minor, but still there in the demo up top.

      Bump up the blur and opacity, you will see it.

      Chrome – Version 33.0.1750.152

    • I increased the pelican image upto 400% and do not see a halo whatsoever. That might be a personal preceived visual distortion.

  15. Jeff McKeand
    Permalink to comment#

    Would be even better if we could pull this off without a second instance of the image. I know a lot of people (including myself), are looking for ways to lay the frosted effect over non-image html elements underneath. There are workarounds if the overlay is full screen, but not if the frosted effect needs to be cut off mid-screen.

  16. Permalink to comment#

    Brilliant, exactly what I was looking. Thanks a million.

  17. Iain
    Permalink to comment#

    Hi

    Im a little confused I recreated the code pen and does not appear the same as if it is not get the correct font (Source Sans Pro)? Any idea why would this be?

    In the end I just copied the HTML,CSS and JS from yours to mine and still the same

    My Pen and Yours Your pen

    • Iain
      Permalink to comment#

      Found it, needed to change the settings on the CSS and load in the fonts!! Only just noticed the settings cog on codepen

  18. Steven Sinatra

    For some reason when I implemented this theory on a background image inside a absolute positioned pseudo-element of a flexbox item and rotated, it disables the background image itself on Firefox. Weird, and that’s even after I disabled every style other than the filter and the background image (even the content: ”;), and it still doesn’t work.

    I wonder if there’s actually a concrete solution to this. Found references in StackOverflow but none of the solutions seem to work.

  19. Would it be possible to do this with a video background?

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".