Hacker News new | past | comments | ask | show | jobs | submit login
Frosted glass effect with CSS and SVG (codepen.io)
88 points by hemezh on Nov 14, 2013 | hide | past | web | favorite | 39 comments

Looks nice, but I really love the Google Font API trick there; I did not know that by using the text querystring, you can build a custom font with just the letters you need :)

I didn't know this either, thanks for the tip!

Relevant line / explanation: two backgrounds, top layer is a gaussian blur inside SVG, second one is the image that will be blurred.

    background-image: url("data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%20width%3D%221920%22%20height%3D%221120%22%3E%3Cdefs%3E%3Cfilter%20id%3D%22blur%22%3E%3CfeGaussianBlur%20stdDeviation%3D%225%22%2F%3E%3C%2Ffilter%3E%3C%2Fdefs%3E%3Cimage%20xlink%3Ahref%3D%22http%3A%2F%2Fplacekitten.com%2F1920%2F1120%22%20width%3D%221920%22%20height%3D%221120%22%20filter%3D%22url%28%23blur%29%22%2F%3E%3C%2Fsvg%3E"), url("http://placekitten.com/1920/1120");

and this is the unescaped/indented version of the SVG in the data-URL.

(figured that, after I decoded it, might as well post it for everyone, couldn't make heads or tails of that side-scrolling oneliner :) it's not very complex an sich but it nicely shows how simple it is to wrap an image in a SVG for filtering/other purposes)

    <?xml version="1.0" encoding="UTF-8"?>
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1920" height="1120">
            <filter id="blur">
                <feGaussianBlur stdDeviation="5"/>
        <image xlink:href="http://placekitten.com/1920/1120" width="1920" height="1120" filter="url(#blur)"/>

I've seen this a bunch of places, until it's done real time with arbitrary images + content, I don't really see the value.

Would be cool if we could do it for translucent toolbar etc.

It's difficult, because you cannot see the pixels in an HTML element's rendering with JavaScript. If you could copy a link to a canvas, then you could see if it has been previously visited, for example. So, canvases would not work.

I may be possible with SVG filters or WebGL, but that also has security implications. It's possible to read cross-origin content using timing attacks and filters. http://www.contextis.com/files/Browser_Timing_Attacks.pdf

Here's a screenshot for a quick view: https://www.dropbox.com/s/35060r2obuwse4f/Photo%2014.11.2013...

It looks better when you see it moving.

Any reason why it's only available for iPhone 5?

Three reasons.

1. Blur filter is only available on WebKit 2. I know for sure how much texture memory is on an iPhone 5 3. The touch event latency on android is too damn high.

>> <h1>If you see this, something is broken.</h1>

The funny thing being that I only saw that because I browsed the source, because the page was so broken for me that I only saw a black screen.

In any case, I see

    Message(null, " This demo is only available for iPhone 5 and iOS 7. Sorry! " )

So I'm out of here.

There was some small text centered on the screen specifying the demo is only available on iPhone 5 (see comment above for why)

Now this is interesting, how does it work ?

They use a webkit CSS extension: "-webkit-filter:blur(5px)"

There's a Firefox bug to implement it: https://bugzilla.mozilla.org/show_bug.cgi?id=660196

That blurs the content inside of a div, how is the content tied in, is it scroll synched?

I do synthetic scrolling (translate3d() + touch event interpretation and inertial math). Then duplicate the DOM for the top and bottom bars, adjust the positioning to make them look fluid and apply the CSS blur filter.

It's easy with React :)

It is done client-side in real time with arbitrary content using an SVG GaussianBlur filter. Decode the data: urls in the SVG to see the full source.

right but it doesn't work with rendered text from arbitrary html content, only by applying filters to an image.

I see a big value in UI design, where you want to make sure that the general layout of your screen is as intended.

I'm still thinking in actually making this thing as a physical object with a handle you put in front of the screen.

Awesome demo, but unfortunately rather slow on my (oldish) Macbook.

I also recently made a page with frosted glass effect, but opted for pre-rendered images because of those performance issues: https://eggerapps.at/pgcommander/fancy-index.html (But I decided the effect was too playful for my website and so it's not public)

How "oldish" is your Macbook? I'm using a core2duo and didn't have any problems.

In fact, retrieving an image from Placekitten took the longest on the network, followed by the overhead of loading a Google font. The only real CPU time spent on this page is the overhead of codepen.

Are you mistaking network latency for performance issues with the example?

I'm also on a core2duo, but I found it slow. It loaded and rendered quickly, but when I resized the preview window (the ability to resize being the main point of doing it this way, I assume), it was very choppy.

Browser versions are important. Do you mind pasting a profile from your debugging tool of choice?

About 4 years. As another commenter said, the problem wasn't loading time, but choppy scrolling/resizing. I am on Mavericks/latest version of safari.

Blur is really slow, esp. when you're trying to animate it (to get a cool "materialization" effect).

Thought of a way to do a materialization effect with good performance. Fake it. If you set a low opacity on the blurred element (ie, put "opacity: 0.5" on the ".glass::before", essentially mixing the blurred image with the sharp one beneath it), this actually looks like it's half as blurred as before.

Opacity can be animated very cheaply, entirely on the GPU (source: http://www.html5rocks.com/en/tutorials/speed/high-performanc...), so if you animate this property from 1 to 0, you should a good materialization effect, without ever asking the CPU to recalculate the blur.

I'm going to fork the codepen and try this, will report back...

EDIT: see http://codepen.io/callumlocke/pen/EKuvs

For me (latest Firefox beta, on Windows 7) your materialization effect animates at about 2Hz.

[EDITED to fix a stupid mistake: I wrote 0.5Hz but meant once per 0.5s, or 2Hz.]

Weird. It works pretty smoothly on Chrome (about 50Hz). Just tried on FF/Mac, it's ultra slow there too. I think it must be redrawing the SVG every frame, if it's that slow. But in the HTML5Rocks tutorial Paul Irish says "Chrome, Firefox, Safari and Opera all hardware accelerate transforms and opacity." I'll try a few more things.

EDIT: ha, IE10/Win7 (in a VM) is super smooth for me. Still no idea what's going on with Firefox.

There is still one problem with using the blur filter in CSS. It's all about the edges.

As you increase the blur the edges shrink inwards. This makes it difficult to get a frosted glass effect with more blur. Try setting a higher blur, eg:

   -webkit-filter: blur(20px);
   filter: blur(20px);

A workaround would be to wrap the blur layer in another one with overflow:hidden and extend the edges of the inner one. I wonder if that would do the trick.

Really cool effect. Great way to get it without resorting to images.

In the future, I wonder if something like this could be done with the -filter attributes, though those may only work on images. I know those have been used to do blurring before, though possibly not in the same way.

Try adding -webkit-filter: blur(5px) to the body tag of a document. It'll blur anything, not just images.

Ah, I implemented frosted glass years ago in SVG using the BackgroundImage source for a feGaussianBlur (composed with other filters, of course). It works fairly well in Inkscape and other such tools, but alas! No browsers supported it and I believe that it is still the case that no browsers support it.

Of course, there are security implications, but those are fairly trivial given the infrastructure already in place.

can someone explain what magic is going on inside ".glass::before" with the background image and svg filter?

There isn't actually as much magic as I first thought. The SVG (which is loaded via data URI) actually loads the same cat image again, and blurs it. (The cat URL is hardcoded into that SVG string in the data URI). So you have to know the image URL in advance, and generate a data URI for an SVG that contains it. Therefore this wouldn't work as a CSS-only technique if you wanted a dynamic image URL - you'd need JavaScript for that.

Tip: you can copy the whole data URI into your browser's location bar it will load the SVG. Then you can open devtools and inspect it to see what's going on.

You can use a svg in a url() and in this case it's inlined. If you url-decode it's:

    <?xml version="1.0" encoding="UTF-8"?>
    <svg xmlns="http://www.w3.org/2000/svg"
         xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1920"
            <filter id="blur">
                <feGaussianBlur stdDeviation="5"/>
        <image xlink:href="http://placekitten.com/1920/1120" width="1920"
               height="1120" filter="url(#blur)"/>

That's one heck of a cute cat!

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact