CSS: Weekly Summary (December 08-14, 2025)

Key trends, opinions and insights from personal blogs

I would describe this week’s CSS chatter as the sort of late-night garage tinkering you do when the shop is empty and the radio’s playing low. There’s a warm, practical mood across the posts — people fiddling with themes, building tiny components that actually work, and watching new browser features move from wishful thinking to “oh, it’s in Chrome now”. To me, it feels like being at a small meetup after the main conference has ended: fewer suits, more hands-on tools laid out on the bench.

Slow tinkering and the joy of small projects

Robin Rendle wrote on 12/08/2025 about the pleasure of messing around with sites during the quiet patch of the year. The post didn’t hit you with big takeaways. Instead it sat there, comfortable, like someone saying “I rebuilt this little thing for fun.” It’s plain: the joy comes from trying things out without pressure, sketching without a client breathing down your neck. I’d say this is the tone behind a lot of the smaller, practical posts this week — less sprint, more pottering about.

This kind of writing matters. It’s not a how-to with ten steps. It’s more like: here’s the kettle, I tried a new tea, it surprised me. You get hints of what worked and what didn’t, not polished marketing copy. If you’re in the mood to poke at your site over a weekend evening, this is the encouragement you didn’t know you needed.

Dark modes — two takes on a classic problem

There were two posts on dark mode that echoed around each other. Tom MacWright (12/09/2025) and Simon Willison (12/10/2025) both implemented dark themes, but they came at it from slightly different angles.

Tom’s approach is neat in a pragmatic way. He built a theme selector that runs largely without JavaScript. The switch is a form. Preferences live in cookies. A tiny Netlify function mediates the change so the server can respect the user choice during the initial render. The result is fast and accessible, and it avoids the jumpy flash-of-wrong-theme that often haunts simpler implementations. He admits the trickiness around caching and UI niceties — which, frankly, is where most theme switches start to feel real and messy.

Simon’s write-up reads like someone who wanted an elegant demo. He used Claude Code for web and leaned on media queries plus localStorage for remembering preferences. He even made a little animated GIF to show the toggling. It’s more demo-ish, less server-minded. I’d say his post is the kind you skim for the clever bits you can pinch for your mini project.

So you’ve got two sensible recipes: one that cares about first-render and server-side context (Tom), and another that’s quick, client-first, and demo-friendly (Simon). They don’t contradict — they complement. One is like making a full pot of tea to share with guests, the other is a single mug for yourself. Both keep the tea warm.

There are some recurring headaches though. How do you avoid double work between server and client? Where do you store the preference so it’s respected quickly? How do you keep accessibility intact while preventing flash-of-unstyled-theme? Tom hits these points head-on; Simon gives the flavor and the visuals. If you’ve wrestled with theme toggles, you’ll nod along.

CSS-only components: the switch that doesn’t need JS

On 12/10/2025, Chris Ferdinandi published a methodical, step-by-step guide to building a toggle switch in pure HTML+CSS. He uses role="switch" for accessibility, CSS variables for theming, pseudo-elements for the knob, and transitions for the movement. Nothing exotic, but done right.

I like this kind of post because it’s unapologetically practical. He talks about when a CSS-only switch is appropriate and when it’s not. That’s important. There’s a place for CSS-only widgets — simple toggles, visual cues — and there’s a place for JS when state must be wired up to APIs or complex logic.

To me, a CSS-only switch is like a rented bike in the park: easy, fun, and gets you where you want for a short trip. But don’t expect it to haul your groceries. Chris pokes at accessibility too, which a lot of toy examples forget. He uses semantic roles and mentions keyboard focus. If you care about real-world use — not just pretty pixels — this is a small, useful blueprint.

There’s also a mild lesson here about restraint. You can do a lot with CSS variables and pseudo-elements. But sometimes you’re better off adding the smallest bit of JavaScript. Chris doesn’t preach either way; he offers trade-offs, which is refreshing.

Tailwind and the messy reality of content you don’t control

Two posts lean into Tailwind problems and solutions, but in different parts of the stack.

Christian Ekrem (12/11/2025) wrote about using Tailwind’s arbitrary variants to target child elements. The main point: sometimes you need to style markup you don’t author directly — think CMS blobs or third-party widgets. In those cases, writing extra CSS files feels wrong if you’re committed to utility-first. Arbitrary variants let you write selectors inside class names — so you can do things like style direct children or nested tags without leaving the markup.

It’s a little bit like sneaking seasoning into a ready-made meal. You can’t change the main dish, but with a pinch of salt here and a squeeze of lemon there, you make it palatable. Christian gives examples for common patterns and argues for keeping styles close to the markup where possible. That colocation thing keeps things readable when you come back in three months and wonder why the page looks like it does.

Meanwhile, David (12/11/2025) had a different angle: integrating Tailwind into a Melange project with dune. This was more of a build-tool walkthrough — prerequisites, dune rules, dependency sealing, production minification. It’s the kind of post you skim on a train if you’re actually about to set up that stack.

Put the two together and you see a pattern: Tailwind is still the utility Swiss Army knife, but the edges — build tooling, content you don’t control — need glue. Christian offers the glue for the markup problem. David gives the glue for the build problem. I’d say they both assume you like Tailwind’s ergonomics and want to keep using it even when things aren’t ideal.

There’s also a tension you’ll notice: utility classes embedded with arbitrary selectors can get clever, but clever often becomes cryptic. It’s like using a pocketknife to fix an engine; it works, but future-you may curse past-you. Christian’s examples are helpful because they show patterns, not just one-off hacks.

Tools, LLMs, and tiny HTML utilities

Simon Willison appears twice this week. The second post (12/10/2025) is less about CSS per se and more about patterns for building small HTML tools. He talks about simplicity, self-hosting, using CDNs and localStorage, and even mentions using LLMs to help development. It’s pragmatic and slightly experimental.

What struck me is how much this ties into the CSS conversation: small, self-contained tools that are easy to drop into a page rely on predictable CSS. If you build a tiny widget, you want it to be robust in unknown contexts. Simon’s tips for debugging, for using CORS-enabled APIs, and for shipping minimal HTML+CSS+JS maps directly to the need for CSS patterns that don’t blow up when injected into a CMS.

There’s a ‘less-is-more’ thread here. Keep CSS small and scoped where possible. Provide sane defaults. Use variables for theming. Make your tiny tool work in as many places as possible. These are the pragmatic survival skills of a front-end tinkerer.

Scroll-triggered animations: the browser takes more control

This is the headline-grabber: Bramus (12/12/2025) wrote about scroll-triggered animations coming to Chrome 145. This is more than a convenience; it’s a shift. Instead of wiring up scroll events or using IntersectionObserver hacks, we’ll be able to define animations that run based on scroll offsets and ranges in pure CSS.

That’s big. It’s like the city council finally deciding to add traffic lights to an intersection you’ve been manually yielding at for years. You could do it before — you had stop signs and an unofficial system — but now the browser can handle timing and ranges, and do so with better performance.

Bramus provides demos and a visualiser for trigger ranges. The feature also moves some of the timing logic back into stylesheets. That’s both liberating and slightly worrisome if you like keeping logic in JS. But for designers and devs who want richer, smoother interactions without complex code, this is a welcome change.

Expect interesting UX patterns. Time-based scroll animations open doors for storytelling and micro-interactions that feel tied to the page’s rhythm. But they also create room for overuse. It’s easy to make a page feel like an animated souvenir shop if you’re not careful. I’d say: try it on one section, then leave the rest of the place alone.

Recurring threads and small disagreements

Across these posts are a few repeating beats. I’ll call them out because they matter when you’re deciding how to work.

  • Theme management: cookie vs localStorage vs server. Tom pushes cookies + server-aware approach. Simon leans client-first with localStorage. Which is right? Depends on whether you care about first-render correctness or demo simplicity. And caching complicates the server story, as Tom admitted. It’s not a theological divide — it’s an operational choice.

  • CSS-only vs JS: Chris makes a case for CSS-only when it’s appropriate. Simon’s tools and Tom’s theme selector show that sometimes a bit of server logic or client logic is the correct tool. These are trade-offs. CSS is simpler and faster for many UI bits, but stateful interactions often need code.

  • Utility-first pros and cons: Tailwind keeps showing up. Christian suggests neat patterns to handle messy content. David shows how to glue Tailwind into other build systems. The tension: utilities are fast, but clever hacks to target children can be cryptic. Keep a hand on the wheel.

  • Browser features landing in CSS: Bramus’ post is a reminder that browsers are still weaponizing CSS with new primitives. When the browser gives you an animation API, it’s often worth using for performance reasons. But keep your restraint — more power, more responsibility.

There aren’t full-on arguments here. More like people solving slightly different problems. If anything, they mostly agree that small, maintainable solutions beat clever, brittle hacks.

Little practical takeaways — the things you can try this week

If you want a shopping list from these posts, here’s the stuff that feels worth experimenting with:

  • Try a CSS-only toggle for a simple setting. Use role="switch" and CSS variables. It’s quick and accessible if you follow Chris’ patterns.
  • If you need theme preference respected on first render, think about a cookie + server-aware approach. Tom’s Netlify function idea is an interesting middle ground that prevents the flash-of-wrong-theme.
  • For quick demos, localStorage plus media queries is fine. Simon’s demo GIFs show how pretty and convincing a client-only approach can be.
  • If you use Tailwind but deal with CMS content, look at arbitrary variants for targeting children. Christian’s examples are a good starting point. But document those usages — future-you will thank you.
  • If you build with unusual stacks (Melange + dune), read David’s step-by-step. It’s practical and saved me some head-scratching.
  • Play with scroll-triggered animations in Chrome Canary or a build that supports them. Bramus’ visualiser is an easy way to see what the new API actually feels like in practice.

These are small experiments. They won’t remake your whole architecture, but they’ll give you pockets of delight and fewer headaches.

A few side thoughts and small tangents

I keep thinking about how this week’s posts are all about boundaries. Boundaries between server and client. Between CSS and JS. Between markup you control and markup you don't. Between design intention and browser implementation. You see people nudging those boundaries, not tearing them down.

There’s another tangent: documentation and discoverability. Some of the happiest moments in these posts are the little code snippets and visual demos. A tiny GIF or a short demo often says more than fifty paragraphs of explanation. Maybe we should spend more time shipping small, runnable examples instead of long essays. That’s a weird echo of the ‘small tools’ ethos Simon mentions.

Also, cultural note: I’ll say something slightly cheeky — the tone of these writers is less like a boardroom and more like your mate at the pub telling you about a neat trick they found. That helps. It lowers the bar for trying stuff. Feels like a cuppa and a chat rather than a corporate webinar. Maybe that’s the best way to learn CSS: messy, friendly, sometimes contradictory, and often useful.

What I’d like to see next week

A few things I'd happily read more about:

  • More real-world examples of server-aware theme handling in production. Tom’s initial notes were great, but how do teams handle cache invalidation at scale?
  • Accessibility audit write-ups of CSS-only widgets. Chris’ switch was solid — but show me a case where keyboard users caught a bug and how it was fixed.
  • Patterns for documenting arbitrary Tailwind selectors. Christian’s patterns are useful, but we need conventions for keeping them understandable.
  • More demos of scroll-triggered animations used sparingly and well. Show me a case where it actually improved comprehension or engagement rather than just adding sparkle.

Yes, nitpicky. But these are the small gaps that make a difference when you go from tinkering to shipping.

If you want to follow up, dive into the individual posts. Each one is short enough to read in a quiet half-hour and useful enough that you’ll nick at least one idea. The links to the authors will point you to the original detail, which is where the actual code lives and where the little caveats are hiding.

Anyway, enough rambling. The week felt practical, hands-on, and refreshingly human. It’s the sort of reading that makes you want to open your editor and try something silly, then tidy it up, then maybe ship it. Like repairing a bike chain in the dark — you get greasy, but you can ride home afterwards.