Chris’ Corner: Can Has Blurs, Filters, and Masks

You’ve seen CSS’ new :has() selector right?

There are all these “basic” use cases that leave me smiling because the solutions of the past were inelegant at best, and now are easy and satisfying. Here’s one:

  1. You want margin below your <h2>
  2. … unless there is a <time> right below it, then no margin
  3. … but put the margin below the <time> instead.

One approach to this with :has() is just a few lines and reads very clearly to me:

h2 {
  margin-block-end: 1.2rem;
  &:has(+ time) {
    margin-block-end: 0;
  }
  &:has(+ time) + time {
    margin-block-end: 1.2rem;
  }
}
Demo

But as I mentioned, that’s a “basic” use case. The power of :has() is very deep, as it allows for inspection from any DOM element down the tree, then moving as far back up as needed. It’s a bit hard to wrap my mind around that sometimes. Like Jim Neilsen said:

I feel like lots of people have their own little oh yeah! moments with this CSS feature. Michelle Barker blogged a few of them, including an interesting combination with the :target selector. Does a certain “have” an element that is targetted? Yes? Animate the grid to reveal an otherwise hidden area:

Poking around my own code bases, I can see it starting to sprinkle in. It’s interested to see when it comes to unknown data coming into templates. Here’s a JSX example:

<div class="things">
  {things.map(thing => {
    return(
      <div class="thing" key={thing.id}>
        <h3 data-category={thing.category}>{thing.name}</h3>
        {thing.text}
      </div>
    );
  })
</div>

Here I’ve spat out a total arbitrary list of “things”. I found it most useful to have the data-category attribute on the header, as direct styling with that was useful. But what if the parent needs styling based on that? Easy:

.thing:has([data-category="widget"]) {
   background: yellow;
}

More, what if the entire group needs a special style? And if it does, make all the headers smaller?

.things:has([data-category="widget"]) h3 {
  font-size: 80%;
}

Go down, then back up!

I’m even very-mindblown-y on the idea that quantity queries are now easy. Does this list have at least 11 items in it? Yes? Then do something:

ol:has(li:nth-child(11)) {
  color: red;
}

Get out of dodge.


We’ve had blend modes in CSS for a while. You use mix-blend-mode when you’re trying to blend an elements content with it’s background. You use background-blend-mode when layering backgrounds and wanting to blend those.

It still strikes me as a surprisingly cool thing we have access to directly in CSS. And it’s niche enough that when I see it used, it’s usually a pleasant surprise.

Brad Woods has an awesome article showing off how they work. Interactive examples really does blending justice here.

Those look dramatic, but blending can be rather subtle. Brad has all sorts of other examples like blending gradients over images, blending textures, blending patterns, that all end up quite nice and the fact that they are programmatic just feels cool and powerful.

Koding Kitty has a similarly good explanation page, specifically using provided Tailwind class names to do the blending over top a single-color icon. I always thought Robin did a good job on the old CSS-Tricks page as well.

You know what I always think of with blending, though? It’s not a CSS property that you just learn and then you know it. All you can learn is the general category of what it can do and the circumstances it might be useful. Then, you have to guess and test your way to a good outcome. One might argue a lot of CSS is that way, but I feel like blending is particularly this way.


Speaking of excellent interactive tutorials!

Artur Bień is all over it in Blur Vignette effect in CSS.

How would you pull of this in CSS?

Quickly, it’s to layer two copies of the image, blur the top one, and use a mask to only reveal the edges of the blurred version. The hard part is crafting the mask. Artur does it with 6 layered gradients which gets the effect just right.

Don’t miss the Windows 98-ish interactive demo at the bottom which lets you totally control different aspects of the effect.

Artur is the master of getting these kind of details right. Check out this quick screencast video he tweeted about getting a “glass overlay” effect just right. I’d be like “that’s what backdrop-filter is for!” That’s in there, but it doesn’t account for the, as Artur puts it:

In reality we see glass objects reflecting light even before they are placed directly between our eyes and the light source.


Well we’ve touched on filters, blending, and masking, I suppose it’s not out of line to hit shadows too. I enjoyed Preethi Sam’s thinking differently in A Few Interesting Ways To Use CSS Shadows For More Than Depth. Shadows can have properties that make them quite un-shadow-like, like having zero blur, being inside an element, being whatever color you want, and even being layered. Like how good are these hovers?

Nothing wrong with using shadows for shadows though! I ran across boxshadows.xyz the other day and it’s a pretty nice tool for doing layered shadows that have a better depth effect than any one shadow alone can do.

I just love that sort of look. It’s intense looking in that exact example, but a slightly more subtle version with a bigger shadow behind and a slight lighting effect inset on top is just a really juicy effect that works well on the web.

You know what else is hot right now? Blurred and colored blobs as backgrounds. As ever, you can make those as images and use a background-image (I’ve seen Figma plugins like this and this). But it’s fun to do programmatically of course as you can color them as needed, make different sizes, and even animate them.

Andrew Walpole took a crack at it with Glowing Blurred Backgrounds with CSS. The filter property does the heavy lifting getting the blurryness going, but getting the shapes together in which to blur is very clever.

Below the (left) turns to the (right).