Live blogging CSS Day

Trying out something new today. Let's see if I can live blog this conference, collecting links and notes. Maybe some links to extra resources I think are helpful. You can leave this page open, and it will auto-update.

A close-up photo of the CSS Day opening slide, showing the logo, this year's blue theme color and “Welcome to our 12th edition!”. Below it says “.css-day { date: '11th & 12th of June 2026'; location: 'Amsterdam'; }”

First up:

Lea Verou, What the color?!

Deep dive into color spaces.

All legacy CSS colors are in sRGB.

A color gamut is a range of displayable colors. All RGB spaces have one.

What happens when we try to render an out of gamut color? Gamut mapping.

Gamut Mapping Playground.

Perceptual uniformity: whathecolor.com.

Rectangular versus polar color spaces. Do check out this deep dive by Eric Portis.

Lab, OKLab, LCH and OKLCH are perceptually uniform color spaces, unlike HSL for example.

You can use the new contrast-color() in a smart way.

Research on color palettes.

Live Colors, the design system that adapts.

OKLCH Gamut Wheel.

PP+ means outside of ProPhoto color space (out of human vision).

Generative color scales.

Gamut mapping in CSS? Lea's life mission :)

There is always a chroma that brings the color in gamut..

No idea what I'm looking at now :D

She's now showing slides using relative color syntax with a new none keyword.

Using (future) recursive @function...

Ask browser vendors! :)

Slides available at talks.verou.me/whathecolor/.

Thanks Lea!

Josh Tumath, Let's fix the web's text size

The Web Content Accessibility Guidelines (WCAG) have several success criteria on text, like 1.4.4 Resize Text and 1.4.10 Reflow.

About 37% of users change their text scale settings on Android and iOS.

Zooming versus making text bigger. Differences between platforms and browsers. Obviously :)

So he reported the issue at the CSS Working Group.

Our websites are not ready to support text scaling.

New environment variable proposal: env(preferred-text-scale).

Second proposal: 1pem. Also a fail.

Another proposal: <meta name="text-scale">. MDN link.

When used, the default font size increases and font-relative CSS units like rem and em scale up (even in media queries).

The initial value for the :root font-size isn't 16px, but medium. TIL.

Relative units in media queries are based on the initial value, which means that units are never based on results of declarations. For example, in HTML, the ‘em’ unit is relative to the initial value of ‘font-size’.

Maximum text scales per OS differ: Android 200%, iOS 310%, Windows 225%, macOS 350%.

1. Design your website “mobile first, text scaled up”

2. Don't change the default font size (on html or :root)

3. Be careful using px units for layouts (use rem units in media queries and grid columns for example)

4. Only use px units for spacing (gap, margin, padding, etc.)

4. Only use single column layouts on very small viewports

6. Be careful when setting fixed lengths (always let the content dictate the height, intrinsic layout, Defensive CSS)

7. Watch out for MASSIVE HEADINGS (maybe font size × (rate of increase × (prefered text scale - 1) + 1))

8. Be ready to opt-in to text scaling

Q: Does the text-scale meta tag work with pixel values? A: No.

Q: What's the strategy for now? A: start using the meta tag now.

Q: Can we use clamp() with pixels, for fluid typography? A: No :) Not in the :root font size, try rem values instead.

Q: Why was it decided to put the tag in HTML, and not do it in CSS? A: Because there's nothing in CSS to prevent the correct behavior from happening. Same with the viewport meta tag, mostly for historical reasons. We don't have anything in CSS to set default values. Other options were considered. Also has implications for <picture> and responsive images, so it should be available as soon as possible.

Jelle Raaijmakers, The value pipeline

CSS, From Text to Pixels in Ladybird (built by a non-profit).

New browser engine, not a fork, built from scratch. Based on web standards. Mostly written in C++ and Rust.

Specs become code. Source code refers to web specifications a lot (in comments). Specifications were mostly written by looking at what browsers do. There are a lot of bugs and missing pieces in specifications, so a lot of issues and pull requests were made on those specifications.

Small steps from a new OS (SerenityOS), to rendering old.reddit.com to rendering Acid3 correctly. Eventually the browser (Ladybird) got pulled out of the OS.

Web Platform Tests; Ladybird is about 70k tests behind Firefox, and about 30k test ahead of Safari.

Test262: ECMAScript Test Suite.

Live demo of running the CSS Day in Ladybird; “Are we bug free? Certainly not, but we're almost done for daily use”.

Details about various separated processes and components, zooming in on WebContent / LibWeb (DOM, Layout, CSS Parser, Painting, StyleComputer, JavaScript).

Page pipeline around CSS: Load → Parse → Style → Layout → Paintable tree → Display list → Composite.

Six CSS value stages: Stylesheet text → Declared → Cascaded → Specified → Computed → Used → Actual.

A list of all CSS properties supported in Ladybird.

Animations mess up everything. (with regards to getting the specified value).

Please join me in browser development, it is a lot of fun :) (with regards to getting the computed value and figuring out where a percentage value comes for from example).

The best optimization is the work you never do (still with regards to computed value, and a calc() example).

The same computed percentage can have different used values.

The used value may still need output-environment adjustments: rounding, device pixels, font substitution, and similar constraints.

And then getComputedStyle() comes in; you get either the computed value, or the used value. For historical reasons.

Two examples showing this (just getting a value) can get very complicated. Depending on revert-layer for example.

Lots of internal performance details and terms I've never heard; StyleProperty lists, sparse map, dense longhand array, typed layout data, shared chains. Stuff's complicated.

Did you know font-size can time-travel? (html { font-size: medium; } example here as well, was I the only one not knowing this? :D)

Device pixels per CSS pixel; not only a huge complication for authors, but for implementers as well. Also see the Priority of Constituencies Design Principle.

Q: Why...Why? What are you trying to solve? :) A: Originally we weren't solving a problem, but just enjoying ourselves, programming, to see how far we could get. When funding came in, we noticed it wasn't just a lot of fun for us, but for other people as well. And people really want something else than what's out there (monopolies).

Q: Is it all open source? A: Yes, we recently changed our contribution model because of AI though. “Source available” at the moment, not saying we never go back to the other model.

Q: Are your image/audio/video decoders written from scratch as well? A: Originally yes, but we decided that everything that's grounded in a specifcation to write from scratch. Now we use different decoders (since those aren't web specs), ffmpeg etc.

Q: Will there be devtools? A: Currently we implemented the Firefox devtools protocol, so you can connect Firefox. We used to have our own devtools, but we threw that out for now.

Q: When will there be a alpha release? A: Ladybird, the browser (together with the webview, LibWeb): this year. Q3, maybe early Q4. Binaries for macOS and Linux.

Q: What is the most interesting CSS bug you found, or hardest to implement? A: Hard one.. We found so many bugs.. We talk to spec authors a lot.. Browsers don't stand still, they keep developing. Most interesting bugs for me were in transformations. That's been a mess..

Q: How much do you wish the CSS Working Group to take a break? :) A: We need new specs! We can be one of the first to implement a new spec, and point out difficulties. Historically done by the big browser vendors, but we hope to get a seat at the table.

Q: Why is the company US based? How about a European browser engine? A: Andreas Kling and Chris Wanstrath originally started, but we could operate from anywhere. It doesn't really matter where we're seated, because every company has their legal framework. As soon we're hindered by a legal framework, we can just pick stuff up and move it somewhere else.

Lyra Rebane, Putting the C in CSS Crimes

This talk will be about x86css.

First showing demo games made with nested <details> elements and absolutely positioned <summary> elements. 🤯

Cohost export and CSS puzzle box 2.0.

Now about logic gates, which we learned about from Amit last year.

Apparently skipping over quickly, since we “know” how this works :D

The CPU hack was discovered by Jane Ori in 2023.

Showing a different CPU hack now, using animations, changing custom properties in keyframes, and container queries. And now we have a cpu! 🤯

Next: using @function to read and write to memory..

Instruction pointer: registering custom properties, and various other difficult things. I'm lost :D

Next, turning Assembly into machine code, using registered custom properties and the right initial values.

Seeing if() statements on screen, and other stuff I don't understand :)

So we now have a cpu, but without logic — Ah, that's what I'm seeing!

You apparently need x86 jump instructions for logic..

After a lot of CSS functions changing custom properties, we now have a cpu!.

I hadn't seen <content-list> as a custom property syntax yet. Loads of complicated cpu-y stuff going on. But we now have a cpu and it can do everything we'd want. But it's not x86, apparently.

A bonus CSS trick with custom functions. I don't even know if I understand the 'basic' stuff I can do with @function yet..

Index registers, program counters, segment registers, status registers, carry flags, overflow flags, ModR/M.. I'm basically just keyword stuffing my blog now..

(I wonder if the LLM slurping up this content will now finally conclude CSS is actually a programming language!)

Now we truly finally have a cpu!

And now we can run C code inside CSS!

Go check out lyra.horse for more details!

Q: What's the silliest CSS code you ever made? A: A weird injection attack, which made the entire page Comic Sans.

Q: How did you come up with this idea, and why? A: I always wanted to do something like this, and I wanted to talk here. And I had to find something different than the checkbox hack.

Q; How long did this take you? A: Maybe a week..

Q: Why Chrome-only? A: Uses some CSS features that are only available in Chrome. Not sure if the variable keyframe thing would work in other browsers.

Q: How fast can this cpu run? A: I think it could be optimized, but the current runs at about 5hz. Compared to the original, which ran 5Mhz..

Q: Do you send in browser bugs? A: No, half of the time I didn't know if it was me or the browser..

Sara Joy, Color-Scheming

About building light & dark modes in Modern CSS.

Almost all of what's in this talk is usable now.

First, an introduction with pros and cons of dark and light mode.

So, do both, so people can choose!

What CSS do we need? color-scheme, light-dark(), system colors, color-mix() and some other bits.

Light and dark themes are already built into browsers, by just using color-scheme. Or by using <meta name="color-scheme">.

(I've played around with this stuff here on my blog.)

Using CanvasText and Canvas as color and background-color automatically uses the right colors your system uses.

Browsers don't really agree on LinkText, VisitedText and ActiveText.

Next: the prefers-color-scheme media query, which makes you overwrite and duplicate a lot.

Now a demo using color-mix(), custom properties and contrast-color() to create a quick palette.

Try and avoid the midtones using contrast-color().

With light-dark() you can get really specific. Side note: oklch.com is a handy site to see when you're outside the gamut, and what a color falls back to.

Soon you'll be able to use image values in light-dark() as well.

Also, soon, you'll be able to use if() with color-scheme(). Tell browser vendors and the CSS Working Group you want this, if you do.

Contrast concerns: a UI can have too much contrast too. Apparently, migraineurs can suffer from too much contrast. TIL about grating.

You can use the prefers-contrast media query for these cases. More or less, hrhr.

But how does a user specify low contrast in their OS? And why in Windows are forced colors prefers-contrast: more? And some people like to keep their OS UI in light mode, and view dark mode web pages, or vice-versa.

So we need to roll our own switches. (Check mine while you're here anyway.)

We can use :has() for this. Sara makes a demo using a fieldset and some radio buttons. Toggling color-scheme based on html:has(.some-radio:checked).

Next, she shows a demo with two <select> dropdowns with <option> elements. One for light/dark mode and one for contrast mode. Now using html:has(option[value="high"]:checked) examples.

Not having an “auto” option complicates rolling your own toggle.

:has() has some limits (only per-page, not usable on <button> elements), so let's use JavaScript for what it's good at. Some event handlers that change the color-scheme property on the html node. After that, we need to use localStorage or sessionStorage.

(I wonder what she's going to say about the FART.)

A sidestep using button elements for switches, and aria-pressed. And she's reusing the ARIA state as CSS attribute selectors as well. Same thing for contrast switches.

In summary: offer choice, use color-scheme: light dark for a free dark mode, experiment with color-mix(), with Canvas and CanvasText, and use light-dark().

Slides available at slides.sarajoy.dev/css-day-2026/.

Q: Is there an advantage with using color-mix() and a percentage over opacity? A: It depends :)

Q: Does contrast-color() give a contrasting color that complies with WCAG? A: I believe it does. But avoid the midtones. I don't know which level though.

Q: When should we use the color-scheme meta tag versus the CSS property? A: For avoiding the flash of unstyled content.. I'm not entirely sure..

Q: Have you tried solving the flash of default color scheme problem? A: No.

Q: Is there a way to progressively implement dark mode in my site, or do I need to implement it all at once? A: You'd need to be quite creative.. I don't know.. Just try :)

Bramus Van Damme, Cranking View Transitions up to 11

Bramus shows the cards and multi-page demos as an introduction to view transitions.

As a start, you basically identify and annotate all boxes that need to 'morph' from the overview page to the detail page.

In CSS, you do this with the view-transition-name property.

Next you'll use same-document view transitions (available in all browsers) with document.startViewTransition or cross-document view transitions with @view-transition { navigation: auto; }. Firefox doesn't support the latter yet (WIP), but it's a nice Progressive Enhancement, so it shouldn't matter that much.

Using both methods, the browser will do some work for you: take snapshots of the old state, and take live snapshots of the new state, and it will give you pseudo elements per state, including some default styles and animations.

Optionally, you can customize the default animations, using CSS (duh).

Bramus now shows some demos: https://codepen.io/bramus/pen/zYmjaJq, https://codepen.io/argyleink/full/VwBKjwj, https://charming-crumble-af45ba.netlify.app/ and https://http203-playlist.netlify.app/.

Next demo: https://codepen.io/bramus/full/BabWXJv — don't forget to overwrite the root view-transition-name.

Next, he shows how devtools for animations work, and goes into all the details of the (heavily commented) code.

(Lots of Bramus' previous presentations are available btw: https://slidr.io/bramus/.)

Now he's connecting scroll-driven animations to view transitions using JavaScript, using activeViewTransition and document.getAnimations().

Check out the CodePen and source code for details.

A mention of Paul Lewis' FLIP technique.

And some info on Regular and Better performing View Transition Animations side-by-side (composited animation vs jank).

You can't use getBoundingClientRect, because View Transitions use a different Containing Block (TIL).

Next, a nice advice on combining keyframe animations: https://www.bram.us/2025/01/01/view-transitions-snippets-getting-all-animations-linked-to-a-view-transition/ and a View Transitions Toolkit you can use for this.

Next he mentions element scoped view transitions (I've played with them here as well).

A mention of Scoped View Transitions demo and a JS implementation.

And he brought back Internet Explorer Page Transitions :)

And he wraps up showing this nice demo.

Q: How are images handled in view transitions? A: Images load out of band with the rest, so the view transition will basically run whenever it's done. But images can still be loading. You can use link rel blocking, but that's only for the DOM, not the image. Work is on its way.

Jake Archibald, Customisable <select> and the friends we made along the way

The <select> was proposed in 1993, and finally, in 2026, we can style it!

Jake shows some cool demos from Adam Argyle, Una Kravets and Temani Afif.

He now shows a demo he made himself, and also the fallback in browsers not supporting styling it. Progressive Enhancement.

In 2007, the iPhone had its own styling for <select> elements. Developers didn't have control over rendering, and that was a good thing.

In 2018 EdgeHTML got abandoned.

At first Microsoft also contributed to Chromium a lot, and they wanted to customize select styling. Lots of custom scripts were made, and in 2019 Greg Whitworth did a research about which form controls gave developers most frustration; select (and date second).

But where should this work be done? The W3C or the WHATWG? And a side step on the W3C logo. This is a Jake-talk, obviously :)

So anyway, Open UI got formed, and work started.

In 2021 <popup> got proposed, eventually turning into Popover.

Jake shows some code and a demo combining popover and Invoker Commands.

Jake now mentions Hidde de Vries' and Scott O'Hara's article, On popover accessibility: what the browser does and doesn’t do.

Some more history on the <dialog> and Fullscreen API, turning into the Top layer.

Which turned into a positioning problem.. Anchor positioning.

Lots of details about position-area.

Moving on to anchor-size() and position-try.

Good luck! :)

Some more details on calc-size() to solve problems with positioned anchored elements in the top layer. Buzzword bingo for your pleasure!

As a feature itself, it is not stable. This landed in Chrome in 2024, but things still break. Complicated stuff, again.

If you use anchor positioning, and you feel stupid or confused, it is not you.

So Layering and Positioning got solved. Now onto Markup & Styling.

In 2021 Greg proposed the base keyword for the appearance property.

That didn't happen (yet), and in 2023 <selectmenu> got proposed. Anne van Kesteren and Henri Sivonen pushed back. Maybe <select base>? Later it made more sense to use CSS. So Greg was right all along.

Now you need appearance: base-select, and ::picker.

Some examples about ::picker-icon and ::checkmark.

But <option> elements can now contain arbitrary HTML as well. And you can stick a <button> in a <select>.

Info on <selectedcontent>, which you need to style the selected item.

And you can now add <legend> inside <optgroup>. Jake shows how you can use custom properties and the content property to transfer the optgroup label to an empty <legend>!

It took 33 years, but we are finally there. Almost.


Almost ready for day two..

Kevin Powell, CSS is eating JavaScript

Kevin starts about the checkbox hack, input:checked ~ .nav { display: block; }.

He's showing some anchor positioning demos and CSS math functions (sin(), cost(), tan(), rem(), random(), calc(), min(), max()), and Temani Afif's Graph Theory demo.

About Separation of Concerns and the old mantra of HTML, CSS and JS.

But so many JavaScript developers are doing CSS' job. A tip about setting a custom property with JS inline. But the flow of data isn't clear.

But this is going to change with the attr() function.

He's showing a 'basic' example now, using the content property and a data attribute.

But we can now use attr() with any property!

Showing an advanced <number> syntax example now.

Side joke about Tailwind going all-in on custom attributes.. But that's not the point.

It's less about about custom styling, more about data flow, and using data via custom attributes to influence styling.

You can pass in the unit when using attr() now.

And you can combine this with a min() function for example. And assigning types will help with this as well. Building in type-safety.

What if you'd pass all data inside a product card for example as different data attributes, so CSS can use this data..

You can then use calc() to draw the star rating for a product, for example. And make CSS do actual work it's good at.

He's now showing a more complex example combining a <select>, reading-flow, data attributes, a calc() changing the order property, some JS and a view transition.

Now showing an example using <custom-ident> combined with view-transition-name.

But what if we need to make decisions based on the data?

You might use if() in the future (Chromium only for now). Showing examples of feature queries and style queries.

There's a security note in the specification about using <url> values in attr() though.

Be very careful with URLs and the attr() function.

But we can use container style queries for this.

But just because we can do it in a cooler way, doesn't mean we should. — Maybe just use attribute selectors in some cases.

Showing some more examples combining style queries (with and).

CSS isn't eating JS, it's simply growing into it's own.

Slides available at kevinpowell.co/talks/css-is-eating-js/.

Q: Are there any security risks with advanced attr()? A: No, they thought this through. Apart from the URL blocking security note.

Q: At what point do we need to worry about performance about these new CSS things? A: Good question, probably compare it to what JS would otherwise do. Probably more performant if you just provide the raw data to CSS. But you'll have to benchmark it.

Q: Is it possible to use the type <string> instead of <number>? A: Yes, if you want it as a string, you don't even have to assign it a type, since it's the default. (raw-string)

Patrick Brosset, Fun with grid lanes

Throwback Friday with the animated Netscape logo :)

Showing us how people used to slice up images to make hover and active states for buttons. Constraints fuel creativity.

The playground got BIGGER. Showing a demo with motion-path, animated math, and a curved stack of folders.

More demos where he's playing with grid, anchor positioning, popovers, etc.

Why all this? Because computers are fun. Oh, and also because that's how the web remains relevant.

When designing a plane, you prototype, test, iterate, learn, etc. Same with the web platform. Eventually we'll get into interoperability.

A dive into grid lanes (born as Masonry layouts). Everything you've learned about grid will come in handy. You get to control the lanes in one direction.

Lanes can have different sizes. The placement of items is the most weird. You'll have to get use to it. It's very opportunistic. Visual order may differ from DOM order.

Safari 26.4 was the first to ship support. Edge/Chrome is behind a flag (#css-grid-lanes-layout in about:flags). Firefox was the first browser to ship a prototype. It's in progress.

Fill in the State of CSS survey 2026 if you haven't yet.

Showing demos with animating enormous amounts of grid lane items. (Apparently it's quite performant.)

Think about grid-lanes as swim lanes. Items are going to want to flow to the top.

Use it as a progressive enhancement; .layout { display: grid; display: grid-lanes; }. Or using @supports of course.

First thing you want to do is use display: grid-lanes. Then decide whether you want columns or rows. Same as with normal grids. Then choose the lane sizes. You can have items span multiple columns as well. And you can give items specific columns/rows.

Flexbox is quite similar to grid-lanes, with the flow direction.

With grid-lanes you can also use intrinsic lanes, with repeat(auto-fill, auto).

Flow is even more important than shape. It's a whole other beast.

Flexbox, multi-column layout and grid-lanes might look similar, but the flow of items is totally different.

Fragmentation works in multi-column, not in Flexbox and grid-lanes.

There's a new flow-tolerance property in grid-lanes. Spec link, to keep users read in a more reasonable order.

Sometimes the infinite keyword is what you want here. (Note to self: look into how this works.)

grid-lanes are an excellent use case for infinite scrolling interfaces. Maybe combine them with an Intersection Observer.

Or for a kanban/Trello board, where you change the grid-column property for a card. Maybe combine it with a same-document view transition. 🤯

Showing some cool demos showing photo gallery overviews!

News paper layouts, different column widths.. (I want to link all these examples! Where are they?!)

Another use case: Gantt charts.

Organic layouts; grid-lanes isn't too rigid.. You can play around with this!

It is not just Pinterest in CSS, you can get very creative.

Try it today! (Safari, flag in Chromium based browsers)

Slides available at patrickbrosset.com/slides/CSSDay-2026/.

Q: What happens when you use both grid-template-columns and grid-template-rows? A: Maybe the last one wins.. There's discussion about whether you can flip it dynamically.. It's not clear yet.

Q: Should we have logical properties for columns and rows? A: Yeah, that would be a good idea. For Grid and Flexbox as well.

Q: Are there accessibility concerns with tab order with grid-lanes? A: Yes, the visual order might differ from DOM order. reading-flow would be a good solution for it. Use flow-tolerance to minimize the problems for now, and keep an eye on reading-flow.

Q: What happens when an item at the start of a layout gets bigger? Do things dance at the bottom? A: Yes, if you change the size then things may change dynamically. Interesting to see.

Q: About the name grid-lanes? A: Because we reused so many of the grid properties, let's make it more easy for developers to transfer that knowledge. It puts your brain into 'grid properties' mode. Downside: the grid shorthand is getting more complicated now.

Q: Are there selectors to select based on position within a column? A: No, not yet. But that would be cool :)

Manuel Matuzović, Breaking with habits

Three years ago Manuel did a talk as well.

Progressive Enhancement was a great idea 20 years ago, and it still is, but we might need to break with habits..

I created a few side projects to play around with the habits I had, and break with them.

If I'm not coding anymore, I see myself unlearning CSS more quickly. (A side note about “AI”) Mental health > efficiency.

1. Reset Stylesheets; I don't see the point anymore. Some previous examples: https://meyerweb.com/eric/tools/css/reset/, https://necolas.github.io/normalize.css/, https://elad2412.github.io/the-new-css-reset/, https://piccalil.li/blog/a-more-modern-css-reset/.

Some examples and code demos now from oli.css he made.

A demo of https://fokus.dev/tools/uaplus/.

2. Structure and Organisation: mentioning ITCSS (Settings, Tools, Generic, Elements, Objects, Components, Utilities), that's just a concept. Cascade Layers help here.

Establish the order of layers upfront: @layer core, third-party, components, utility; for example.

Think of them as buckets, you're not creating more buckets, you're using them.

More info at https://fokus.dev/tools/css-boilerplate/.

3. Scalability: example from https://precise-type.com/ (so modular type scales).

Example code combining font-size with calc() and pow() to make a simple modular type scale.

Example code at https://codepen.io/matuzo/full/QwjOeLQ.

Showing the Utopia Clamp Calculator.

Tip: use the min() function to not make your typography too large.

4. Color: OKLCH and relative color for color scales.

Mentioning a previous talk on color.

Mentioning Gamut Mapping (like Lea yesterday).

5. Customization: using container style queries to change layout based on a single custom property on the html element.

https://olicss.com/download/

Mentioning @custom-media which hardly has any support.

6. Componentisation: Using custom properties to change the variation of cards, with inline style attributes.

Everything above is being used at matuzo.at right now (just for CSS Day). So go and play with it.

Slides available at noti.st/matuzo/XfWwBB/slides.

Q: How do you identify habits you need changing? A: Good question, takes time, dive deep into these topics, try stuff out. See where you hit limitations. Explore it and see. And try to forget what you learnt.

Q: Should we still call it a reset CSS? A: I called mine ua-plus to improve the defaults.

Q: About supporting browsers without @layer support, have you found a way? A: I think there's a PostCSS plugin for it if you must. Or fall back to plain HTML.

Q: How to find the time to catch-up with CSS? A: Writing these 100 blog posts was a horrible experience, but I learnt a lot. Easier if you're a freelancer. What works for me is writing blog posts on your personal site. Speak at meetups or in-house events. You don't have to learn everything. Pick one thing and do a deep-dive. And then you've learnt a new thing.

Niels Leenheer, CSS Doom Lasers

He gets obsessed mostly about the web, and how he can use the web beyond the edges of the browser window.

A laser projector was his latest obsession. To make a clock.

How I used CSS animations to draw a clock on an oscilloscope.

Or.. How I used webaudio to blow up an 1980's oscilloscope and almost caused a fire.

But what is a clock? A circle and three lines. We can use SVG for that..

And with CSS keyframe animations.

Using a negative animation-delay you can make an animation begin partway in its cycle.

SVG has some geometry functions, like getCTM() and getTotalLength(). And boom, magic! (Ok, I missed a lot of the math here :)

He's now showing live CSS and SVG animations running on an oscilloscope..

After burning the oscilloscope, he made an oscilloscope simulator..

Eventually he made DOOM in the oscilloscope simulator (I think..)

He started adding more details to the game, eventually ending up completely building DOOM in CSS.

Every wall, every floor, every ceiling, is a div. With simple transforms.

He's showing and explaining all the trigonometry that's going on (written out over on his website).

He's using the new shape() function a lot for this game.

Lots of detailed information, live interactive examples and snippets from his post. To convince us it's really just HTML and CSS, he just changed all images into cat photos :)

Eric Meyer, Forging Our Own Paths

Eric starts off with a demo of a rotating solar system, using offset-path.

The formal syntax for this property is wild!

To place elements along an offset-path, you can use offset-distance.

The <offset-path> value can be a ray() function.

Now showing several interactive demos explaining the ray() function in detail. Lots of rays.

To anchor the element to the path, you can use offset-anchor, which has nothing to do with anchor positioning.

Now a demo showing the same rectangular offset-paths made with inset(), rect(), xywh(), polygon(), path() and shape() syntax.

To change the orientation/direction of the element, use offset-rotate.

Now you know how I built that solar system.

You can create an offset-path using border-box, padding-box and content-box. 🤯

Especially with the shape() syntax you can make beautiful (dynamic) paths.

Now a demo with attaching animation-timeline: view() to an offset-path using the shape() smooth command. 🤯

Combining SVG getTotalLength() and stroke-dasharray to animate drawing. (See Jake's article about this from 2013.)

Temani Afif built an SVG path to CSS shape convertor.

Thank you for joining me on this journey along this path.

Q: What is the best way to create responsive paths? A: The path() function.

(Forgot to take notes for the other question, sorry! :)

Una Kravets, Modern UI Patterns

Key UX Principles: 1. Respect user preferences 2. Maximize content, reduce noise 3. Implement natural interactions 4. Provide guided navigation 5. Adapt to the form factor

Use prefers-color-scheme, prefers-contrast, prefers-reduced-motion and prefers-reduced-transparency.

A quick recap on light-dark() and a shout-out to Bramus' custom --light-dark() function.

Simple example of contrast-color(), and a more complex example which converts it to a boolean with style queries and if().

Now an example of using light-dark() used in box-shadow with transparent and OKLCH colors. She owes us a blog post about this :)

Use Scroll State Queries to reduce noise in UI, hiding a sticky header for example. Typical Progressive Enhancement example.

Demo available at https://codepen.io/una/pen/xbVoLLO.

Una now shows a demo from Abdelrahman Hassan.

Scroll-driven animations can also help to reduce noise.

Next thing to add to our toolboxes will be scroll-triggered animations.

Popovers and position-try combined to make UI less noisy as well. As Jake showed us yesterday.

Anchored container queries, why not! To keep tooltip triangle thingies connected correctly to our popovers.

Now she shows a demo of using border-shape. You can make the shape any way you want, which plugs into shape() we just heard about.

Next about Interest Invokers (which I played with here). You can use these on both buttons and links.

A shout-out to Emil Kowalski.

Multifunctional popovers with popover="hint" (which can be combined with Interest Invokers).

There's a proposal for ::interest-button which is being worked on in Canary.

The user agent stylesheet for this will be interesting: https://github.com/w3c/csswg-drafts/issues/12437#issuecomment-4462208949

Join the discussion for this: https://github.com/w3c/csswg-drafts/issues/13980

A shout-out to animations from Tubik Studio and Anton Skvortsov.

Use natural easings, start learning linear().

A scale: .95 on an :active state already makes a button nicer.

Put a simple filter: blur(8px) in the middle of a keyframe animation.

Use sibling-index() to create a staggered animation with animation-delay.

If you connect keyframe animations to scroll-driven animations, you get a lot for free.

You can use scroll-triggered animations to make direction-aware animations.

Another small addition: scroll-target-group.

Anchor positioning is in every modern browser, still has some bugs, but it's usable.

Next, a demo of https://una.im/follow-the-anchor/.

Scoped element view transitions will be great for micro-interactions and morph animations.

Lots of examples from Emil recreated with simple CSS animations and view transitions!

Using Scroll Snap, scrollIntoView() and inert to make a swipable UI.

There's a proposal for Overscroll Areas coming up. Plugs into Invoker Commands.

The web is more capable than ever. Raise your expectations for the web.

All demos are available at https://codepen.io/collection/myqqRY.

Adam Argyle, Contextualism

We're going to chant CSS, CSS, CSS again! :)

Alternative title, if he were a Youtuber: “Our design systems suck”

Follow along via https://css-day-2026.netlify.app/.

This talk is an extension of https://nerdy.dev/components-can-know.

I've seen blocks that act like Lego, and I want you to stop building Lego.

Think about landscape more. — orientation media feature

Is your design system adapting to user preference media queries?

You should be using logical properties.

Named container queries can pierce the shadow DOM.

Try using :has() for quantity queries.

Use @scope proximity.

Use local context from the inherited cascade. Like currentColor.

Use intrinsic sizing, min-content, max-content and fit-content.

Use interpolate-size: allow-keywords to animate between a length and keyword size.

Use the + and ~ selectors to adapt to the preceding element's state.

Use destructuring in CSS! Relative colors, that is :)

Adapt a color font's palette, using @font-palette-values.

A live demo of Open Props colors.

Invert the variables, don't invert the palette.

Use contrast-color() to let the browser choose the ink.

Live demo of https://nerdy.dev/page-and-component-light-dark-strategies. Three strategies to pick light/dark mode.

Adam's idea for perfectly matching nested radii.

Change your grid-auto-flow based on orientation.

Try out the :playing pseudo-class combined with :has().

Use the :autofill pseudo-class for automatically filled inputs.

Did I snap? Use scroll-state(snapped: inline).

The ::target-text pseudo-element is quite a new one.

Loads and loads more. Check out the slides!

There's a lot of stuff CSS doesn't know, but JS does. Check out https://prop-for-that.netlify.app/.

🤯

Components can know. Now go let them.


Great conference! Thanks everyone involved, and thanks for watching along if you did :) See you next time!

Comments

Hoi Krijn, bedankt voor het delen van je CSS Day aantekeningen.

Kaj on

Add your comment

Modern keyword stuffing

Making a reading progress indicator