This always bugged me! The whole point of frosted glass is to be smooth and relaxing, but the lack of surrounding pixel data causes the blurred image to make unnatural jumps in brightness and color when just a single row of pixels scrolls into view.
It makes me very happy that someone not only noticed this, but did something about it, and then shared it freely!
I don’t like the `height: 200%`: you might as well be specific about how much extra you need, because an extra 100% might be a lot more than you need, or not enough.
> Note: A true Gaussian blur has theoretically infinite extent, but in practice all implementations use a finite-area approximation of a Gaussian blur. At the time of writing (January 2024) all major implementations use the familiar three-pass box blur approximation, which has extent: ((3 * sqrt(2 * π) / 4) * σ).
¾√2π is about 1.88; it’s generally most convenient to just double the radius instead.
So, if you’re going for a 16px blur, add 32px. (The formula would make it 30.079px; so I’d accept 30px and 31px also.)
In the first main demo with code: ditch the `height: 200%`, change the inset to `0 0 -32px 0`, and change the 50% in the mask-image linear-gradient to calc(100% - 32px). (Aside: you can also shorten the gradient definition: linear-gradient(to bottom, black calc(100% - 32px), transparent 0%).) Applying it to later things is left as an exercise to the reader.
The SVG <filter> element is interesting in this rendering size question: it lets you control the rendering area for the filter, via its x, y, width and height attributes. Their defaults are -10%, -10%, 120% and 120%, meaning 10% overdraw on each edge. Unfortunately you can’t really do height="calc(100% + 32px)" which is what you’d want for the equivalent here. Yes, you could definitely do this whole thing in SVG, using the BackgroundImage source—in fact, you can do better, because you can composite that with SourceAlpha, rather than the dodgy mask-image technique you’re limited to in HTML/CSS. Unfortunately I don’t believe any current browsers support BackgroundImage, though I think IE and Opera used to, and Inkscape does.
All this time I thought a 16px gaussian blur meant it faded to 0 at 16px. That explains why I always seem to need to add some extra padding! I never thought to question it! Wow! I can use this right away to fix some stuff, thanks for sharing!
Thanks for the response! It’s always nice to know when some incidental thing you remark on has helped someone. Thinking back, I suppose I struggled with understanding the SVG <feGaussianBlur stdDev> parameter when messing around with complicated filters in Inkscape a few years back, for much the same reasons. And I didn’t actually know the ¾√2π until today, I just knew that a factor of 2 was a little more than enough. I’m glad for the note being attached to the spec, it’s a great note.
Although people often talk of blur radii, it might help to remember it’s a standard deviation. Take the curve in https://en.wikipedia.org/wiki/Gaussian_filter#/media/File:Ga..., and a Gaussian blur is taking so much of each pixel value, most from the closest ones, less from further away, negligible by two standard deviations away, but only asymptotic to zero; hence the “theoretically infinite extent” the spec note mentioned. But the ¾√2π thing will probably be good enough forever.
Author here — yeah, so my goal with 200% was to make the code as comprehensible as possible. My actual glassy header does something quite similar to what you’re suggesting, but that also raises the bar quite a bit for how much CSS you need to know in order to understand this post.
I like making things like this copy/pasteable, rather than NPM-installable, so that more experienced developers can make tweaks like the one you suggest.
Your effort to make these posts consumable by the masses doesn’t go unnoticed. It’s clear you put a great deal of work into them, and the quality you achieve raises the bar in many ways for what to expect when learning about the web. If only all educational materials on MDN could reach these heights.
Honestly, I feel that `bottom: -32px` and `calc(100% - 32px)` might be easier to understand than `height: 200%` and `50%`. (Yeah, for early teaching I might step back from using `inset`.) It does require the one extra concept of calc(), but it’s exact and feels slightly more easily explicable than how 50% of 200% is back to 100%. The fact that the number 32 would be present in both makes it easier to track, whereas the fact that 200% and 50% are inverses is pretty easily overlooked.
I’m the author of tyleo.com. I’m happy to see folks innovating and building on the idea. I’m also surprised at how popular this topic is on HN!
Both of these posts add additional tweaks beyond `backdrop-filter: blur()` to enhance glass effects. We use different tweaks so it looks like the techniques in each of our posts is compatible. When I get around to it I’ll update my page to link to this new one.
Perhaps in a few weeks we will get the, “I’ve consolidated all the HTML glass effects on HN and this is what it looks like,” post :)
That one suffers from the effect described in the article, it only considers pixels directly behind the element for blurring. So unlike real glass it can't catch adjacent light.
But it is unique in its own way and has many other good ideas.
These effects are all pretty, but like... there should be some sort of media query for devices that are not that powerful (or their owners simply do not wish to burn through their batteries just to read a website). It gets pretty annoying that my phone slows down to a crawl when someone has these effects on their website. At the same time, simply opting out of the blurring and leaving everything else as-is is not a solution, since that may quickly render a lot of things unreadable.
Absolutely. None of these look good to me. I would rather just have plain text. I wish all of these fancy sites would at least include a plain text / simplified reader mode by default. Front end stuff is getting way too over engineered .
This is the sort of completely unnecessary details that eat hours of your time and add tons of code and maintenance for something that few-to-none notice.
It's great to experiment, but don't use this in projects that you intend to maintain.
I think "tons of code and maintenance" is an exaggeration for this effect, once it's done you'll rarely have to come back to it.
Many people value creating and using products with these kinds of details, I disagree with "don't use this in projects you intend to maintain" as across-the-board advice.
I disagree. Check the changes required to the spacing/sizing. Soon you will need to adjust those values and that.is.maintenance. Multiply this by each detail and soon you have more work than you signed up for. This is usually when someone comes along and wants a rewrite because the codebase is fragile.
If you're using a CSS preprocessor like SCSS or LESS you can just define the height for the toolbar as a variable and then use the mask area for the blur as a multiplier (eg. 1.88) of that variable. In general for making things easy.to.maintain it's better to not build project-wide stylesheets with raw CSS.
It's not universally safe to use CSS nesting yet. Without nesting support, writing raw CSS is like raw-dogging a sex-trafficked Vietnamese prostitute from Malaysia. Sure, it will probably work, but if your goal is zero maintenance then you're ignoring the post-exposure prophylaxsis and antibiotic regimens necessary for typical usage patterns.
> I disagree with "don't use this in projects you intend to maintain" as across-the-board advice
Backdrop-filter is... fine. Using masks, animations, and backdrop filter, and gradients, especially for fine details like edges, are just asking for trouble.
Browsers are incredibly complicated, and rendering engines have lots of edge cases, broken features, slight incompatibility issues some of which vary by hardware/os/enabled-flags.
I’m at the point in my career where if it’s an internal project, zero shame for Bootstrap and JQuery. If that’s what floats your boat, do it. It’s simple, well understood, functional.
This is the webdev equivalent of the inside of a Mac being tidy and attractive (black PCBs!). Sure, it doesn't matter, but if you want to build a brand based on attention to details then these are exactly the kinds of details you need to consider.
Exactly what I was going to say. Attention to detail is noticed by people, to the point that they may not necessarily even consciously know why they like one product over another when in reality they just subconsciously are attracted to products that are simply more polished.
Before I read your comment I thought you were referring to blurring in general, then I read the article and... Yeah, it's not worth it for software that needs to be maintained, for a fun hobby project sure do whatever
Yeah, definitely do add those 2 extra properties to make your site look nice, but don't overwork the DOM just because the native CSS blur isn't perfect enough. Guaranteed 0.01% of people would even register this change.
I'd rather open a bug report and hope for the best in this case.
Sure, if you are building an enterprise application, this likely doesn't make any
sense.
But, if you are building something for a consumer audience. Or if you are trying to differentiate yourself by building something beautiful. Then maybe wrap these 100 lines of code in a very specific class name (.fancyGlassFrostedGlass) and call it day?
The recent posts around frosted glass reminded me of an exploration I did a while ago, using perspective and svg filters (feTurbulence and feDisplacementMap) to simulate an actual rough surface.
Chrome & Safari render it differently but interesting, Firefox is skipping it completely … I‘d need to look into it. Anyway, just wanted to share it :)
In case anyone's trying to remember what macos/iOS does with what they call 'vibrancy' - can't find the video directly anymore but they sorta touch on it here (WWDC 2014 , session 220): https://github.com/ASCIIwwdc/wwdc-session-transcripts/blob/b...
"The actual implementation
and blending that we do could
be a Linear Burn, a Color Dodge, PlusD, PlusL."
Microsoft’s Acrylic is tolerably documented too (the concepts, not the exact values): https://learn.microsoft.com/en-us/windows/apps/design/style/.... At the end, especially: “The acrylic recipe: background, blur, exclusion blend, color/tint overlay, noise.”
This was one of the most effective tutorials I've read on HN. Define everything and hold our hands the entire way. I find I'm often frustrated reading tutorials on HN because they are often littered with ambiguous language, undefined labels, and incorrect assumptions on the reader's prior knowledge.
Last time this article came up, I voiced my opinion that instead of a blog post, this should've probably been a bug report either for the browser or the CSS spec itself. Since this got posted again, I went and looked for one and boy did it not disappoint: there's an ongoing ticket that's now been open for eight years [0]. Granted, that ticket and the related spec cover much more than just this behavior, but the underlying issue is the same. If you look through related tickets on e.g. Chromium, you'll see plenty that are closed as won't fix exactly because of this, the spec itself doesn't account for all the use cases.
I added this to https://cppbuilder.com/ which used to use a standard blur for the header background. It's very subtle, especially with the bottom border turned off, but I appreciate the knowledge of it being a 'better', ie a more real effect matching how real-world light or glass works. Feels like doing it right.
Firefox on Mac _may_ have a slight lag scrolling now which Chrome does not show.
Not mentioned in the article (that I saw) is that despite being a background blur it will affect all elements placed in the header, even with z-index higher than the blur, unless you mark them `position: relative;`. I added that style to my nav container.
You're probably right, but I enjoyed the effect as text and graphics slid under the header. Originally I was going to have the header and page different colours.
This is claptrap: "This effect helps us add depth and realism to our projects." -- when was the last time you, dear reader, saw frosted glass? Let's be real: it's because it was in iOS 7, Apple never moved on from that look and feel, and Apple is Apple. (n.b. a winking opinion, and a mild homage to Apple lore, not a genuine rebuke: https://folklore.org/Round_Rects_Are_Everywhere.html)
backdrop-filter: blur() is still annoyingly buggy and inconsistent between browsers. I just ran into this this week - Chrome doesn't supported nested/stacked blurred backgrounds, whereas Firefox does. https://codepen.io/joshhunt/full/GgKZKed
Also ran into odd colour issues in Firefox when combining it also with opacity.
My Samsung s24 ultra chugs at like 10fps or lower when scrolling on this site. Needless to say I won't be taking recommendations from the author, if I can't use their website smoothly on one of the most Powerful phones on the market.
This always bugged me! The whole point of frosted glass is to be smooth and relaxing, but the lack of surrounding pixel data causes the blurred image to make unnatural jumps in brightness and color when just a single row of pixels scrolls into view.
It makes me very happy that someone not only noticed this, but did something about it, and then shared it freely!
I don’t like the `height: 200%`: you might as well be specific about how much extra you need, because an extra 100% might be a lot more than you need, or not enough.
First question: how much more do you need? Per https://drafts.fxtf.org/filter-effects/#funcdef-filter-blur (via MDN blur() docs → link to spec):
> Note: A true Gaussian blur has theoretically infinite extent, but in practice all implementations use a finite-area approximation of a Gaussian blur. At the time of writing (January 2024) all major implementations use the familiar three-pass box blur approximation, which has extent: ((3 * sqrt(2 * π) / 4) * σ).
¾√2π is about 1.88; it’s generally most convenient to just double the radius instead.
So, if you’re going for a 16px blur, add 32px. (The formula would make it 30.079px; so I’d accept 30px and 31px also.)
In the first main demo with code: ditch the `height: 200%`, change the inset to `0 0 -32px 0`, and change the 50% in the mask-image linear-gradient to calc(100% - 32px). (Aside: you can also shorten the gradient definition: linear-gradient(to bottom, black calc(100% - 32px), transparent 0%).) Applying it to later things is left as an exercise to the reader.
The SVG <filter> element is interesting in this rendering size question: it lets you control the rendering area for the filter, via its x, y, width and height attributes. Their defaults are -10%, -10%, 120% and 120%, meaning 10% overdraw on each edge. Unfortunately you can’t really do height="calc(100% + 32px)" which is what you’d want for the equivalent here. Yes, you could definitely do this whole thing in SVG, using the BackgroundImage source—in fact, you can do better, because you can composite that with SourceAlpha, rather than the dodgy mask-image technique you’re limited to in HTML/CSS. Unfortunately I don’t believe any current browsers support BackgroundImage, though I think IE and Opera used to, and Inkscape does.
All this time I thought a 16px gaussian blur meant it faded to 0 at 16px. That explains why I always seem to need to add some extra padding! I never thought to question it! Wow! I can use this right away to fix some stuff, thanks for sharing!
Thanks for the response! It’s always nice to know when some incidental thing you remark on has helped someone. Thinking back, I suppose I struggled with understanding the SVG <feGaussianBlur stdDev> parameter when messing around with complicated filters in Inkscape a few years back, for much the same reasons. And I didn’t actually know the ¾√2π until today, I just knew that a factor of 2 was a little more than enough. I’m glad for the note being attached to the spec, it’s a great note.
Although people often talk of blur radii, it might help to remember it’s a standard deviation. Take the curve in https://en.wikipedia.org/wiki/Gaussian_filter#/media/File:Ga..., and a Gaussian blur is taking so much of each pixel value, most from the closest ones, less from further away, negligible by two standard deviations away, but only asymptotic to zero; hence the “theoretically infinite extent” the spec note mentioned. But the ¾√2π thing will probably be good enough forever.
Author here — yeah, so my goal with 200% was to make the code as comprehensible as possible. My actual glassy header does something quite similar to what you’re suggesting, but that also raises the bar quite a bit for how much CSS you need to know in order to understand this post.
I like making things like this copy/pasteable, rather than NPM-installable, so that more experienced developers can make tweaks like the one you suggest.
Your effort to make these posts consumable by the masses doesn’t go unnoticed. It’s clear you put a great deal of work into them, and the quality you achieve raises the bar in many ways for what to expect when learning about the web. If only all educational materials on MDN could reach these heights.
Honestly, I feel that `bottom: -32px` and `calc(100% - 32px)` might be easier to understand than `height: 200%` and `50%`. (Yeah, for early teaching I might step back from using `inset`.) It does require the one extra concept of calc(), but it’s exact and feels slightly more easily explicable than how 50% of 200% is back to 100%. The fact that the number 32 would be present in both makes it easier to track, whereas the fact that 200% and 50% are inverses is pretty easily overlooked.
How does this compare with this that was posted on HN a few weeks ago?
https://www.tyleo.com/html-glass.html
I’m the author of tyleo.com. I’m happy to see folks innovating and building on the idea. I’m also surprised at how popular this topic is on HN!
Both of these posts add additional tweaks beyond `backdrop-filter: blur()` to enhance glass effects. We use different tweaks so it looks like the techniques in each of our posts is compatible. When I get around to it I’ll update my page to link to this new one.
Perhaps in a few weeks we will get the, “I’ve consolidated all the HTML glass effects on HN and this is what it looks like,” post :)
That one suffers from the effect described in the article, it only considers pixels directly behind the element for blurring. So unlike real glass it can't catch adjacent light.
But it is unique in its own way and has many other good ideas.
These effects are all pretty, but like... there should be some sort of media query for devices that are not that powerful (or their owners simply do not wish to burn through their batteries just to read a website). It gets pretty annoying that my phone slows down to a crawl when someone has these effects on their website. At the same time, simply opting out of the blurring and leaving everything else as-is is not a solution, since that may quickly render a lot of things unreadable.
Absolutely. None of these look good to me. I would rather just have plain text. I wish all of these fancy sites would at least include a plain text / simplified reader mode by default. Front end stuff is getting way too over engineered .
You can do it with negative margins too, https://codepen.io/webstrand/pen/OPLLBZN
Wait is this better than the one in the OP?
This is really interesting. I suspect there may be different reasons to take different approaches depending on surrounding CSS and elements.
A lot of UI work I do is experimenting with different ways to do things to find what’s cleanest for the specific situation.
Small note that the drag UX doesn’t appear to work on iOS.
does "scatter" do anything? doesn't seem so to me on android chrome (pixel 7a)
This is the sort of completely unnecessary details that eat hours of your time and add tons of code and maintenance for something that few-to-none notice.
It's great to experiment, but don't use this in projects that you intend to maintain.
Signed, someone who used to do this a lot.
I think "tons of code and maintenance" is an exaggeration for this effect, once it's done you'll rarely have to come back to it.
Many people value creating and using products with these kinds of details, I disagree with "don't use this in projects you intend to maintain" as across-the-board advice.
> is an exaggeration for this effect
I disagree. Check the changes required to the spacing/sizing. Soon you will need to adjust those values and that.is.maintenance. Multiply this by each detail and soon you have more work than you signed up for. This is usually when someone comes along and wants a rewrite because the codebase is fragile.
If you're using a CSS preprocessor like SCSS or LESS you can just define the height for the toolbar as a variable and then use the mask area for the blur as a multiplier (eg. 1.88) of that variable. In general for making things easy.to.maintain it's better to not build project-wide stylesheets with raw CSS.
You don't even need a preprocessor for that with var() and calc(). It's perfectly possible to write clear and easily maintainable raw CSS nowadays.
It's not universally safe to use CSS nesting yet. Without nesting support, writing raw CSS is like raw-dogging a sex-trafficked Vietnamese prostitute from Malaysia. Sure, it will probably work, but if your goal is zero maintenance then you're ignoring the post-exposure prophylaxsis and antibiotic regimens necessary for typical usage patterns.
Why would you need to adjust any spacing/sizing values for for the blur? There’s not much of anything to adjust.
Maybe just use CSS vars from the start? Doesn’t look like you really need to change anything but the containing element though.
> I disagree with "don't use this in projects you intend to maintain" as across-the-board advice
Backdrop-filter is... fine. Using masks, animations, and backdrop filter, and gradients, especially for fine details like edges, are just asking for trouble.
Browsers are incredibly complicated, and rendering engines have lots of edge cases, broken features, slight incompatibility issues some of which vary by hardware/os/enabled-flags.
IME, this would definitely not be worth it.
I’m at the point in my career where if it’s an internal project, zero shame for Bootstrap and JQuery. If that’s what floats your boat, do it. It’s simple, well understood, functional.
This is the webdev equivalent of the inside of a Mac being tidy and attractive (black PCBs!). Sure, it doesn't matter, but if you want to build a brand based on attention to details then these are exactly the kinds of details you need to consider.
Exactly what I was going to say. Attention to detail is noticed by people, to the point that they may not necessarily even consciously know why they like one product over another when in reality they just subconsciously are attracted to products that are simply more polished.
Before I read your comment I thought you were referring to blurring in general, then I read the article and... Yeah, it's not worth it for software that needs to be maintained, for a fun hobby project sure do whatever
Yeah, definitely do add those 2 extra properties to make your site look nice, but don't overwork the DOM just because the native CSS blur isn't perfect enough. Guaranteed 0.01% of people would even register this change.
I'd rather open a bug report and hope for the best in this case.
It really depends on the use case. Right?
Sure, if you are building an enterprise application, this likely doesn't make any sense.
But, if you are building something for a consumer audience. Or if you are trying to differentiate yourself by building something beautiful. Then maybe wrap these 100 lines of code in a very specific class name (.fancyGlassFrostedGlass) and call it day?
I'm not a UX person so I'd rather use something already made that looks good.
The recent posts around frosted glass reminded me of an exploration I did a while ago, using perspective and svg filters (feTurbulence and feDisplacementMap) to simulate an actual rough surface.
https://sg5omz.csb.app/
Chrome & Safari render it differently but interesting, Firefox is skipping it completely … I‘d need to look into it. Anyway, just wanted to share it :)
The technique is interesting, but every time I see this effect, I can't help but feel like 2010 is calling and wants its UI design back.
Looking at most "modern" UI design, I want to go back to 2010.
Windows Vista introduced this and released in 2007
Brushed metal for me, thanks.
In case anyone's trying to remember what macos/iOS does with what they call 'vibrancy' - can't find the video directly anymore but they sorta touch on it here (WWDC 2014 , session 220): https://github.com/ASCIIwwdc/wwdc-session-transcripts/blob/b... "The actual implementation and blending that we do could be a Linear Burn, a Color Dodge, PlusD, PlusL."
Microsoft’s Acrylic is tolerably documented too (the concepts, not the exact values): https://learn.microsoft.com/en-us/windows/apps/design/style/.... At the end, especially: “The acrylic recipe: background, blur, exclusion blend, color/tint overlay, noise.”
This was one of the most effective tutorials I've read on HN. Define everything and hold our hands the entire way. I find I'm often frustrated reading tutorials on HN because they are often littered with ambiguous language, undefined labels, and incorrect assumptions on the reader's prior knowledge.
Last time this article came up, I voiced my opinion that instead of a blog post, this should've probably been a bug report either for the browser or the CSS spec itself. Since this got posted again, I went and looked for one and boy did it not disappoint: there's an ongoing ticket that's now been open for eight years [0]. Granted, that ticket and the related spec cover much more than just this behavior, but the underlying issue is the same. If you look through related tickets on e.g. Chromium, you'll see plenty that are closed as won't fix exactly because of this, the spec itself doesn't account for all the use cases.
[0] https://github.com/w3c/fxtf-drafts/issues/53
Very clever and it does result in a nice effect. I do have to say that I am a fan of this glassmorphism trend.
I added this to https://cppbuilder.com/ which used to use a standard blur for the header background. It's very subtle, especially with the bottom border turned off, but I appreciate the knowledge of it being a 'better', ie a more real effect matching how real-world light or glass works. Feels like doing it right.
Firefox on Mac _may_ have a slight lag scrolling now which Chrome does not show.
Not mentioned in the article (that I saw) is that despite being a background blur it will affect all elements placed in the header, even with z-index higher than the blur, unless you mark them `position: relative;`. I added that style to my nav container.
Isn't it a bit unnecessary to add blur when the website is almost completely black? Maybe put some screenshots on the page.
You're probably right, but I enjoyed the effect as text and graphics slid under the header. Originally I was going to have the header and page different colours.
I may add more graphics soon!
The scrolling lag also makes it unsuable on Firefox mobile, my s24 ultra chugs hard on the top part of the website...
Thanks. I reverted the code. A simple blur-behind is significantly faster.
This is claptrap: "This effect helps us add depth and realism to our projects." -- when was the last time you, dear reader, saw frosted glass? Let's be real: it's because it was in iOS 7, Apple never moved on from that look and feel, and Apple is Apple. (n.b. a winking opinion, and a mild homage to Apple lore, not a genuine rebuke: https://folklore.org/Round_Rects_Are_Everywhere.html)
Lots of sites these days are using that frosted glass effect, I recall seeing it on the Linear site recently.
backdrop-filter: blur() is still annoyingly buggy and inconsistent between browsers. I just ran into this this week - Chrome doesn't supported nested/stacked blurred backgrounds, whereas Firefox does. https://codepen.io/joshhunt/full/GgKZKed
Also ran into odd colour issues in Firefox when combining it also with opacity.
this effect is nextlevel, i use it for almost all my personal projects. i have created a library for generating frosted glass effect.
https://github.com/JP1016/react-icon-blur
My Samsung s24 ultra chugs at like 10fps or lower when scrolling on this site. Needless to say I won't be taking recommendations from the author, if I can't use their website smoothly on one of the most Powerful phones on the market.
Interesting. This page is easily max framerate on my Pixel 4a, which I'd expect since the effects should be hardware accelerated fairly easily...
Fellow 4a user (best small phone ever). It's perfectly fine for me too.
What browser are you using? My phone is a fair bit older and downmarket than that and has no issues.
> Application error: a client-side exception has occurred (see the browser console for more information).
A bit too "next-level" for my iPad it seems.
I like the fonts used on this blog!
Same! The cursive font is Cartograph CF.
I thought at first it may have been (one of the) Playwrite fonts.
See https://fonts.google.com/?query=playwrite
How did you come to that conclusion? I inspected the bold cursive text, and Firefox dev tools tell me it's "Sriracha".
https://fonts.google.com/specimen/Sriracha?query=Sriracha
I used Chrome devtools! Computed style is:
Same result in Firefox for me. MacOS Sequoia.The tutorial itself is next level with stunning interactive visual story telling.
All of Josh's tutorials are like this. Check out some of his others!
love this post just for the example of filter: hue-rotate(0deg); That's one I've never seen before!
Josh your work is amazing
Beautiful