Lowering the specificity of multiple rules at once - Manuel Matuzovic
This is clever, and seems obvious in hindsight: use an anonymous @layer for your CSS reset rules!
This is clever, and seems obvious in hindsight: use an anonymous @layer for your CSS reset rules!
I’m not the only one who’s amazed by how much you can do with just a little CSS these days.
I was messing about with some images on a website recently and while I was happy enough with the arrangement on large screens, I thought it would be better to have the images in a kind of carousel on smaller screens—a swipable gallery.
My old brain immediately thought this would be fairly complicated to do, but actually it’s ludicrously straightforward. Just stick this bit of CSS on the containing element inside a media query (or better yet, a container query):
display: flex;
overflow-x: auto;
That’s it.
Oh, and you can swap out overflow-x for overflow-inline if, like me, you’re a fan of logical properties. But support for that only just landed in Safari so I’d probably wait a little while before removing the old syntax.
Here’s an example using pictures of some of the lovely people who will be speaking at Web Day Out:
While you’re at it, add this:
overscroll-behavior-inline: contain;
Thats prevents the user accidentally triggering a backwards/forwards navigation when they’re swiping.
You could add some more little niceties like this, but you don’t have to:
scroll-snap-type: inline mandatory;
scroll-behavior: smooth;
And maybe this on the individual items:
scroll-snap-align: center;
You could progressively enhance even more with the new pseudo-elements like ::scroll-button() and ::scroll-marker for Chromium browsers.
Apart from that last bit, none of this is particularly new or groundbreaking. But it was a pleasant reminder for me that interactions that used to be complicated to implement are now very straightforward indeed.
Here’s another example that Ana Tudor brought up yesterday:
You have a
sectionwith apon the left & animgon the right. How do you make theimgheight always be determined by thepwith the tiniest bit of CSS? 😼No changing the HTML structure in any way, no pseudos, no background declarations, no JS. Just a tiny bit of #CSS.
Old me would’ve said it can’t be done. But with a little bit of investigating, I found a nice straightforward solution:
section > img {
contain: size;
place-self: stretch;
object-fit: cover;
}
That’ll work whether the section has its display set to flex or grid.
There’s something very, very satisfying in finding a simple solution to something you thought would be complicated.
Honestly, I feel like web developers are constantly being gaslit into thinking that complex over-engineered solutions are the only option. When the discourse is being dominated by people invested in frameworks and libraries, all our default thinking will involve frameworks and libraries. That’s not good for users, and I don’t think it’s good for us either.
Of course, the trick is knowing that the simpler solution exists. The information probably isn’t going to fall in your lap—especially when the discourse is dominated by overly-complex JavaScript.
So get yourself a ticket for Web Day Out. It’s on Thursday, March 12th, 2026 right here in Brighton.
I guarantee you’ll hear about some magnificent techniques that will allow you to rip out plenty of complex code in favour of letting the browser do the work.
While I’ve been listening to Hounds Of Love, I’ve also been reading Orbital by Samantha Harvey.
Here’s a passage from an early chapter as the crew of the International Space Station watch a typhoon forming:
How wired and wakeful the earth seems suddenly. It’s not one of the regular typhoons that haphazardly assault these parts of the world, they agree. They can’t see it all, but it’s bigger than projections had previously thought, and moving faster. They send their images, the latitudes and longitudes. They are like fortune tellers, the crew. Fortune tellers who can see and tell the future but do nothing to change or stop it. Soon their orbit will descend away to the east and south and no matter how they crane their necks backward at the earth-viewing windows the typhoon will roll out of sight and their vigil will end and darkness will hit them at speed.
They have no power – they have only their cameras and a privileged anxious view of its building magnificence. They watch it come.
The penultimate track on Hounds Of Love is the magnificent Hello Earth with its eerie Georgian chant for a chorus, and magnificent uilleann piping from the late great Liam Óg O’Flynn on the bridge. It too features a narrator watching from space:
Watching storms
Start to form
Over America.
Can’t do anything.
Just watch them swing
With the wind
Out to sea.All you sailors, (“Get out of the waves! Get out of the water!”)
All life-savers, (“Get out of the waves! Get out of the water!”)
All you cruisers, (“Get out of the waves! Get out of the water!”)
All you fishermen,
Head for home.
Matching the song to the book feels like pairing a fine wine with a delicious morsel.
- Building HTML pages is easy
- Pure HTML is evergreen
- Bloated web pages are too slow
- I can host it anywhere, often for free
- Accessibility and SEO benefits are automatic
- It won’t need security patches
- There are no build steps
It seems like the misguided perception of needing to use complex tools and frameworks to build a website comes from a thinking that web browsers are inherently limited. When, in fact, browsers have evolved to a tremendous degree
A fun new font from Jason:
Citywide is a sans serif family inspired by mid-1900s bus and train destination roll signs.
About halfway through this talk transcript, Aaron starts dropping a barrage of truth bombs:
I understand the web, whose distinguishing characteristic is asynchronous recall on a global scale, as the technology which makes revisiting possible in a way that has genuinely never existed before the web.
What the web has made possible are the economics of keeping something, something which has not enjoyed “hockey stick growth”, around long enough for people to warm up to it. Or to survive long past the moment when people may have grown tired of it.
If your goal is to build something which is designed to flip inside of ten years, like many things in the private sector, that may not seem like a very compelling argument.
If, however, your goal is to build something to match the longevity of the cultural heritage sector, to meet the goal of fostering revisiting, or for novel ideas to outlast the reluctance of the present and to do so at a global scale, or really any scale larger than shouting distance, then I will challenge you to find a better vehicle for doing so than the internet, and the web in particular.
CSS wants you to build a system with it. It wants styles to build up, not flatten down.
Truth!
This makes sense:
Wrap everything in your CSS reset with a
@layerrule.When you place any styles inside a layer, these styles automatically have lower priority compared to all unlayered styles on the page. Think of it like an
!unimportantblock. You don’t need to worry about specificity or order of stylesheets at all.
I’ve been going buildless—or as Brad crudely puts it, raw-dogging websites on a few projects recently. Not just obviously simple things like Clearleft’s Browser Support page, but sites like:
They also have 0 dependencies.
Funnily enough, many build tools advertise their superior “Developer Experience” (DX). For my money, there’s no better DX than shipping code straight to the browser and not having to worry about some cryptic
node_moduleserror in between.
Making websites without a build step is a gift to your future self. When you open that project six months or a year or two years later, there’ll be no faffing about with npm updates, installs, or vulnerabilities.
Need to edit the CSS? You edit the CSS. Need to change the markup? You change the markup.
It’s remarkably freeing. It’s also very, very performant.
If you’re thinking that your next project couldn’t possibly be made without a build step, let me tell you about a phrase I first heard in the indie web community: “Manual ‘till it hurts”. It’s basically a two-step process:
It’s remarkable how often you never reach step two.
I’m not saying premature optimisation is the root of all evil. I’m just saying it’s premature.
Start simple. Get more complex if and when you need to.
You might never need to.
Perhaps the tide is finally turning against complex web frameworks.
Number one:
Do things in the most straightforward way possible. It’s easy to fall into the trap of clever solutions, or clever applications of technology, or overbuilding something because you’re anticipating the future. Don’t do it. You will hate yourself for it later when you have to maintain it.
Can we please stop adding complexity to our systems just so we can do it in JavaScript? If you can do it without JavaScript, you probably should. Tools shouldn’t add complexity.
You don’t need a framework to render static content to the end user. Stop creating complex solutions to simple problems.
It would be much harder for a 15-year-old today to View Source and understand the code structure that built the website they’re on. Every site is layered with analytics, code snippets, javascript plugins, CMS data, and more.
This is why the simplicity of HTML and CSS now feels like a radical act. To build a website with just these tools is a small protest against platform capitalism: a way to assert sustainability, independence, longevity.
The bar to overriding browser defaults should be way higher than it is.
Amen!
When I wrote about my time in Amsterdam last week, I mentioned the task that the students were given:
They’re given a PDF inheritance-tax form and told to convert it for the web.
Rich had a question about that:
I’m curious to know if they had the opportunity to optimise the user experience of the form for an online environment, eg. splitting it up into a sequence of questions, using progressive disclosure, branching based on inputs, etc?
The answer is yes, very much so. Progressive disclosure was a very clear opportunity for enhancement.
You know the kind of paper form where it says “If you answered no to this, then skip ahead to that”? On the web, we can do the skipping automatically. Or to put it another way, we can display a section of the form only when the user has ticked the appropriate box.
This is a classic example of progressive disclosure:
information is revealed when it becomes relevant to the current task.
But what should the mechanism be?
This is an interaction design pattern so JavaScript seems the best choice. JavaScript is for behaviour.
On the other hand, you can do this in CSS using the :checked pseudo-class. And the principle of least power suggests using the least powerful language suitable for a given task.
I’m torn on this. I’m not sure if there’s a correct answer. I’d probably lean towards JavaScript just because it’s then possible to dynamically update ARIA attributes like aria-expanded—very handy in combination with aria-controls. But using CSS also seems perfectly reasonable to me.
It was interesting to see which students went down the JavaScript route and which ones used CSS.
It used to be that using the :checked pseudo-class involved an adjacent sibling selector, like this:
input.disclosure-switch:checked ~ .disclosure-content {
display: block;
}
That meant your markup had to follow a specific pattern where the elements needed to be siblings:
<div class="disclosure-container">
<input type="checkbox" class="disclosure-switch">
<div class="disclosure-content">
...
</div>
</div>
But none of the students were doing that. They were all using :has(). That meant that their selector could be much more robust. Even if the nesting of their markup changes, the CSS will still work. Something like this:
.disclosure-container:has(.disclosure-switch:checked) .disclosure-content
That will target the .disclosure-content element anywhere inside the same .disclosure-container that has the .disclosure-switch. Much better! (Ignore these class names by the way—I’m just making them up to illustrate the idea.)
But just about every student ended up with something like this in their style sheets:
.disclosure-content {
display: none;
}
.disclosure-container:has(.disclosure-switch:checked) .disclosure-content {
display: block;
}
That gets my spidey-senses tingling. It doesn’t smell right to me. Here’s why…
The simpler selector is doing the more destructive action: hiding content. There’s a reliance on the more complex selector to display content.
If a browser understands the first ruleset but not the second, that content will be hidden by default.
I know that :has() is very well supported now, but this still makes me nervous. I feel that the more risky action (hiding content) should belong to the more complex selector.
Thanks to the :not() selector, you can reverse the logic of the progressive disclosure:
.disclosure-content {
display: block;
}
.disclosure-container:not(:has(.disclosure-switch:checked)) .disclosure-content {
display: none;
}
Now if a browser understands the first ruleset, but not the second, it’s not so bad. The content remains visible.
When I was explaining this way of thinking to the students, I used an analogy.
Suppose you’re building a physical product that uses electricity. What should happen if there’s a power cut? Like, if you’ve got a building with electric doors, what should happen when the power is cut off? Should the doors be locked by default? Or is it safer to default to unlocked doors?
It’s a bit of a tortured analogy, but it’s one I’ve used in the past when talking about JavaScript on the web. I like to think about JavaScript as being like electricity…
Take an existing product, like say, a toothbrush. Now imagine what you can do when you turbo-charge it with electricity: an electric toothbrush!
But also consider what happens when the electricity fails. Instead of the product becoming useless you want it to revert back to being a regular old toothbrush.
That’s the same mindset I’m encouraging for the progressive disclosure pattern. Make sure that the default state is safe. Then enhance.
I love how straightforward these bits of CSS are—time to rip out some of those old complicated hacks and workarounds!
While some executives in Davos may get excited about its infinite possibilities this week, to a younger consumer AI Art is already ‘a bit cringe’.
I didn’t want to play the game of striving to be seen.
I just wanted to be.