Breaking with habits

Returning to CSS Day: Three Years of Unbroken Habits

Speaker A introduces Manuel Matuzovic as a CSS educator, accessibility author, and beloved community member. Manuel reflects on his previous CSS Day talk about evolving CSS practices and explains why his predictions didn't fully materialize — cascade layers are hard to progressively enhance, and long-held habits like BEM are difficult to break when they already solve the problem at hand. He uses a real reader anecdote to illustrate how adopting new CSS features sometimes requires abandoning the very tools that made the old approach work.

An AI Detour: Efficiency, Burnout, and Why Coding Still Matters

Manuel takes a last-minute detour to share concerns about how AI is reshaping developer workflows, citing a friend doing the work of five people and another running six AI agents — including one that summarizes their RSS feed each morning. He argues that manual coding, deep reading, and genuine learning are prerequisites for professional growth, and frames his continued love of hands-on CSS work as both a personal value and a professional necessity rather than a relic of the past.

Rethinking Reset Style Sheets: From Resetting to Improving Defaults

Manuel outlines the five CSS areas he's been reinventing and dives into the first: reset style sheets. He traces their evolution from Eric Meyer's early resets through Nicolas Gallagher's normalize.css to modern approaches by Ella Chachter and Andy Bell, noting the shift toward improving browser defaults rather than wiping them. He then walks through his own reset stylesheet's innovations, including smarter label/input stacking, animated dialog transitions using the transition-behavior property, anchor-positioned popovers, and wrapping the entire sheet in a cascade layer for seamless compatibility with both layered and unlayered CSS codebases.

Enforcing CSS Architecture with Cascade Layers

Manuel presents cascade layers as the missing enforcement mechanism for the ITCSS organizational concept, explaining how ITCSS's inverted-pyramid specificity model is a sound idea that breaks down without tooling to enforce it. He reveals his four-layer architecture — core (reset, tokens, base), third-party (imports and overrides), components (base and variations), and utility — and demonstrates how declaring layer order upfront allows CSS to be split across dozens of files without losing cascade predictability. He likens the layers to reusable buckets: you throw styles in without ever redefining the order.

A Mathematical Type Scale Using CSS's pow() Function

Manuel explores making font sizing systematic and scalable, drawing on lessons from his design system work for the City of Vienna, where a no-class framework proved its value when thousands of CMS pages imported cleanly without any custom markup. He walks through building a type scale with CSS's pow() math function, where two custom properties — a base size and a multiplier — drive all heading sizes through an exponential scale. He shows how applying the system to all elements via a universal selector forces consistent sizing while still allowing overrides, demonstrated live with interactive range sliders changing the entire page's typography by updating just two custom properties.

Fluid Typography and Handling Browser Accessibility Overrides

Manuel tackles the challenge of integrating fluid typography with his unit-less custom property system, using a Stack Overflow solution by Temani Afif that strips units from a clamp() expression via nested math functions — a technique Manuel admits he doesn't fully understand but deploys in production. He then confronts an accessibility failure discovered during the conference: Firefox's text-only zoom mode causes his exponential scale to produce enormous text, which he fixes with a simple min() cap that gracefully limits font size growth.

Modern Color with OKLCH and Relative Color Syntax

Manuel explains how preparing a color theory talk converted him from hex values to OKLCH, whose three human-readable channels — lightness, chroma, and hue — make colors easier to reason about and unlock 50% more of the color gamut. He shows how relative color syntax makes generating coherent tint scales effortless, then live-demonstrates a surprising and dangerous out-of-gamut edge case where a seemingly reasonable lightness value produces a wildly unexpected result in browser color tools. The segment closes with Manuel sharing what he describes as official confirmation from representatives of each major browser that gamut clipping behavior will be improved.

Opinionated Defaults, the --magic Property, and Simulated Custom Breakpoints

Manuel shows his base stylesheet rendering HTML elements without any classes, then introduces a --magic custom property that uses container style queries to transform plain semantic HTML into a properly laid-out page — complete with styled header, navigation, and footer — without a single class name. He also reveals a creative hack using the min() function to simulate custom breakpoints inside container queries, working around CSS's current inability to use custom properties in media query expressions, and points attendees to a related wild demo at CSS Café.

Componentization as Configuration and New Website Launch

Inspired by Lea Verou's ideas on custom properties as component APIs, Manuel demonstrates how card components can be configured entirely via custom properties passed through style attributes or inherited from parent elements, replacing predefined class variants with a declarative configuration model. He reveals his experimental OlliCSS framework and a newly launched personal website — built specifically for CSS Day — that uses every technique discussed in the talk, including fluid type, container style queries, and whole-site color theming driven by a single custom property. The talk ends with a book giveaway and links to slides, code on GitHub, and documentation on focusofak.dev.

Q&A: On Habits, Naming, Teams, and Learning CSS

The moderator leads a Q&A covering audience questions including why Manuel uses --magic instead of a class, how he identifies habits worth changing, whether 'CSS reset' is still the right term (Manuel prefers 'UA plus'), cascade layers with inline styles, browser support strategies for at-layer, and the challenge of opinionated defaults across multiple projects. Manuel closes with candid advice on keeping up with CSS in a full-time job: write blog posts, present at meetups, and apply Leonie Watson's accessibility principle — it doesn't have to be perfect, just a little better than yesterday.

These days when I walk past a record shop, the first thing that comes to my mind is our next speaker. That if you don't follow them on social media or on our your RSS readers, you should do it now. He's a highly talented individual that everyday makes the web in our community a better place by teaching and bringing their own personality into it. But CSS is not the only thing they excel at.

They also wrote one of my favorite accessibility books that I consult every week. Give a round of applause, Manuel. Thanks

a lot. Hello, lovely people. It's so great to be back again here in Amsterdam at CSS Day. Last time I was here was exactly three years ago with a talk titled That's Not How I Wrote CSS Three Years Ago or you know six years ago counting from today.

Anyways, the core idea of this talk was that in the years leading up to the events, the way I write CSS has changed a lot and I explained how and why. And I also predict that it will even change more with many of the new things that we have in CSS thanks to the Interop efforts. And I think we saw a really good demonstration of that yesterday in Lyra's talk.

Yeah. So this has changed a lot for them but not for me unfortunately because there are several reasons. The first reason is I just didn't have a project where I could put all my ideas and predictions into practice because with some of these things, it's either all in or nothing. For example, cascade layers. They're amazing, they're fantastic, I love them.

But they're also really hard to progressively enhance. That's the first reason. Another reason is that I realized that I've been following certain approaches and principles and an understanding of what's a good or a bad practice for ten years, fifteen years, sometimes even twenty years without second guessing them. And for some things that make sense like progressive enhancement was a really, really great idea twenty years ago and it still is a really great idea now.

But in order to get the most out of some things in CSS, we may have to reevaluate how we approach certain problems in CSS or we may have to break with habits. Here's an example. I wrote a blog post about cascade layers a while ago and I posted it on social media and someone replied and said, hey, Manuel, thanks a lot for explaining cascade layers.

I added them to my website but I didn't see a difference. I'm not sure what they expected but we chatted a little bit and I learned that they were using BAM. So they already had a tool in place that solves the problem that cascade layers are supposed to solve, make working with the cascade and specifically specificity easier.

So in order for them to see a difference, they will probably have to stop using BAM and maybe even change the way they are selecting stuff and maybe also, like I said, reevaluate some of the good and bad practices of working with selectors and changing them maybe completely. Okay, thank you. I hope that works.

Okay. So this is the core idea of this talk now. The first thing I did is I created some side projects where I can test stuff and play around a little bit. And also I was trying to see where I can break with habits, where I can change some of the things that I've been doing for the past twenty years.

And before I go into that, I have to quickly make a last minute change to my talk because I've been to several events this year and some of them feature talks about AI. So I heard a lot about AI, people talking about AI and how they're using it and also had a lot of conversations with people about how they use AI or maybe how they are not using it. And I just can't get certain things out of my head. Like, I I constantly thinking about AI these days.

And if we put the horrible impacts on environment aside and also on culture as a total, then maybe it can be a good idea to use AI excessively. And I think there are smart ways and good ways of using AI and then there are also not so smart and bad ways of using it. And yeah, I just heard some things that I find concerning. I was talking to a friend actually and he told me that he went all in on AI and he's fully integrated it in their workflows.

And he told me that now he has more work than before. And when I heard that, I was trying to like come up with a reason why that was. But then he continued and he said, but I'm doing now the work of five people. And it took me a while to process that and when I did, I was like, is that what we want?

Like, do we want to improve efficiency so much so that we can burn out at age 25 instead of age 35? Is that our goal? Is that what we want? Then I heard about another guy who has six agents working for them, I have no idea what that means, but he says he has six agents. One agent is his CEO, one is his project manager, one is the developer, another one is the designer and assistant and the sixth one is, I don't know, fucking barista or whatever.

I don't know. And he also said that one of them is giving them a summary of their RSS feed every morning. And when I heard that, I was like, no, that's not what RSS is about. You don't want It's not about information consumption. You want to read and learn from your friends, from the people you follow, from the people that you that you respect.

You want to see what they're working on, what's on their minds, the problems they are trying to solve. This is the stuff that they find interesting. It's not just about the what but also about how. It's like how are they describing it? How are they using language? How deep are they getting into the content? That's what you want to learn.

It's not just about stuffing as much information as possible into your head. And one more thing and then I promise I will talk about CSS. I heard another one who who said that they have been they not have they have been using prompting and voice for coding for two years. So they're not touching the keyboard anymore for coding.

And I've heard that several times and I was like, did it happen now? Am I now you know, one of the people who doesn't know how web development works in 2016? Like am I completely out of the loop now? Did I miss the train? Am I like doing the it's the old way? But if that's the new way, I'm not sure if I'm like that, if I want that because I'm in this very privileged position like probably most of you that I really love my job.

I love coding. I love you know designing in in the browser. I love I love playing with dev tools. And I don't see having as much fun if I'm just using my voice and prompting. And also, one of the reasons why I was invited three years ago is that I missed so much of the new CSS stuff that I was completely out of the loop and I had to get back on track, so I wrote 100 blog posts about CSS in one hundred days.

Not just because I hated myself, but because this is my preferred way of learning. And if I'm not coding anymore, I see myself unlearning CSS really quickly. Yeah, I know that's a bit off topic but it was just weighing on me and in my head and I just had to get it out for you.

And the last minute change that I'm making to my presentation now is I'm changing the title. Don't worry PPK, I'm not changing the content of the talk, just the title. And I'm giving you options. Maybe if you like breaking with habits, we're cool. But maybe you like mental health is more important than efficiency better. Or maybe you like something that you can put as a sticker on your wall. Read, learn, grow.

Or maybe being good at CSS is more important than ever. Or it's time to really learn CSS maybe. Oh, that one's controversial. Your profound expertise matters. Or maybe just explore because exploring is what I did for this talk and I was trying to find areas where I can change the way I write CSS.

And I've identified five areas and the first one is reset style sheets. The second one is structure and organization. The third one is scalability, customization and componentization. So this is where I was looking about things that I can change in order to get more out of modern CSS. And we'll start with reset style sheets. I haven't been using reset style sheets for five, six, seven years probably, like for a long time because I just don't see the point anymore. There used to be a time where reset style sheets made a lot of sense because the browser landscape was much more diverse than it is today and they render pages very very differently.

Eric Meyer famously created the first popular reset style sheet, reset CSS, which resets properties like margin and padding and a list style. Nicolas Gallagher took a much gentle approach by normalizing more than than resetting, which made sense and was also super useful. But the thing is, there was a long time ago and many of the problems that these style sheets solve don't exist anymore today.

But reset style sheets are still a thing. There are modern style sheets like the new reset, the new CSS reset by Ella Chachter and his approach is to just reset almost everything. So you see a lot of all unset in his stylesheets and a lot of non keywords and reword. Pretty radical, but if it works for them, it's it's fine I guess. But there are also other style sheets that take a different approach like Andy Bell's A More Modern CSS Reset.

And looking at his style sheet and also other similar style sheets, I realized that today it's less about resetting and normalizing but more about improving the defaults. And I found it super interesting. So this is the first area where I'm trying to see if there's anything that I can change about the way I write CSS and think about CSS.

So I created a reset style sheet and in my style sheet you will find some of the traditional stuff like I'm switching to a traditional box model. I know that there are certain people here, certain influential content creator people here who don't believe anymore maybe in in switching to this box model. But it works for me so I'm keeping that stuff.

But you're not here for that. You want to see some of the modern stuff. Let's look at this wild selector here. If you create a label, a label element and an input field by default it will look like this. So you can see that the input field is next to the label because they're both display inline or inline block or something like that. But I would argue that in 98% of cases that's not what you want or maybe even 100% of cases because you want to be your input field to be below the label because that's what's best for UX and accessibility.

And this is exactly what the selector does. So what I'm doing here I'm saying is if there is a select element or a text area or an input that is not of the type radio or checkbox and it's following a label element, then sets the label to display block. And that's in my opinion a better default. Or here's another example.

By default, you open a dialogue element, just appears and if you close it, it disappears. There's no transition and it makes sense because it's hidden, it's display none and we can't animate display none. Or at least we weren't able to do that for the longest time because now it's possible. Thanks to the I think transition behavior property.

So in your transition you don't just transition opacity but also display and you had to allow discrete keyword so that you can also animate discrete properties like display and then you also animate overlay which is the backdrop so that it fades in and fades out as well. And in order to make the fade in possible you have to define a starting style.

And then you get this. And I know it's not a big difference. It's very subtle but you know it's nice. Here's another one popovers. By default, you open a popover, we heard a lot about popovers yesterday, they almost look like dialogues and that's not a good default if you ask me. What's great about popovers is that they come with an implicit anchor and I think we heard about it yesterday in Jake's talk.

So we don't have to do that. We don't have to select the button explicitly and define an anchor and then reference it in the popover and position the element. We don't have to do that because you don't want very explicit stuff like that in your CSS style sheet. All we have to do is we say, you know what, if the browser supports anchor positioning then select the popover, remove the margin so it's not centered on the screen, and then position it and even add some fallback.

And now we get this. You can see how the popover is positioned closely to the button and if there's not enough space then it just flips. And this is really nice. And a much, much better default if you ask me. Okay. One more thing about my reset style sheet, I wrapped everything inside a cascade layer which is a really smart thing to do.

I didn't come up with that. Emilio suggested it in a GitHub issue and said, hey, why not wrap it? Because the thing is if you're not working with cascade layers, that's really cool because if you add this style sheet you are making sure that your styles will always overwrite these styles because unlayered styles overwrite layered styles. And if you're using cascade layers, then you just integrate it in your pipeline or you reference it and position it wherever you want in your Cascade Layers.

So that's really cool. So to sum it up, you may want to revisit your existing style sheets and see if the stuff in there still makes sense or maybe if you're not using one, you may want to create one. Mine is online on GitHub and also on a website called focus.dev, focusofak because all the good domain names are gone.

And yes, you can you can see a breakdown of all the properties. You can check it out. And the website doesn't look nice. It's just a placeholder for a website. But what's really cool is I built this demo thing. So I list most of the elements in HTML and you can see how it looks like with my stylesheet and compare it to the default user style sheets or with another stylesheet like Andy Bells for example or LR Checkers.

So that's a really nice way of comparing the different reset stylesheets. Cool. A second area where I wanted to see if there's anything I can change is structure and organization. For most of my career, I've been following an approach very similar to Harry Roberts, its CSS or IT CSS, which is represented in this inverted pyramids. The idea is that at the beginning of your CSS file, you start with very general stuff.

Harry created this specifically for Sass so you would use stuff like mixins and function. I don't know. I don't remember anymore. It's been years since I've written Sass but stuff like mixins. Or in modern CSS it would be your add rules. You define your layers. You have your custom property registrations and add font face and stuff like that. And then you have maybe in the universal selector or something that's with very low specificity.

Then you have your tags and you slowly increase the specificity of your selectors. So you go for your class selectors, attributes selectors, maybe even IDs and then at the end you have utility class. And the idea is that by progressively increasing the specificity you make it easier for you to manage specificity in your CSS.

That's a fantastic concept but the problem is that it's just a concept. There is nothing that enforces these rules. So if you throw in an ID selector somewhere in between, then it messes with the specificity of your CSS and I'm really proud of that animation. Yes. Luckily, have cascade layers and they are really cool because they allow us to enforce these rules.

So they allow us to split up our CSS into multiple layers so we don't have to manage specificity for the entire document but just split up in layers. And layers defined later in the document, overwrite layers defined earlier. And within these layers, can even split them up again if you want to. You add more sub layers and make it easier to manage specificity inside the layer.

And for my project, I didn't just want to come up with a structure that I can use for this specific project. I wanted something that I can use in any project of any size and this is what I came up with. I have four layers, core, third party, components and utility. Core is split up into reset. This is where your reset style sheet or mine goes.

Then we have tokens and base. Tokens is just for token space for base style sheets. This could also easily be a single layer. Then we have third party and I split it up in imports and overrides. So in imports, this is where your Bootstrap CSS goes or your Prism CSS. Any third party tool. And if there's anything that you want to override from these third parties, then you have the dedicated overrides layer.

So it's not like you are throwing it anywhere in your document but you have a dedicated place for overrides of third party styles. Then you have a components. Inside components, have a place for base styling of your components like this is how a card looks like by default. And then you have variations where you define your large, small and so on. And that's that.

And now if I want to use it, for example I want to use my UA plus my reset style sheet, I just import it directly into the resets layer inside the core layer. Or if I have a utility inside my utilities CSS, I just call this layer and add my styles or inside my card CSS, I just add my card styles and put them in this layer.

And what's great about this is that it doesn't just make working with the cascade or with specificity easier, it also allows me to split up my CSS into multiple files. So now I'm not just working in a single file, I'm working in, I don't know, 50 files or 30, whatever depending on how many components you have. And I don't have to worry what's happening when I'm putting the files together, maybe inside the build step because in the very first line, the line that you see here, we have already established the order of the layers.

So anytime you're using a layer, you're not redefining them, you're just reusing them. Think of them as buckets like you have four buckets and when you have styles, you just throw them in the first, second, third or fourth bucket. And you're not creating more buckets but reusing them. And I really like that. So this is how my inverted pyramid looks like.

Utility overrides components, components overrides third party and third party overrides core and here are the sub layers. All of that is also online on focus.dev. There is the code. There is also an FAQ. No one actually asked these questions. I'm pretending like people actually asked me something.

But yeah, I'm basically just justifying all my decisions here and explaining what I did and why I did it. Check it out if you want to. Next, scalability. So here I wanted to find out if there's anything in modern CSS I can use in order to make my websites more scalable and more resilient.

One of my clients is the city of Vienna and I was the one who created the concept for a new patent library and I also wrote the big part of it. And the way we designed it, we use native HTML, native CSS and web components with Lit.

And we are big fans of progressive enhancement. So we have a lot of JavaScript in our websites but if you disable JavaScript, the website still works. So you will still It looks a bit different maybe but everything is still accessible because we don't use Shadow DOM too much. I'm not the biggest fan of Shadow DOM necessarily and it just didn't make sense for us.

Anyways, so if you disable JavaScript, it still looks fine. If you use the website and you don't use any classes, it also looks fine because we designed it as a no class framework. So if you take our CSS and you just throw in some HTML, it will look nice. And as it turns out that was a really great idea because we recently switched CMS and we imported a lot of pages, like thousands of pages into the new CMS.

And some of them we touched and improved to make them look really nice. So like the most important pages, the most viewed pages, but most of them we didn't want to touch. It was just too much work. And the guys who imported it wrote me an email or they called me and said, Manuel, we didn't import and it's really strange.

Everything looks fine. What's going on? And I said, yeah, we are selecting most of the elements in HTML and we have just default styles for most of them and that's why it looks cool. So that was a really good idea and yeah, because that worked so well, I wanted to see if there's anything that I can use in my projects.

And here's an example. You can see I'm defining font sizes here and I'm using pixel so that it's easier to read. And if you look at these numbers, does anyone see a system? Some kind of scale? Yes, you're nodding? Okay. I don't see it. For me, these are just random numbers, magic numbers. But there could be a system behind it.

There could be like a system for the headings or for picking the size for each headings. And actually there is. So if we look at one of these websites where you can define the type scale, this is not the best. This is just the first one that I found precise type. You can see that on this website you define a base font size like 16 pixels and then you define a type scale.

And you can see how it starts at 16 pixels and then you multiply the 16 pixels by the type scale, you get 25, no 20, then you multiply 20 again, get 25 and so on. So this is how the scale works. And when I looked at that, I was like, okay, I was really bad at school but I can I understand the system here, I can do this in CSS?

So I just create a custom property for the scale, one for the base, and then I say the h six is just the base, just 16 pixels. But the h five is the h six multiplied by the scale, the h four is the h five multiplied by the scale and so on. Nice. But there are two things that I don't like about it. First of all, the repetition, I don't like that.

And I also don't I don't like the referencing. Another way to write that is like this. I mean you can do that. So the h five is the base times the scale, the h four is the base times the scale times the scale, the h three is the base times the scale times the scale. It doesn't even fit on the screen, so that's not nice.

But again, there is a system and I was like, okay, some dead dude probably came up with a formula for that many many years ago. And I also know that there are math functions in CSS, so I went on MDN and I found the power function. And there it says the math power static method returns the value of a base raised to a power.

I was like, okay, that sounds exactly like what I want. So I tried it out and now we have this. You can see that I'm using the power function now. It takes two values. The first one is the base number and the second one is the exponent. And the number basically indicates how many times you want to multiply the base with the number, yes.

So if you provide zero, it just returns 16 because it just multiplies it once. If you provide one, it returns 20. If you provide two, twenty five and so on. Still a lot of repetition but much cooler repetition if you ask me. But of course, we can improve that. So the next thing it is, I selected all of the headings and instead of defining a fixed number like zero, one, or two, I'm using a custom property with a fallback of zero.

And now instead of defining the font size, you're just defining a custom property. I know that looks strange but it's also kind of cool. And what's great about it is now I'm forced to use the system, very similar to what I was talking about the cascade layer. So this is not just a concept, now I'm forced to use the system that I've defined.

Kind of because you can also say, you know, give me four points two or something like that. So you can trick the system but yeah, it's cool. But I was like, headings but what if I want to use the system on the entire website? So I did this and please don't try that at home. Or actually try it at home.

Don't try it at work. You can try it at home, don't try it at work because what I'm doing here is I'm selecting all the elements on the page and I'm using that. And this can be a problem because first of all, I'm resetting all the font sizes by default to 16 pixels because the default value is zero. That's the first thing.

And the second thing thing is this messes with inheritance potentially. So yeah, be cautious of that. But I tried it and I think it's really cool because now I can define custom classes. You can see that this big class with a factor of 10 and then have a small class with minus one, you can also use negative numbers. Really cool.

But what if I don't want to use the system? What if I want to break out of the system? What if I want to define something like 50% or two REM or something like that? So I split the formula up and now what I'm doing is I'm saying there is a dash dash font size custom property where you can define the font size.

This could be two rem for example. If you're using that, then it's just two rem and that's it. If you're not using it, then it falls back to my formula. Okay? And this is how it looks like. Have two range sliders here, one that can change the scale, one changes the font size and you can see how just by changing two custom properties, we get very different results.

The custom class is not changing because I just defined two rem, but everything else is changing with the scale and then you change the font size. And this is pretty powerful and all we're doing is changing two custom properties. Yesterday in Josh's talk, we heard how cool fluids type is. And I think fluid type is cool, super useful, but how can I do that? I probably can't because you know I've now I've custom properties with unit less numbers.

And of course I was thinking maybe I can use clamp and just use my unit less numbers inside clamp but that doesn't work. You need something like pixel or REM inside the clamp function. But it gets really hacky now and I'm not recommending it to do that. I'm using it in production on my website, it works, it's fine. But it's a bit strange.

What I did is I went on Utopia FYI, I went to the clamp page and I said, okay, at the minimum viewport of three twenty, I want one pixel and at the maximum of twelve eighty, I want 10 pixels because I want to transition my font size from one to 10. So from the value one, exponent one to exponent 10.

And what Utopia gives you is of course a pixel like one pixel to 10 pixel or actually they will give you RAM. So they converts the here's the photo. Okay. So they convert the pixel to RAM. So you can see 0.0625 is one pixel. And but what I need is I need a computed value of that without the units.

And my friend Matthias Ott helped me with that and I did some research and then I found of course a Stack Overflow answered by Timani Aviv with this solution. So he's wrapping the clamp function inside an eighteen two function inside a 10 function. And I looked it up online because I wanted to explain it to you because we're at CSS day.

I didn't understand it so fuck that. So I have no idea what's going on. But what it does in the end is it gives me unit less numbers that I can transition. There's one more step, I just have to register this custom property and then we get this with my dash dash exponent. Yeah. Yeah and that works.

And I'm using it in production on my website and you can see how the h one by default is very large on my website. And yesterday in George's talk I saw this option in Firefox where you can say text only and I wanted to see what happens if I check this checkbox and increase the font size. Oh no no no no no.

This looks horrible. This is one like perfect example for where this doesn't work well. And I didn't use Josh's solution because it's not implemented in any browser yet. But I I just It was the simplest thing fix I can think of. I just use min. So I'm One of the values is my formula and the other one is just a fixed pixel value.

So if the font size is lower than 97, it just uses my whatever I'm doing here. And if it's larger it's limited to 97 and that works. So this is zoomed in with text only and it works. Yes, yes. Alright. Another interesting topic is color and we heard a lot about color yesterday.

And for the most part of my career I didn't care about color at all. Like I didn't know anything about color theory and I I was just using hex values. I just copied it from the design that I got and that's it. But Mark invited me to speak at Beyond Telerent. Mark, are you here? Oh, hi Mark.

That was the third attempt like I'd I'd try to do this joke twice and he was always at the conference where I was speaking but he was not in the room and finally he's in the room so I could do the joke. Okay. Yeah. So he invited me to speak at Beyond Telehand and I presented a talk called color in CSS or how I learned to disrespect tennis. And in preparation for this talk, I learned a lot about color theory.

It took me so so long to prepare this talk because I didn't know anything like I said. And now I know much more, I know how to use color in CSS but I still fucking hate tennis. Anyways, now instead of using hex codes, I'm using OKLCH and we learned about some of the benefits yesterday. One of them is that it's just so much easier to read.

I can't read hex. I know that there are people that can read hex. There's a talk by David DeSandro on YouTube that you can check out where he explains how how you can read it. But I can't. OKLCH is so much easier because it's in a cylindrical shape. We have three channels. The lightness which goes from zero to one or 0% to 100%.

Then we have the chroma which is a strange number. It's between zero and zero point four. And then we have the hue which is a value between zero degrees and three sixty degrees. It's very similar to the HSL color wheel but it's a bit different. And that's actually much easier to read. You can read OKLCH. And the another advantage is you have 50% more color.

So this is also really cool. But if you're working with colors, you can see these are the four colors that I'm using. You're You probably don't want, don't just need four colors. You need different tints, different variations of this color. And that's super easy with relative color syntax. It just works so fine. You would just define your base color and then you reference the base color all the time.

You reuse the chroma and the hue and you change the lightness. Or maybe you maybe you even want to adjust the chroma a little bit but I kept it easy here and I'm just changing the lightness and this gives me these nice color scales. And what's great about it, if I decide to change the green to blue, the the different variations of the color will just update with the color. Okay.

You can see how the dark colors get really dark. The light colors can get kind of light. They're still in in gamut but if you go from 0.9 close to one, it doesn't look great. And that's because out of gamut is the Wild West as we learned yesterday. And actually I took one of the colors and I wanted to see what happens in one of the tools that Leo showed us. So if I take the yellow that you just saw, yeah, the last color, the yellow one.

If I take that and I put it in the tool, you can see, I put it in this tool and I changed the lightness to one and lightness one means white essentially. But we get this light yellow color. But what I would expect is this color. And then I tried the same in this tool because I really liked the visualization here and now you can see the value is a bit darker but it's caused, I set it to 80%.

And I'm slowly increasing it to 90% and you can see it's still in gamut. But as soon as I pass 0.9, we are now completely out of gamut. Like we were so so far away and that's very unexpected. And I wasn't doing anything wild here. I just picked colors that I like. I wasn't deliberately trying to find a color.

I just It was the first color that I actually did it like two hours ago in the back. I just picked one of the colors and I saw this and I was like, okay, the tool is broken but then I changed the value, you know, realized, okay, I'm just so far out of gamut that I don't see the colors in the middle.

Yeah. That's really really bad. But I have good news for you because I have totally official confirmation that browsers will change that. I got a confirmation for free high profile representatives of each browser And they told me that they're going to fix gamut clipping.

Although I have to say it is possible that they didn't know why I was taking that photo and how I'm going to use it. Alright. There are many more rules in my base style sheet and this is how it looks like. So if you scroll through the page, I've added most of the elements in HTML here.

They look okay. I'm not a designer. I'm not good at designing. But it looks fine. So it's good enough for me. And you can see most of the Yeah. There are styles for most of the elements in HTML and different variations of these elements and so on. But if you look at the page, can see how this doesn't look like a website.

And it makes sense because I've just I just have base styles. I'm not using any classes. But in this document there is a header element at the very top and there's also a navigation inside the header element. But it doesn't look like a header of a website. I could add styles and say, you know what, if the header is in the context of the body then please make it look like a proper header of a page.

But that's kind of dangerous because it could also be a header inside the section element or inside an article or there could be a nav element inside the main content somewhere. But then again, I know how I write my HTML and there is a certain structure that I usually follow and maybe I want an opinionated variation of my CSS.

Maybe I want the header to just magically look like a header even though I'm not defining any classes. So I need a level of customization and I need some magic. And this is why I select the HTML element and I set dash dash magic to true. And when I do that, the page looks like this. I can see how there is now a proper layout.

We have a header, the navigation looks like a navigation. And of course, I'm using container style queries here. And I'm saying if dash dash magic is true, then please change the layout of the header and the footer and the main element. And also inside the header change some of the layouts. And I'm using custom properties heavily here.

Yeah, I have different settings so you can turn magic on and off. You can change the layout from a vertical to a horizontal layout and you can also change the font stack. Let me just quickly show you that because I really like that. I have different font stacks defined based on modernfontstacks.com and you can pick one. And what I like about this is it looks like a switch statement almost in CSS in a way.

Yes. So if you go to Olli CSS, that's one of the projects. And you download the file, it's file. It will look like this, but you can also customize it. So you can see how you can change some of the settings. You can disable magic or enable it. Okay. Yeah. You can change the layout, so vertical layout.

And all I'm doing is I'm changing custom properties. So you can see the custom properties that I'm changing here and now I'm changing just the hue and it affects the entire website. Then the chroma maybe a little bit, the lightness, and all I've done is I've changed three or four custom properties. And it doesn't look completely different, but different enough if you ask me. So I'm changing the fonts, the font family, base font size, and the scaling.

And on top of that, have a lot more custom properties. So you can change almost anything on the website. And I even have that. You can define custom breakpoints. So you can see see define where the first breakpoint is and the second breakpoint is. I'll limit it two. Now some of you may be thinking, how are you doing that?

Because that's not possible. We can't use custom properties inside of Miracuries. Yes, true. That's unfortunately not possible. The thing that would get us as close as possible to doing something like that is custom media queries. But unfortunately they are only in Firefox nightly behind the flag as far as I know. So this is also not available. What I'm doing is this.

I'm defining two custom properties. One is my breakpoint, so 48 rem. And then I have another one where I have a min function where I pass the breakpoint and 100% of the viewport width. Before I keep talking and explain what's going on here, let's just quickly talk about the min function because I keep forgetting how it works. So you have this function, I'm passing two values and there's a 10 pixel value and a 50 pixel value and what min does is it always picks the smaller value.

So 10 pixel wins here. If we have 10050%, it depends on what 100% represents or what a computed value of 100% is. If it's lower than 50 pixels then 100% wins. If it's larger than 50 pixels then 50 pixels wins. So in my example I have 48 rem and I have 100 viewport width, so the entire viewport.

And if the viewport width is smaller than 48 rem then we get 100 viewports. And that is whatever is currently the width of the viewport Like 500 or four eighty or three twenty, whatever. But if the viewport is larger, then we get 48 rem. And in my container style query, I'm basically saying, does 48 rem equal 48 rem? And that's only true if the viewport is larger.

Yeah. If the viewport is smaller then it doesn't equal 48 rem so the styles don't apply. But if it's 40 ms or larger then it's equal and this is how I apply these styles. One more thing, you have to register the custom property and that's it. I found it really cool. Hacking as hell but cool.

And yes, if if you want to see a really crazy demo then I suggest you go to CSS cafe tomorrow because Marco Christian Kren did a similar thing and he's going to show something that's really really wild. So it's definitely worth checking out. Alright, the last thing that I want to talk about is componentization because I didn't come up with the idea of using custom properties heavily. Of course, I was inspired by Leah because in a presentation here at CSSD I think almost ten years ago or something like that, she was talking about custom properties and how we are not getting enough out of them.

We're just using them in a very basic way. And this is why I tried using them very heavily. So that's what's happening here. And I'm also using it in my components because Lia said that custom properties with containers like Cypress may allow us to stop using presentational attributes in web components for example.

So stuff like color or size because instead we could just use the style attribute with our custom properties. Here's an example. So I have a card component here. There's a heading, some text, and an image. This is how it looks like. And if I want a larger variation, I use the style attribute. A bad practice. Or maybe not.

Why not? Why why not just use the style attribute and set card size to large? If I want a different variation of that, I just set dash dash card axis to x and then I get a different layout. Course, you don't have to use the style attribute. Can just use classes. Why not? It's not like I hate classes all of a sudden.

You just define a custom class and you change your settings. And what I really like about that is that you're not just randomly defining properties in CSS. You are working with a system that is already in place. You are not declaring, you're just configuring. And I really like the idea of having a config CSS file. There are many advantages but I'm slowly running out of time.

One of the advantages that I also see is the following. So let's say you have a container and inside the container you have four cards and you don't want them to have the default width but you want them to have a smaller width. You can select all of them and set dash dash card size to small or you just select the parent element because custom properties are inheritable. So if you set it on the parent element, the children will inherit from the parent.

And the big advantage here is that you don't have to predefine a class in your CSS that does that. You can just in a very flexible way just put your custom properties wherever you want and then the system does the rest. Cool. Yes. Everything I showed you is on an olliecss.com. It's not production ready because I'm playing around with this stuff.

I'm not sure if it will ever be production ready because a lot of that stuff is very experimental. And yeah, but you can still check it out if you want to. The code is also on Github. And until recently there was another reason why it wasn't ready for production which was browser support. But thankfully Firefox shipped it like three weeks ago with version 151.

So now we can use container style queries. And I was so motivated by that that I went onto my old website which looks horrible of course, but the content is fantastic. So I went on the website, I removed all the CSS, I added some configuration. It looks wild, I know, but you know I'm configuring my CSS and then I got this.

Which looks a bit broken but actually pretty cool because it didn't change much about the markup. I only Yeah. Added my CSS and added some config. But yeah. I changed some CSS, some more CSS, added the components here and there. And then I got this website which is now designed for my new website and I launched it just for CSS day. So you can check it out.

Everything that I showed you today is on this website. So I'm using containers style queries, all the flexible fluids type stuff as well. And yeah, you can see how it uses the fluid type and it's also accessible. You can check out my accessibility statement and see how I tested it. And yesterday during Brahmos' talk I actually also added new transitions.

Yeah. And here's an Easter egg, you can change the color. And it affects the entire website so you can see how the syntax highlighting is changing with the color. And this is just a single custom property. And oh there's my book. I wrote a book about accessibility for O'Reilly. And as it turns out I have a copy here.

And I'm giving it away. I have a really hard question. Who wants it? Who's that? I heard me somewhere here. You? Was it you? Who's that? You? Okay. If you are into front end developments and accessibility then I highly recommend this book. Can buy it anywhere.

Don't buy it on Amazon. My slides are online at matuzzo.at/cssday26 and it comes with a transcript of the entire talk because I care about you. Thank you so much.

That is fantastic. Thank you, Manuel. Join me, please. That is a great example how having your personal website is the best playground to experiment with the best CSS things out there.

Absolutely.

Please do it. And I'm gonna go dive straight in because we only have a few minutes. Mhmm. One of the questions touches something you just mentioned that you wish you had more time to mention, but you didn't. So because you were mentioning so the questions from Sara says, why use dash dash magic in custom properties rather than a class?

Generous curious, but also okay with you just having fun down the rabbit hole. And you were down the card examples, and you said, wish I had more time, so now you have the time.

Yeah. It's it's really about just seeing how far I can push push custom properties and see what we can do with them. And like I said, like the the the core idea was like having a config or or an API that I can configure instead of just redeclaring properties. This is also by one of the examples where I changed the layout. You you didn't see any margin auto or something like that.

All I'm doing is I'm changing custom properties everywhere. So I I try to not really clear any custom property, but really just change the Not really clear any regular property, but just change custom properties. No. It's just really experimentation and classes are fine. But I also really like the idea that building this website, I didn't think much about classes.

I just randomly picked the names. I didn't care about any convention because I only have a couple of them. The heavy lifting does dual custom properties and also the web components that I use.

Nice. Jesper asks, how do you identify habits of yours that need changing?

Yeah. That's a that's a interesting question. It just takes time. Just what works for me is just really diving deep deep into these topics and learning as much as possible about them and then just trying stuff out and seeing where you hit maybe limitations or where you have a situation like the one that I explained at the very beginning where you feel like that doesn't do anything.

It's very unlikely that it doesn't do anything or that there's no reason behind the thing. So just trying to explore it and and see. Yeah. Trying trying to to to forget what you learned, maybe. It's it's tough. Yeah. But it it took me three years to be able to talk. So yeah.

Sean asks, should we still call it a CSS reset? Feels like we are just setting better defaults, so base CSS or something else would make more sense.

Yes. I didn't mention the name of things, but I called my style sheets u UA plus. So u j user agent plus because I'm just, you know, improving the defaults. Yes. I agree.

Mhmm. Mattan asks, how would you combine layer with inline styles or abstract concepts like mixin?

What?

How would you combine at layer with inline styles or abstract cons conspects? I I think they mean concepts like Mixin.

I don't know. Next question.

Yep. Here we go. I have a question about supporting browsers without at layer support. Have you found a way to support these browsers or do you just drop the support for them? Roger said also adds love to talk.

Thank you. I think there is a post CSS plugin that can do that. But I just waited for the support to be great. And also it's my personal website. It's a website that mostly devs visit so your browsers are up to date and good enough. So that should be fine. And if the layers don't work, my HTML is fantastic.

It looks beautiful. So it just falls back to HTML, and HTML is pretty pretty cool.

Yes. Pretty good. Works really well. Asks, opinionated and massive better defaults are unique for every project unlike browser defaults. Do you find getting it it getting in the way when switching between projects?

It's hard to tell because I haven't used it in many projects yet. That's something that I could probably answer in a year or two I guess. I try to not to be too opinionated. Of course there are some things that are a bit opinionated in my reset stylesheet or base stylesheet improvements stylesheet plus thing. But it's just a CSS file.

Just remove stuff that you don't like. And yeah. But yeah. I can't answer that now.

Have you because you're mostly a freelancer and a teacher. But have you experienced pushbacks or friction when trying to bring these modern CSS techniques to establish a team that established routines and ways of doing things? And if so, how did you turn it around?

Not necessarily push back because they don't like it or because they can't use it because of browsers or what. But more because many of the teams that I work with when I consult, they live in a completely different reality than I do in terms of web development. Because I usually write everything from scratch or I reuse the things that I see and I try to get most the modern stuff.

And most teams that I work with just pick a component library and use that. And for them it's really hard to implement some of that stuff because they already have something that works and they are limited to whatever the component library provides. So this is the kind of pushback that I see. But people are usually very excited to see what's possible in browsers.

But in my experience, they immediately forget about it because they just can't use it anyway. Yeah. Yeah. Course, that's not true for every team, but at least most of the teams that I work with.

Yeah. And I and I reckon that, like you've mentioned, like you've done your own a hundred days of blog posts about CSS. We are all working our full time jobs. How do you have any advice on how to find the time to catch up with CSS and learn everything? Because there's a lot.

Everything? Yeah. No. I tried this 100 blog posts and it was such a horrible experience. Yeah. But but yeah. But but I did it. It worked and I learned a lot and a lot of people learned. For me it's pretty easy because I'm a freelancer. So I can just rearrange the my work time just the way I want it and just squeeze in a couple of hours.

But the best thing that works for me is really just writing blog posts on your personal website that you definitely need. This is my preferred way of of learning and also another way is to just speak at meetups for example, or at in house events, or if you have like an in house thing where you can present in front of your colleagues, that's also a good way of doing it. And you don't have to learn everything.

You just pick one thing and do a deep dive. There's a thing that Leonie Watson said about accessibility. She said it doesn't have to be perfect, just a little bit better than yesterday. And you can imply the same thing to learning CSS. You don't have to learn everything, but just pick one thing and you've learned one more thing.

Wow. That was beautiful.

Yeah. We'll get that transcript as well and put on stickers and all that. Yep. We don't have any more questions, which means we can break to launch soon. Thank you so much. Give a round of applause to both our speakers. Patrick and Manuel, thank you so much.

.css-day {
  date: 'June 11 & 12 2026';
  location: 'Amsterdam'
}
#identifier-sponsors {
  Google
  AG Grid
}
selector-sponsors {
  9ELEMENTS
  Polypane
}

Manuel Matuzović

Breaking with habits

Headshot of Manuel Matuzović.

LEG DAY

.now {

11:50 | Manuel Matuzović

Presentation slide with conference branding. A geometric CSS Day logo is in the top right. Sponsor logos for Google and AG Grid are in the bottom bar, along with an 'X' icon.

.now {

11:50 | Manuel Matuzović

11:50 | Manuel Matuzović

.now {

11:50 | Manuel Matuzović

.now {

11:50 | Manuel Matuzović

A schedule slide featuring the CSS DAY logo in the top right. A footer bar displays the Google logo and the AG Grid logo.

NOW SHOWING

BREAKING WITH HABITS

11:50 | Manuel Matuzović

Manuel Matuzovic, CSS Day, June 12th, 2026

BREAKING WITH HABITS

Manuel Matuzović, CSS Day, June 12th, 2026

BREAKING WITH HABITS

Manuel Matuzović, CSS Day, June 12th, 2026

A slide featuring a large white rectangular screen on the right side, displaying partial text. The rest of the slide area has a dark background.

That's not how I wrote CSS 3 years ago

matuzo.social

matuzo.at/cssday23

A presentation slide displaying an embedded YouTube video player. The video is paused on a frame from a previous presentation titled 'That's not how I wrote CSS 3 years ago', depicting a speaker on stage.

That's not how I wrote CSS 3 years ago

matuzo.social

matuzo.at/cssday23

Screenshot of an embedded YouTube video player displaying a previous presentation.

That's not how I wrote CSS 3 years ago

matuzo.social

matuzo.at/cssday23

Screenshot of a YouTube video player displaying a presentation slide titled "That's not how I wrote CSS 3 years ago" by Manuel Matuzović from CSS Day 2019.

That's not how I wrote CSS 3 years ago - Manuel Matuzović | CSS Day 2023

matuzo.at/cssday23

Screenshot of a YouTube video player displaying a presentation slide with the title "That's not how I wrote CSS 3 years ago".

That's not how I wrote CSS 3 years ago

That's not how I wrote CSS 3 years ago

Screenshot of a YouTube video player displaying a presentation slide with the title 'That's not how I wrote CSS 3 years ago'.

That's not how I wrote CSS 3 years ago - Manuel Matuzović | CSS Day 2023

matuzo.social

matuzo.at/cssday23

Screenshot of a YouTube video player displaying a presentation, paused on a slide titled "That's not how I wrote CSS 3 years ago".

That's not how I wrote CSS 3 years ago

matuzo.at/cssday23

Screenshot of a YouTube video player displaying a presentation. The video shows a speaker at a podium with 'CSS DAY' branding.

That's not how I wrote CSS 3 years ago

Screenshot of a YouTube video player showing a presentation with the title "That's not how I wrote CSS 3 years ago".

That's not how I wrote CSS 3 years ago

matuzo.at/cssday23

Screenshot of a YouTube video player showing a presentation slide with the title 'That's not how I wrote CSS 3 years ago'.

That's not how I wrote CSS 3 years ago

matuzo.at/cssday23

Screenshot of a YouTube video player displaying a presentation slide.

matuzo.social

That's not how I wrote CSS 3 years ago

matuzo.at/cssday23

A screenshot of a YouTube video player displaying a presentation slide with a speaker at a podium.

That's not how I wrote CSS 3 years ago

Screenshot of a YouTube video player showing a presentation titled 'That's not how I wrote CSS 3 years ago'.

BREAKING WITH HABITS

Manuel Matuzović, CSS Day, June 12th, 2026

BREAKING WITH HABITS

Manuel Matuzović, CSS Day, June 12th, 2026

BREAKING WITH HABITS

Manuel Matuzović, CSS Day, June 12th, 2026

Options for a Title

  • Breaking with Habits
  • Mental Health is more important than efficiency
  • Read. Learn. Grow.

BREAKING WITH HABITS

Manuel Matuzović, CSS Day, June 12th, 2026

MENTAL HEALTH > EFFICIENCY

Manuel Matuzović, CSS Day June 12th, 2026

READ

LEARN

GROW

Manuel Matuzović, CSS Day, June 12th, 2026

BEING GOOD AT CSS IS MORE IMPORTANT THAN EVER

Manuel Matuzović, CSS Day, June 12th, 2026

IT'S TIME TO REALLY LEARN CSS!

CSS cafe

matuzo.social

An image depicting a dark pink banner or bag. The banner features text related to learning CSS. The background behind the banner is blurred.

YOUR PROFOUND EXPERTISE MATTERS

Manuel Matuzović, CSS Day, June 12th, 2026

EXPLORE!

Manuel Matuzović, CSS Day, June 12th, 2026

  • Reset style sheets
  • Structure and organisation
  • Scalability
  • Reset style sheets
  • Structure and organisation
  • Scalability
  • Customisation
  • Componentisation
A list of five points, each presented within a distinct orange rectangular box, arranged diagonally from top-left to bottom-right on a white background.

matuzo.social

  • Reset style sheets
  • Structure and organisation
  • Scalability
  • Customisation
  • Componentisation

matuzo.social

Reset Style Sheets

reset.css by Eric Meyer

/* http://meyerweb.com/eric/tools/css/reset/
   v2.0 | 20110126
   License: none (public domain)
*/

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
	margin: 0;
	padding: 0;
	border: 0;
	font-size: 100%;
	font: inherit;
	vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
	display: block;
}
body {
	line-height: 1;
}
ol, ul {
	list-style: none;
}
blockquote, q {
	quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
	content: '';
	content: none;
}
table {
	border-collapse: collapse;
	border-spacing: 0;
}
A screenshot displaying the CSS code for Eric Meyer's CSS Reset stylesheet.

normalize.css by Nicolas Gallagher

/*! normalize.css v1.1.3 | MIT License | git.io/normalize */

/* ==========================================================================
   HTML5 display definitions
   ========================================================================== */

/**
 * Correct `block` display not defined in IE 6/7/8/9 and Firefox 3.
 */

article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section,
summary {
    display: block;
}

/**
 * Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3.
 */

audio,
canvas,
video {
    display: inline-block;
    *display: inline;
    *zoom: 1;
}

/**
 * Prevent modern browsers from displaying `audio` without controls.
 * Remove excess height in iOS 5 devices.
 */

audio:not([controls]) {
    display: none;
    height: 0;
}

normalize.css by Nicolas Gallagher

html {
	cursor: default;
	overflow-y: scroll;
	-webkit-tap-highlight-color: transparent;
	-webkit-text-size-adjust: none;
}
Screenshot of a code editor displaying normalize.css, with a dark overlay highlighting the CSS rule for `html` elements.

matuzo.social

html {
  cursor: default;
  overflow-y: scroll;
  -webkit-tap-highlight-color: transparent;
  -webkit-text-size-adjust: none;
}

normalize.css by Nicolas Gallagher

A code snippet showing CSS rules for the html element.
@charset "utf-8";
/***
 * The new CSS reset - version 1.8.5 (last updated 14.6.2023)
 * GitHub page: <a href="https://github.com/elad2412/the-new-css-reset">https://github.com/elad2412/the-new-css-reset</a>
 ***/

/*
 * Remove all the styles of the "User-Agent-Stylesheet", except for the 'display' property
 * - The "symbol *" part is to solve Firefox SVG sprite bug
 * - The "html" attribute is exclud, because otherwise a bug in Chrome breaks the CSS hyphens
 */
*:where(:not(html, iframe, canvas, img, svg, video, audio):not(svg *, symbol *)) {
	all: unset;
	display: revert;
}

/* Preferred box-sizing value */
*,
*::before,
*::after {
	box-sizing: border-box;
}

/* Reapply the pointer cursor for anchor tags */
a, button {
	cursor: revert;
}

/* Remove list styles (bullets/numbers) */
ol, ul, menu {
	list-style: none;
}
/* Box sizing rules */
*,
*::before,
*::after {
	box-sizing: border-box;
}

/* Prevent font size inflation */
html {
	-moz-text-size-adjust: none;
	-webkit-text-size-adjust: none;
	text-size-adjust: none;
}

/* Remove default margin in favour of better control in authored CSS */
body, h1, h2, h3, h4, p,
figure, blockquote, dl, dd {
	margin-block-end: 0;
}

/* Remove list styles on ul, ol elements with a list role, which sugges */
ul[role='list'],
ol[role='list'] {
	list-style: none;
}

/* Set core body defaults */
body {
	min-height: 100vh;
	line-height: 1.5;
}

/* Set shorter line heights on headings and interactive elements */
h1, h2, h3, h4,
button, input, label {
	line-height: 1.1;
}
/* balance text wrapping on headings */
h3, h4 {
	text-wrap: balance;
}

A (more) Modern CSS Reset by Andy Bell

Screenshot displaying CSS code for a modern CSS reset.
/* Box sizing rules */
*,
*::before,
*::after {
	box-sizing: border-box;
}

/* Prevent font size inflation */
html {
	-moz-text-size-adjust: none;
	-webkit-text-size-adjust: none;
	text-size-adjust: none;
}

/* Remove default margin in favour of better control in authored CSS */
body, h1, h2, h3, h4, p,
figure, blockquote, dl, dd {
	margin-block-end: 0;
}

/* Remove list styles on ul, ol elements with a list role, which sugges */
ul[role='list'],
ol[role='list'] {
	list-style: none;
}

/* Set core body defaults */
body {
	min-height: 100vh;
	line-height: 1.5;
}

/* Set shorter line heights on headings and interactive elements */
h1, h2, h3, h4,
button, input, label {
	line-height: 1.1;
}

/* Balance text wrapping on headings */
h3, h4 {
	text-wrap: balance;
}

A (more) Modern CSS Reset by Andy Bell

Screenshot of CSS code in a text editor showing a modern CSS reset stylesheet.

A (more) Modern CSS Reset by Andy Bell

/* Box sizing rules */
*,
*::before,
*::after {
  box-sizing: border-box;
}

/* Prevent font size inflation */
html {
  -moz-text-size-adjust: none;
  -webkit-text-size-adjust: none;
  text-size-adjust: none;
}

/* Remove default margin in favour of better control in authored CSS */
body, h1, h2, h3, h4, p,
figure, blockquote,
dl, dd {
  margin-block-end: 0;
  margin-block-start: 0;
}

/* Remove list styles on ul, ol elements with a list role, which sugges */
ul[role='list'],
ol[role='list'] {
  list-style: none;
}

/* Set core body defaults */
body {
  min-height: 100vh;
  line-height: 1.5;
}

/* Set shorter line heights on headings and interactive elements */
h1, h2, h3, h4,
button, input, label {
  line-height: 1.1;
}

/* Balance text wrapping on headings */
h1, h2, h3, h4 {
  text-wrap: balance;
}
A section of CSS code is highlighted within a purple box, specifically the `body` rule that sets `min-height` to `100vh` and `line-height` to `1.5`.
*,
*::after,
*::before {
	box-sizing: border-box;
}
label:has(
  + :where(
    input:not([[type="radio"], [type="checkbox"]]), select, textarea)
  ) {
  display: block;
}

matuzo.so

label:has(
  + :where(
    input:not(([type="radio"], [type="checkbox"]), select, textarea)
  )
) {
  display: block;
}

Modern CSS Selector Example

label:has(
	+ :where(
		input:not(([type="radio"], [type="checkbox"])), select, textarea)
	) {
	display: block;
}

matuzo.social

A screen displaying a CSS code snippet that uses the `:has()` and `:where()` pseudo-classes to style `label` elements. The code applies `display: block;` to a label if it contains an input field (excluding radio and checkbox types), a select element, or a textarea. Below the code, an example shows the text label "Name" positioned above an empty text input field, demonstrating the effect of the CSS which makes the input field appear on a new line below the label.

matuzo.social

label:has(
  + :where(
    input:not([type="radio"], [type="checkbox"]), select, textarea
  )
) {
  display: block;
}
A screenshot of a presentation slide displaying a CSS code snippet. Below the code, there is a simple web form element showing the label "Name" immediately to the left of an empty text input box, illustrating the default inline display behavior of these elements.
label:has(
  + :where(
    input:not([type="radio"], [type="checkbox"]), select, textarea
  )
) {
  display: block;
}
label:has(
  + :where(
    input:not([[type="radio"], [type="checkbox"]]), select, textarea
  )
) {
  display: block;
}
Two examples of a 'Name' label and input field. In the first example, the label and input are inline. In the second example, the label is positioned above the input field.

Interactive content

Screenshot of a web page from oli.css demonstrating interactive elements like dialogs and popovers.

Interactive content

Screenshot of a web page titled 'Interactive content' within a browser window, featuring sections for interactive elements like 'Details', 'Dialog', and 'Popover', and displaying an 'oli.css' logo.

Interactive content

Screenshot of a web page titled 'Interactive content' from 'oli.css', demonstrating interactive HTML elements. A modal dialog is open in the center of the page, titled 'A modal dialog', containing descriptive text and a 'CLOSE' button. A mouse cursor is pointing to the 'CLOSE' button.

Interactive content

This page is built using the following elements: details, summary, dialog, and others.

Details

There's more

Dialog

SHOW MODAL

Popover

SHOW POPOVER

built by matuzo in Graz

Screenshot of a web browser displaying a demo page from oli.css. The page, titled "Interactive content", features the oli.css logo with an olive branch icon, and navigation links for Demos, Docs, and Download. It demonstrates a "Details" section with a "There's more" summary, a "Dialog" section with a "SHOW MODAL" button, and a "Popover" section with a "SHOW POPOVER" button. A faint olive branch pattern is visible in the background.

Interactive content

Screenshot of the oli.css website, showcasing interactive content elements like details, dialogs, and popovers. A purple cursor is positioned over the 'SHOW MODAL' button. The webpage has a subtle green leaf pattern in the background.

Interactive content

This page is built using the following elements: details, summary, dialog, and others.

oli.css

  • DEMOS
  • DOCS
  • DOWNLOAD

Details

  • There's more

Dialog

Popover

built by matuzo in Graz

Screenshot of a web browser displaying a page titled "Interactive content" from oli.css. The page demonstrates interactive web elements including a details disclosure, a dialog with a "SHOW MODAL" button, and a popover with a "SHOW POPOVER" button. A purple mouse cursor hovers over the "SHOW MODAL" button. The webpage features a subtle background image of foliage.

A modal dialog

Screenshot of a web page displaying a modal dialog box. The modal has a title "A modal dialog", descriptive text, and a "CLOSE" button which a mouse cursor is hovering over.
dialog,
dialog::backdrop {
	opacity: 0;
	transition: opacity 150ms ease-out,
				display 150ms allow-discrete,
				overlay 150ms allow-discrete;
}

dialog[open],
dialog[open]::backdrop { opacity: 1; }

@starting-style {
	dialog[open],
	dialog[open]::backdrop { opacity: 0; }
}

oli.css

Interactive content

This page is built using the following elements: details, summary, dialog, and others.

Details

► There's more

Dialog

Popover

built by matuzo in Graz

Screenshot of a web browser displaying the "Interactive content" page of the oli.css website. The website's header includes an olive branch icon next to the "oli.css" text. The page features a faint olive branch illustration in the background. The main content demonstrates HTML interactive elements, including a "Details" section with a "There's more" toggle, a "Dialog" section with a "SHOW MODA" button, and a "Popover" section with a "SHOW POPOVER" button. A purple mouse pointer is shown hovering over the "SHOW MODA" button, indicating an interaction point.

A modal dialog

Screenshot of a web browser displaying a demo page titled "Interactive content". A modal dialog, also titled "A modal dialog", is open in the center, overlapping the main page content. The modal contains a paragraph of text and a 'CLOSE' button in the top right corner.

Interactive content

This page is built using the following elements: details, summary, dialog, and others.

Details

▶ There's more

Dialog

SHOW MODAL

Popover

SHOW POPOVER

built by matuzo in Graz

Screenshot of a web page from oli.css demonstrating interactive content elements including details, dialog, and popover. The page features the oli.css logo and a subtle light green leaf background image.

Interactive content

Screenshot of a web browser displaying a page titled 'Interactive content' from 'oli.css', showcasing interactive UI elements including details, a modal dialog, and a popover. A popover is currently open, displaying the text 'I'm just popping over to show you how I look by default...'.
button {
  anchor-name: --the-button;
}

div {
  position-anchor: --the-button;
  position-area: end span-end;
  position: absolute;
}

matuzo.social

@supports(position-area: end) {
  [popover] {
    margin: 0;
    position-area: end span-end;
    position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;
  }
}

Interactive content

Screenshot of a web browser displaying a web page for 'oli.css' titled "Interactive content", featuring sections for details, dialog, and popover examples. The popover example shows a "SHOW POPOVER" button with a popover element open below it containing the text "I'm just popping over to show you how I look by default...".

Interactive content

A web browser displaying a page titled "Interactive content - oli.css" from localhost. The page content includes sections for "Details", "Dialog" with a "SHOW MODAL" button, and "Popover" with a "SHOW POPOVER" button and an open popover stating "I'm just popping over to show you how I look by default...". The browser's developer tools are open on the right, showing the HTML structure in the Elements panel and CSS styles for the body in the Styles panel.
@layer uaplus-reset-styles {
  *,
  *::after,
  *::before {
    box-sizing: border-box;
  }
  ...
}
@layer uaplus-reset-styles {
  *,
  *::after,
  *::before {
    box-sizing: border-box;
  }
}
@layer uaplus-reset-styles {
	*,
	*::after,
	*::before {
		box-sizing: border-box;
	}
	...
}

matuzo.social

@layer uaplus-reset-styles {
  *,
  ::after,
  ::before {
    box-sizing: border-box;
  }
}

matuzo.social

@layer uaplus-reset-styles {
	*,
	*::after,
	*::before {
		box-sizing: border-box;
	}

	...
}

UA+

Screenshot of a webpage for the UA+ tool on fokus.dev.

UA+

Screenshot of a webpage from fokus.dev/tools/uaplus displayed within a browser window. The browser tab is labeled "uaaplus.css | fokus". The page content includes a header with a "fokus" logo, navigation links "TOOLS SNIPPETS ABOUT", and a main section titled "UA+". This section provides a description of "UA+", a CSS reset stylesheet, followed by "Download" and "GitHub" buttons. Further sections are titled "Who is this for?", "Demo", and "Breakdown". A mouse cursor is visible on the page.

Breakdown

Here's a detailed breakdown of the entire file.

Different box model

We use the traditional box model, where the padding and border of the element is drawn inside and not outside the specified width and height. That makes combining relative and absolute units in properties like inline-size and block-size easier.

*,
*::after,
*::before {
	box-sizing: border-box;
}

See the box model page on wikipedia for details.

Improve focus styles

Add spacing between content and its focus outline.

:focus-visible {
	outline-offset: 3px;
}

Disable text size adjustment

To improve readability on non-mobile optimized websites, browsers like mobile Safari increase the default font size when you switch a website from portrait to landscape. We don't want that for our optimized sites.

Screenshot of a web browser displaying a page from fokus.dev/tools/uaplus, which details CSS styling techniques. At the bottom left of the slide, a prominent red rectangle displays the URL "fokus.dev/tools/uaplus".

Read Your CSS reset needs text-size adjust (probably) by Kilian Valkhof for details.

Screenshot of the fokus.dev/tools/uaplus webpage, displayed within a browser window, showing various CSS styling and reset recommendations with code examples.

UA+

UA+ (User agent plus) is a different type of reset style sheet. Instead of mostly resetting and normalizing properties, we focus on improving existing user agent styles and adding new styles only where browsers fall short.

Please note that this project is still in the early alpha phase. Feedback is highly appreciated.

Download GitHub

Who is this for?

UAplus is for anyone who wants a better baseline for their style sheets. It does more than other reset style sheets but less than most. Most importantly, we try not to be too opinionated and reset too much. We also take accessibility more into consideration than many others.

Demo

Visit our demo pages to compare your browsers' default styles with our improved ones. Please note that the differences are often barely noticeable. That's because we like the default styles and only help out browsers where needed.

Demo

Breakdown

Here's a detailed breakdown of the entire file.

Different box model

We use the traditional box model, where the padding and border of the element is drawn

Built with Eleventy in Graz by Matuzo

fokus.dev/tools/uaplus

Screenshot of the fokus.dev website displaying information about the UA+ reset stylesheet, within a browser window showing the URL fokus.dev/tools/uaplus. A social media handle 'matuzo.social' is visible at the top right of the slide.

UA+ playground

Screenshot of the "UA+ playground" web application on fokus.dev, displaying a list of HTML elements on the left and a main content area that describes the tool and lists elements not included in its tests.

fokus.dev: Input Element Demo

fokus.dev/tools/uaplus
Screenshot of a web application on fokus.dev showing a comparison of HTML input element styles. The left sidebar lists various HTML elements, with `` currently selected. The main content area displays examples of text input fields in different states, such as default, with an implicit label, with a default value, with a placeholder, with a specific size, disabled, and aria-disabled. Dropdown menus at the top suggest choosing different stylesheets for comparison.

fokus.dev: <input> Element Styles Demo

Screenshot of the fokus.dev web application, a tool for comparing CSS reset stylesheets. The main content area displays different styling variations for the HTML <input> element, including default, with implicit label, with default value, with placeholder, with size, disabled, aria-disabled, readonly, datalist, and with autocomplete attributes. A sidebar lists other HTML form and tabular elements. Dropdowns at the top right allow selecting different CSS reset styles to apply.

<input>

fokus.dev/tools/uaplus
A screenshot of the fokus.dev web application, specifically the /tools/uaplus page, which demonstrates various styling and states for HTML input fields.

Structure and Organisation

Structure and Organisation

A slide with the main heading 'Structure and Organisation' framed by two horizontal orange lines.

Structure and Organisation

Two horizontal red lines frame the heading, one above and one below.

Structure and Organisation

matuzo.social

ITCSS by Harry Roberts

  • SETTINGS
  • TOOLS
  • GENERIC
  • ELEMENTS
  • OBJECTS
  • COMPONENTS
  • UTILITIES

matuzo.social

Diagram of an inverted pyramid illustrating the ITCSS (Inverted Triangle CSS) architecture. The pyramid is divided into seven horizontal layers, representing different levels of CSS specificity and organization, from most generic at the top to most specific at the bottom. The layers are labeled: Settings, Tools, Generic, Elements, Objects, Components, and Utilities.

ITCSS by Harry Roberts

  • SETTINGS
  • TOOLS
  • GENERIC
  • ELEMENTS
  • OBJECTS
  • COMPONENTS
  • UTILITIES
Diagram of an inverted pyramid illustrating the ITCSS architecture, with layers labeled from top to bottom as Settings, Tools, Generic, Elements, Objects, Components, and Utilities.

ITCSS by Harry Roberts

ITCSS Layers (Inverted Triangle)

  • SETTINGS
  • TOOLS
  • GENERIC
  • ELEMENTS
  • OBJECTS
  • COMPONENTS
  • UTILITIES

CSS At-Rule Examples

  • @layer
  • @property
  • @font-face
A diagram illustrating the ITCSS (Inverted Triangle CSS) architecture as an inverted pyramid, divided into seven horizontal layers.

ITCSS by Harry Roberts

  • SETTINGS
  • TOOLS
  • GENERIC
  • ELEMENTS
  • OBJECTS
  • COMPONENTS
  • UTILITIES
@layer
@property
@font-face

*{}

p{}
button{}

matuzo.social

An inverted pyramid diagram representing the ITCSS (Inverted Triangle CSS) methodology. It is divided into layers from top to bottom: SETTINGS, TOOLS, GENERIC, ELEMENTS, OBJECTS, COMPONENTS, and UTILITIES. To the right, CSS examples (`@layer`, `@property`, `@font-face`, `*{}`, `p{}`, `button{}`) are aligned, visually corresponding to specific layers of the pyramid.

matuzo.social

ITCSS by Harry Roberts

SETTINGS
@layer @property @font-face
TOOLS
GENERIC
* {}
ELEMENTS
p {} button {}
OBJECTS
.card
COMPONENTS
[aria-current=page] #header
UTILITIES
.is-hidden !important
An inverted pyramid diagram, divided into seven horizontal layers, illustrating the ITCSS (Inverted Triangle CSS) architecture. Each layer is labeled on the left with its name, and corresponding CSS examples are listed on the right, demonstrating increasing specificity from top to bottom.

ITCSS by Harry Roberts

matuzo.social

@layer
@property
@pronerty
@f
div#button {
  background: red !important
}
*{}
p{}
button{}
.card
[aria-current=page]
#header
.is-hidden !important

An annotation highlights the rule div#button { background: red !important } with red, angled text, emphasizing the use of !important.

/* Establish the order of layers upfront */
@layer core, third-party, components, utility;
/* Establish the order of layers upfront */
@layer core, third-party, components, utility;

matuzo.social

matuzo.social

/* Establish the order of layers upfront */
@layer core, third-party, components, utility;
/* Establish the order of layers upfront */
@layer core, third-party, components, utility;
@layer core.reset, core.tokens, core.base;
@layer third-party.imports, third-party.overrides;
@layer components.base, components.variations;

matuzo.social

/* Establish the order of layers upfront */
@layer core, third-party, components, utility;
@layer core.reset, core.tokens, core.base;
@layer third-party.imports, third-party.overrides;
@layer components.base, components.variations;

/* Reset, normalize, etc. */
@import url('uaplus.css') layer(core.reset);
/* Establish the order of layers upfront */
@layer core, third-party, components, utility;
@layer core.reset, core.tokens, core.base;
@layer third-party.imports, third-party.overrides;
@layer components.base, components.variations;

/* Reset, normalize, etc. */
@import url('uaplus.css') layer(core.reset);
/* utilities.css */
@layer utility {
	.visually-hidden {
		clip: rect(0 0 0 0);
		clip-path: inset(50%);
		height: 1px;
		overflow: hidden;
		position: absolute;
		white-space: nowrap;
		width: 1px;
	}
}

matuzo.social

/* components/card.css */

@layer components {
  @layer base {
    .card {
      --size: 20rem;
      max-inline-size: var(--size);
    }
  }
}

@layer variations {
  .card-large {
    --size: 30rem;
  }
}
/* Establishes the order of layers upfront */
@layer core, third-party, components, utility;

matuzo.social

/* Establishes the order of layers upfront */
@layer core, third-party, components, utility;
/* Establishes the order of layers upfront */
@layer core, third-party, components, utility;

matuzo.social

Inverted Pyramid of CSS Layers

  • CORE
  • THIRD-PARTY
  • COMPONENTS
  • UTILITY
A diagram showing four stacked, orange rectangular blocks, forming an inverted pyramid. Each block is labeled with a CSS layer name, illustrating a hierarchical structure where the layers at the bottom override those above them.

Inverted Pyramid Layer Structure

  • CORE
  • THIRD-PARTY
  • COMPONENTS
  • UTILITY
A diagram showing an inverted pyramid made of four stacked horizontal blocks, decreasing in width from top to bottom. The blocks are labeled from top to bottom: CORE, THIRD-PARTY, COMPONENTS, and UTILITY.

Inverted Pyramid Structure

  • CORE
    • RESET
    • TOKENS
    • BASE
  • THIRD-PARTY
    • IMPORTS
    • OVERRIDES
  • COMPONENTS
    • BASE
    • VARIATIONS
  • UTILITY

matuzo.social

A diagram illustrating a hierarchical structure resembling an inverted pyramid or funnel, divided into major categories of CORE, THIRD-PARTY, COMPONENTS, and UTILITY. Each major category, except UTILITY, contains sub-categories such as RESET, TOKENS, BASE under CORE; IMPORTS, OVERRIDES under THIRD-PARTY; and BASE, VARIATIONS under COMPONENTS.

cts of any size.

GitHub

Proceed to the FAQ.

/* layers upfront */
components, utility;
tokens, core.base;
third-party.overrides;
components.variations;

@layer(core.reset);

/* styles */

A screenshot showing a code editor with CSS-like code defining cascade layers.

GitHub

Proceed to the FAQ.

/* layers upfront */
components, utility;
tokens, core.base;
third-party.overrides;
components.variations;

/*
layer(core.reset);
/*
es */
Screenshot of a code editor displaying CSS/SCSS code for component layering, with a 'GitHub' button and a 'Proceed to the FAQ' heading.

Questions (FAQ)

Boilerplate?

Boilerplate is one or more CSS files you want to include in your project. For some, this is just a reset style sheet; for others, it also contains a more complete set of base styles.

Boilerplate is one or more CSS files you want to include in your project. For some, this is just a reset stylesheet; for others, it also contains base styles.

Boilerplate uses a reset stylesheet and comes with pre-established structure using Cascade Layers, giving you...

What's in it for me?

  • Main layers.
  • Custom properties and base styles.
  • Global custom properties for the entire site. Base styles are standard styles you use for the site.
/*
layer(core.reset);
*/

/* Base styles */
/*
layer(core.reset);

styles */

  0.97 0.01 0);
.22 0.01 0);

  (--color-light);
rk);
a, sans-serif;

put the global custom properties into a dedicated layer. use styles into a dedicated layer. They override layered

Screenshot of a code editor displaying CSS code.

performance?

shouldn't use @import in 2009. The browser landscape have changed a lot since then. Chris Ferdinandi and recently, and they both found that importing is still conclusions were very different. For Chris, 300ms extra necessarily a deal breaker; for Erwin, it is. So, I don't know today. All I know is that browsers all agreed to improve element head when they released layers so, I don't know and share my findings here.

styles in a third-party

override them. Why?

@layer components, utility;
@layer tokens, core.base;
@layer important, third-party.imports, third-party.overrides;
@layer components.variations;

@layer third-party.imports;
  important {
...

reset stylesheet?

could. This site is the first to use this boilerplate, but I this year. I'll list them here.

boilerplates?

g posts:

Code editor screenshot displaying CSS layer declarations and a partial CSS rule `important {`.
core, third-party, components, utility;
core, reset, dark, tokens, core.base;
layer third-party.very-important, third-party.imports, third-party.overrides,
third-party.base, components.variations;
@import "url('prism.css')" layer(third-party.imports);
layer third-party.very-important {
  language-css .token {
    color: red !important;
  }
}

Can I use a different reset stylesheet?

Yes, absolutely

Does it scale?

Uhm... I don't know yet, but it should. This site is the first to use this boilerplate, but I plan to use it on more sites later this year. I'll list them here.

Are there other similar boilerplates?

Not that I know, but there are blog posts

  • A Whole Cascade of Layers by Miriam Suzanne
  • New Year, New Site by Adam Argyle

Where can I learn about cascade layers?

  • Cascade Layers Guide by Miriam Suzanne on CSS-Tricks
  • The CSS Cascade: a deep dive (YouTube) by Bramus Van Damme at CSS Day 2022
  • Hello, CSS Cascade Layers by Ahmad Shadeed
  • Cascade Layers are awesome! by Manuel Matuzović
A screenshot of the matuzo.social website, displaying an FAQ section related to CSS boilerplates and cascade layers, including a CSS code example.

Scalability

Handbuch wien.gv.at

Screenshot of the Handbuch wien.gv.at website, displaying its homepage within a browser window.

Handbuch wien.gv.at

Screenshot of the Handbuch wien.gv.at website, displaying its homepage with sections like 'Bevor Sie starten', 'Pattern Library', and 'Farben'.

Handbuch wien.gv.at

Screenshot of the Handbuch wien.gv.at website, displaying its homepage with various sections like "Pattern Library" and "Colors" visible.

Handbuch wien.gv.at

Screenshot of the Handbuch wien.gv.at website showing its homepage with sections like "Entdecken Sie das Handbuch" (Discover the Handbook) and links to "Pattern Library" and "Farben" (Colors).

Handbuch wien.gv.at

Das Handbuch wien.gv.at ist die Arbeitsgrundlage für alle Web-Angebote der Stadt und wurde im Zuge des neuen Corporate Designs umgesetzt.

Es ist die Weiterentwicklung des Styleguides wien.gv.at, löst diesen ab und ist verbindlich für alle wien.gv.at-Projekte.

Bis 2024 wurden Projekte mit der ersten Version des Handbuchs umgesetzt, die nicht mehr gewartet wird, aber für diese Projekte noch zur Verfügung steht.

Entdecken Sie das Handbuch

Bevor Sie starten

So nutzen Sie dieses Handbuch.

Pattern Library

Eine Übersicht aller Web-Elemente für wien.gv.at.

Farben

Eine Übersicht der möglichen Farben und Farbkombinationen.

Anwendungsbeispiele

Pilotprojekte und Musterseiten, die als Orientierung dienen können.

Redaktionelle Richtlinien

Grundlagen für Redakteur*innen, um nützliche und verständliche Inhalte zu erstellen.

Anforderungen für Devs

Einstieg für alle IT-Verantwortlichen und Entwickler*innen.

A screenshot of the "Handbuch wien.gv.at" website, which serves as a style guide and handbook for the city of Vienna's web offerings. The website interface displays a main heading, navigation tabs, descriptive text about the handbook's purpose, and a grid of six content cards for different sections like Pattern Library, Colors, and Requirements for Devs.

Handbuch wien.gv.at

Screenshot of the Handbuch wien.gv.at website, showing its homepage with navigation, an introductory text, and cards linking to different sections like Pattern Library and Colors.
h1 {
	font-size: 51px;
}

h2 {
	font-size: 40px;
}

h3 {
	font-size: 32px;
}
...

matuzo.social

h1 {
	font-size: 51px;
}

h2 {
	font-size: 40px;
}

h3 {
	font-size: 32px;
}
...

Precise Type Tool

Screenshot of the Precise Type web application, a type scale tool displaying modular type scales. It shows input fields for base font size, line height, letter spacing, and a scale (e.g., Major Third), along with calculated font sizes, line heights, and letter spacings for various modular type scales, from 64px down to 13px.
:root {
  --scale: 1.26;
  --base: 1rem;

  --h6: var(--base); /* 16px */
  --h5: calc(var(--h6) * var(--scale)); /* 20px */
  --h4: calc(var(--h5) * var(--scale)); /* 25px */
  --h3: calc(var(--h4) * var(--scale)); /* 32px */
  --h2: calc(var(--h3) * var(--scale)); /* 40px */
  --h1: calc(var(--h2) * var(--scale)); /* 51px */
}
:root {
  --scale: 1.26;
  --base: 1rem;

  --h6: var(--base);
  --h5: calc(var(--base) * var(--scale));
  --h4: calc(var(--base) * var(--scale) * var(--scale));
  --h3: calc(var(--base) * var(--scale) * var(--scale) * var(--scale));
  --h2: calc(var(--base) * var(--scale) * var(--scale) * var(--scale) * var(--scale));
  --h1: calc(var(--base) * var(--scale) * var(--scale) * var(--scale) * var(--scale) * var(--scale));
}

Math.pow()

Screenshot of the MDN Web Docs page for the JavaScript `Math.pow()` method.

Math.pow()

Screenshot of the MDN Web Docs website showing the documentation for the JavaScript `Math.pow()` method, including its definition and a "Try it" code editor with examples.
:root {
  --scale: 1.26;
  --base: 1rem;

  --h6: calc(var(--base) * pow(var(--scale), 0));
  --h5: calc(var(--base) * pow(var(--scale), 1));
  --h4: calc(var(--base) * pow(var(--scale), 2));
  --h3: calc(var(--base) * pow(var(--scale), 3));
  --h2: calc(var(--base) * pow(var(--scale), 4));
  --h1: calc(var(--base) * pow(var(--scale), 5));
}

h1 { font-size: var(--h1); }
h2 { font-size: var(--h2); }
h3 { font-size: var(--h3); }
h4 { font-size: var(--h4); }
h5 { font-size: var(--h5); }
h6 { font-size: var(--h6); }
:root {
  --scale: 1.26;
  --base: 1rem;
}

h1, h2, h3, h4, h5, h6 {
  font-size: calc(var(--base) * pow(var(--scale), var(--font-factor, 0)));
}

h1 { --font-factor: 5; }
h2 { --font-factor: 4; }
h3 { --font-factor: 3; }
h4 { --font-factor: 2; }
h5 { --font-factor: 1; }

matuzo.social

:root {
  --scale: 1.26;
  --base: 1rem;
}

h1, h2, h3, h4, h5, h6 {
  font-size: calc(var(--base) * pow(var(--scale), var(--font-factor, 0)));
}

h1 { --font-factor: 5; }
h2 { --font-factor: 4; }
h3 { --font-factor: 3; }
h4 { --font-factor: 2; }
h5 { --font-factor: 1; }

matuzo.social

:root {
  --scale: 1.26;
  --base: 1rem;
}

*, ::after, ::before {
  font-size: calc(var(--base) * pow(var(--scale), var(--font-factor, 0)));
}

h1 { --font-factor: 5; }
h2 { --font-factor: 5; }
h3 { --font-factor: 3; }
h4 { --font-factor: 2; }
h5 { --font-factor: 1; }
.big { --font-factor: 10; }
.small { --font-factor: -1; }

:root {
  --scale: 1.26;
  --base: 1rem;
}

*, ::after, ::before {
  font-size: calc(var(--base) * pow(var(--scale), var(--font-factor, 0)));
}

h1 { --font-factor: 5; }
h2 { --font-factor: 5; }
h3 { --font-factor: 3; }
h4 { --font-factor: 2; }
h5 { --font-factor: 1; }
.big { --font-factor: 10; }
.small { --font-factor: -1; }
  

matuzo.social

:root {
  --scale: 1.26;
  --base: 1rem;
}

*, ::after, ::before {
  font-size: calc(var(--base) * pow(var(--scale), var(--font-factor, 0)));
}

h1 { --font-factor: 5; }
h2 { --font-factor: 5; }
h3 { --font-factor: 3; }
h4 { --font-factor: 2; }
h5 { --font-factor: 1; }
.big { --font-factor: 10; }
.small { --font-factor: -1; }
:root {
  --scale: 1.26;
  --base: 1rem;
}

*, ::after, ::before {
  --_type-power: pow(var(--scale), var(--font-factor, 0));
  --_type-scale-formula: calc(var(--base) * var(--_type-power));
  font-size: var(--font-size, var(--_type-scale-formula));
}

.big { --font-factor: 10; }
.small { --font-factor: -1; }
.custom { --font-size: 2rem; }

Type Scale in CSS

matuzo.at/type-scale

Screenshot of a web application demonstrating a type scale, featuring controls for adjusting 'Scale' and 'Base Font size' via range sliders, and displaying various text sizes for "Heading 1" through "Heading 6", "big", "small", and "custom" labels.

Type Scale in CSS

matuzo.at/type-scale
A web browser displaying a type scale tool with sliders to adjust scale and base font size, and examples of various heading levels and custom text demonstrating the changes.

Type Scale in CSS

matuzo.at/type-scale
Screenshot of a web application interface. At the top of the interface, there are two horizontal range sliders labeled "Scale" and "Base Font size". Below these controls, various text elements are displayed, including "Heading 1" through "Heading 6", "big", "small", and "custom", demonstrating how font sizes are affected by the scale settings.

Type Scale in CSS

Screenshot of a web browser demonstrating a type scale, with sliders for 'Scale' and 'Base Font size' controlling the sizes of headings and other text elements. A mouse cursor hovers over the 'Base Font size' slider.

Type Scale in CSS

Screenshot of a web application demonstrating a type scale in CSS. The application shows two sliders for adjusting 'Scale' and 'Base Font size', and displays text examples like 'Heading 1' through 'Heading 6', 'big', 'small', and 'custom' to illustrate the resulting font sizes. A purple arrow indicates interaction with the 'Base Font size' slider.

matuzo.at/type-scale

Screenshot of a web browser displaying a demonstration page. The page shows various heading sizes from "Heading 1" down to "Heading 5", followed by the word "big" and "custom", illustrating a type scale. The browser tab displays "matuzo.social".

matuzo.at/type-scale

Screenshot of a web-based type scale tool within a browser window. The application interface displays a sidebar with options like 'Base', 'ratio', and various headings (1-6), with 'matuzo.social' visible in the browser's header area.

MIN VIEWPORT

Width

320 px

Font size

px

A user interface panel displaying settings for minimum viewport. It shows an input field for "Width" with the value "320 px", and an input field for "Font size" which is empty, followed by "px".

CLAMP CALCULATOR

A screenshot of the Utopia website's Clamp Calculator tool, displaying input fields for minimum and maximum viewport settings (width, font size, type scale) and an interactive visualization slider for fluid value tokens.
--scale: 1.26;
--base: 1rem;

--1to10range: clamp(0.0625rem, -0.125rem + 0.9375vw, 0.625rem);
--1to10: tan(atan2(var(--1to10range), 1px));
}
A white arrow points to the line defining the `--1to10range` CSS custom property.

MIN VIEWPORT

  • Width: 320 px
  • Font size: [empty input field] px
  • Type scale: [empty input field] px

MAX VIEWPORT

  • Width: 1280 px
  • Font size: [empty input field] px
  • Type scale: [empty input field] px
A configuration panel showing input fields for minimum and maximum viewport settings.

CLAMP CALCULATOR

Screenshot of a web-based calculator interface. It features two sections, 'MIN VIEWPORT' and 'MAX VIEWPORT', each with fields for Width, Font size, and Type scale. The minimum width is set to 320px and maximum to 1280px. Below these, there is a visualization section with input fields labeled '@min' (set to 1) and '@max' (set to 10), and a slider visually demonstrating a fluid value from 1px to 10px.
:root {
  --scale: 1.26;
  --base: 1rem;

  --1to10range: clamp(0.0625rem, -0.125rem + 0.9375vw, 0.625rem);
  --1to10: tan(atan2(var(--1to10range),1px));
}

h1 {
  --font-factor: var(--1to10);
}
A white arrow points to the line defining the CSS custom property `--1to10range` within the `:root` block.
:root {
  --scale: 1.26;
  --base: 1rem;

  --1to10range: clamp(0.0625rem, -0.125rem + 0.9375vw, 0.625rem);
  --1to10: tan(atan2(var(--1to10range),1px));
}

h1 {
  --font-factor: var(--1to10);
}
A white arrow points to the CSS custom property definitions for `--1to10range` and `--1to10` within the `:root` selector.
@property --1to10range {
  syntax: "<length>";
  initial-value: 0px;
  inherits: false;
}

bitterballen

Screenshot of a web browser displaying a webpage with the text "bitterballen" and the browser's developer tools open, showing the HTML structure and CSS styles.

bitterballen

Screenshot of a web browser displaying the word 'bitterballen' with developer tools open on the right, showing the HTML structure and CSS styles.
<!DOCTYPE html>
<html lang="en">
	<head> </head>
	<body>
		<h1>bitterballen</h1>
	</body>
</html>
*, ::after, ::before {
	--type-power: pow(var(--scale),
		var(--font-factor), 0);
	--type-scale-formula: calc(var(--base)

bitterballen

Screenshot of a web browser displaying a webpage with the word "bitterballen" in a large font, with developer tools open on the right showing the HTML and CSS for the element.

bitterballen

Screenshot of a Chrome web browser displaying a webpage with the heading 'bitterballen'. The browser's developer tools are open on the right, showing the HTML structure for the heading and CSS styles related to font sizing and custom properties.

Manuel Matuzovic's Website

Screenshot of Manuel Matuzovic's personal website, matuzo.at, shown in a web browser. The page displays the website's logo "MATUZO VÍC", a black and white photo of Manuel, and the main heading "That's me and this is my website.".

← That's me and this is my website.

Screenshot of the matuzo.at website, featuring a profile picture, name and title, navigation links, and a large heading.

Firefox Browser Settings: General

A screenshot of the Firefox browser's settings page, specifically the "General" section, displaying options for size, zoom, language, translations, and spell check.

Settings

Screenshot of the Firefox browser displaying its settings page. An arrow points to the 'Zoom text only' checkbox, which is checked, and the 'Default zoom' dropdown set to 100%.

That's me and this is my website.

Screenshot of a website, matuzo.at, displayed in a web browser. The website features a black and white profile picture of a man, the name "MATUZO VIĆ", and a description "FRONT-END / A11Y / HTML / CSS". Navigation links for HOME, BLOG, and ABOUT ME are visible below the image. An arrow points from the descriptive text "That's me and this is my website." towards the profile picture on the website.

How to prevent large headings

Use this formula to reduce the rate of scaling

font size × (rate of increase × (preferred text scale - 1) + 1)

@function --font-size-scaling-rate(--font-size <length>, --scaling-rate <number>) {
  result: calc(var(--font-size) + (var(--scaling-rate) * (env(preferred-text-scale) - 1) + 1));
}

h1 {
  font-size: --font-size-scaling-rate(3rem, 0.5);
}

@joshtomath.uk

How to prevent large headings

Use this formula to reduce the rate of scaling

font size × (rate of increase × (preferred text scale - 1) + 1)

@function --font-size-scaling-rate(--font-size <length>, --scaling-rate <number>) {
  result: calc(var(--font-size) * (var(--scaling-rate) * (env(preferred-text-scale) - 1) + 1));
}

h1 {
  font-size: --font-size-scaling-rate(3rem, 0.5);
}

BBC @joshtumath.uk

h1 {
	--_type-power: pow(var(--scale), var(--font-factor, 0));
	--_type-scale-formula: calc(var(--base) * var(--_type-power));
	font-size: min(var(--font-size), var(--_type-scale-formula)), 97px);
}

That's me and this is my website.

Screenshot of the matuzo.at website in a browser window. The website features a black and white photograph of a man smiling on the left, and large text on the right that reads 'That's me and this is my website.'

MATUZO VÍC

Screenshot of a personal website displayed within a browser frame. The website features a profile picture of a man smiling, the name "MATUZO VÍC", and the text "FRONT-END / AI1Y / HTML / CSS". A large arrow points from the text "← That's me and this is my website." towards the profile picture. The website URL in the browser frame is matuzo.social.

MATUZO VIC

Screenshot of Matuzo Vic's personal website, matuzo.social, featuring his profile picture and an introduction describing him as a frontend developer, consultant, accessibility auditor, book author, speaker, and teacher.

matuzo.social

:root {
  --color-main: #526d34;
  --color-neutral: #636462;
  --color-contrast: #8f4b57;
  --color-alt-contrast: #8c5700;
}
:root {
	--color-main: #526d34;
	--color-neutral: #636462;
	--color-contrast: #8f4b57;
	--color-alt-contrast: #8c5700;
}

matuzo.social

:root {
  --color-main: #526d34;
  --color-neutral: #636462;
  --color-contrast: #8f4b57;
  --color-alt-contrast: #8c5700;
}

FCK AFD

A grid displays twelve variations of the text "FCK AFD" rendered in different color palettes and textured styles. On the left, a smaller projected screen shows eight instances of the same "FCK AFD" text in various colors.

matuzo social

  • FCK AFD
  • FCK AFD
  • FCK AFD
  • FCK AFD
  • FCK AFD
  • FCK AFD
  • FCK AFD
  • FCK AFD
  • FCK AFD
  • FCK AFD
  • FCK AFD
  • FCK AFD

matuzo.at/fckafd

A grid of twelve text blocks, each displaying "FCK AFD" in a different color, arranged in three rows and four columns. To the left, a smaller physical object, possibly 3D-printed, shows the same "FCK AFD" text in a grid pattern.
:root {
  --color-main: oklch(0.5 0.09 130.31);
  --color-neutral: oklch(0.5 0 0);
  --color-contrast: oklch(0.5 0.09 9.76);
  --color-alt-contrast: oklch(0.5 0.11 69.33);
}

matuzo.social

:root {
  --color-main: oklch(0.5 0.09 130.31);
  --color-neutral: oklch(0.5 0 0);
  --color-contrast: oklch(0.5 0.09 9.76);
  --color-alt-contrast: oklch(0.5 0.11 69.33);
}

OKLCH Color Space Axis Labels

  • 100 (Lightness)
  • 80 (Lightness)
  • 60 (Lightness)
  • 40 (Lightness)
  • 20 (Lightness)
  • 0 (Lightness)
  • 210 (Hue)
A 3D illustration of the OKLCH color space. A vibrant, tear-drop shaped color gradient transitions from purple through red, orange, yellow, and green, enclosed within a translucent cylindrical grid.

Lightness (L) axis values: 100, 90, 80, 70, 60, 50, 40, 30, 20

A 3D representation of a cylindrical color space model, likely OKLCH, displaying a range of hues and lightness values. The vertical axis is labeled 'L' for Lightness, with numerical markers from 20 to 100.

A 3D diagram illustrating the OKLCH color space, shown as a cylindrical volume. Inside the cylinder, a colorful, irregular 3D shape represents the range of colors (gamut) within this space. The vertical axis on the right is labeled with numbers from 50 to 100, and "L" for Lightness. The circular base of the cylinder has angular labels (e.g., 0, 150, 200, 250, 300, 350) indicating Hue in degrees.
  • Lightness (L) scale: 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100
  • Chroma (C) scale: 0, 50, 100
  • Hue scale (degrees): 0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330
A 3D diagram illustrating a color gamut within a cylindrical OKLCH color space. The vertical axis represents Lightness (L), the radial distance from the center represents Chroma (C), and the angle around the central axis represents Hue. The gamut is depicted as a colorful, teardrop-shaped volume.
A 3D visualization of the OKLCH color space, shown as a teardrop or leaf-shaped volume of colors. The graph has a vertical axis labeled 'L' (Lightness) with values from 0 to 100, and a circular base representing hue, with an axis labeled 'C' (Chroma) extending outward. The colors transition from yellows and greens at the top to blues, purples, and pinks at lower lightness and different hues.
A 3D diagram illustrating a cylindrical color space model, likely OKLCH, with axes representing lightness (L), chroma (C), and hue (H). The model is rendered with a gradient of colors within its volume.

sRGB

A visual representation of a color space, possibly illustrating a gamut, showing a green to yellow gradient with an axis labeled '-a'.
:root {
  --color-main: oklch(0.5 0.09 130.31);
  --color-neutral: oklch(0.5 0 0);
  --color-contrast: oklch(0.5 0.09 9.76);
  --color-alt-contrast: oklch(0.5 0.11 69.33);
}
:root {
  --color-main: oklch(0.5 0.09 130.31);
  --color-main-100: oklch(from var(--color-main) 0.9 c h);
  --color-main-200: oklch(from var(--color-main) 0.8 c h);
  --color-main-300: oklch(from var(--color-main) 0.7 c h);
  --color-main-400: oklch(from var(--color-main) 0.6 c h);
  --color-main-500: oklch(from var(--color-main) 0.5 c h);
  --color-main-600: oklch(from var(--color-main) 0.4 c h);
  --color-main-700: oklch(from var(--color-main) 0.3 c h);
  --color-main-800: oklch(from var(--color-main) 0.2 c h);
  --color-main-900: oklch(from var(--color-main) 0.1 c h);
}

Colors

Primary colors

Primary color tokens

Secondary colors

main

  • 100
  • 200
  • 300
  • 400
  • 500
  • 600
  • 700
  • 800
  • 900

neutral

  • 100
  • 200
  • 300
  • 400
  • 500
  • 600
  • 700
  • 800
  • 900

contrast

  • 100
  • 200
  • 300
  • 400
  • 500
  • 600
  • 700
  • 800
  • 900

A screenshot of a web application running on localhost, displaying color palettes. Under "Primary colors", there are six individual color swatches and a disclosure button labeled "Primary color tokens". Under "Secondary colors", there are three color scales named "main", "neutral", and "contrast", each displaying nine shades labeled from 100 to 900.

Colors

Primary colors

Primary color tokens

Secondary colors

main
neutral
contrast
contrast2

matuzo.social

A design system screenshot displaying color palettes. It shows a row of distinct primary color swatches. Below that, four rows of secondary color swatches are presented, categorized as 'main' (green hues), 'neutral' (grayscale), 'contrast' (pink/purple hues), and 'contrast2' (yellow/orange hues). Each secondary color row contains nine swatches, progressively darker, labeled from 100 to 900.

Screenshot of a color palette tool displaying OKLCH and sRGB color scales.

Screenshot of a user interface showing two horizontal rows of color swatches. The top row is labeled 'OKLCH' and displays a gradient of blue-purple shades, each swatch numbered from 100 to 900. The bottom row is labeled 'sRGB' and displays a gradient of yellow-brown shades, each swatch numbered from 100 to 900.
  • No orthogonality
    • even in spaces that generally have these properties
Screenshot of a user interface for a color manipulation tool, displaying color values and input controls.
  • No orthogonality
  • even in spaces that generally have these properties
Screenshot of a color selection and manipulation tool interface, displaying a yellow color, a color picker, and input fields for HSL (Hue, Saturation, Lightness) and RGB color values. The lightness slider is set to 1.00.

Out of gamut is the Wild West

  • No perceptual uniformity*
  • No device independence*
  • No orthogonality*

* even in spaces that generally have these properties

Colors

Primary colors

Primary color tokens

Secondary colors

main

100 200 300 400 500 600 700 800 900

neutral

100 200 300 400 500 600 700 800 900

contrast

100 200 300 400 500 600 700 800 900

contrast2

100 200 300 400 500 600 700 800 900

A color palette display, showing primary and secondary color sets. Primary colors include white, dark green, olive green, gray, plum, and golden brown. Secondary colors are organized into four rows, each with nine shades from 100 (lightest) to 900 (darkest): a gradient of greens labeled 'main', a gradient of grays labeled 'neutral', a gradient of pinks/plums labeled 'contrast', and a gradient of golden browns labeled 'contrast2'.

Gamut Mapping Playground

Screenshot of a web application called "Gamut Mapping Playground," which shows an input color and its transformed versions using different gamut mapping methods, along with color swatches and numerical color difference values for each method.

Gamut Mapping Playground

Screenshot of a web application named 'Gamut Mapping Playground' showing color input controls (Lightness, Chroma, Hue, Alpha) and various gamut mapping methods like Clip, CSS, Scale, Chromium, Björn Ottosson, Raytrace, Edge Seeker, HSL Clip Iterative, and Scale LH, each displaying a color swatch and delta values.

Gamut Mapping Playground

Screenshot of a web application interface titled "Gamut Mapping Playground" which demonstrates various color mapping algorithms.

Gamut Mapping Playground

Screenshot of a web application titled "Gamut Mapping Playground" showing different color gamut mapping methods. The interface includes controls for adjusting OkLCh color values (Lightness, Chroma, Hue, Alpha) and displays how an input color (yellow in this case) is rendered by the browser and mapped by various algorithms such as Clip, CSS, Chromium, Björn Ottosson, Scale, Scale LH, Edge Seeker, Raytrace, and HSL Clip Iterative, along with their Delta E differences. A yellow color in the "Clip" section is highlighted with a red arrow.

Gamut Mapping Playground

Screenshot of a web-based 'Gamut Mapping Playground' tool, which compares various gamut mapping methods for a given input color (a light yellow). It displays different mapping results with associated color difference metrics.

OkLCh

Screenshot of a color picker tool for the OkLCh color space, showing sliders for lightness, chroma, and hue, and a circular color wheel displaying a color gamut. The selected color is a yellowish-golden hue, with a black dot indicating its position within the gamut and a larger circle marking another point.

OkLCh~

A screenshot of a color picker tool displaying OkLCh values for Lightness, Chroma, and Hue, with an interactive circular color gamut visualization showing a selected color point within and potentially outside of a defined color space.

OkLCh~

Screenshot of an OkLCh color picker tool. The interface features sliders for Lightness (0-1), Chroma, and Hue, displaying current values of 0.85, 0.13, and 87.03 respectively. A large light yellow color swatch is displayed at the bottom, corresponding to `oklch(85% 0.13 87.03)`. On the right, a circular color gamut visualization shows chroma and hue at a fixed lightness, with a black outline representing the sRGB gamut. A black dot indicates the current color's position within the gamut, and a white circle highlights another point, possibly a target color or a reference point.

OkLCh

Screenshot of an OkLCh color picker tool. The interface features sliders for Lightness, Chroma, and Hue, along with a color swatch representing the selected color. A circular diagram visually represents color gamuts, showing the selected color within the gamut boundary and another color point outside it.

OkLCh Color Picker Interface

  • Lightness (0-1): 0,9
  • Chroma: 0,13
  • Hue: 87,03

Current selected color value: oklch(90% 0.13 87.03)

Options to paint colors in: sRGB, P3, Rec2020, All

Options to show gamut: sRGB, P3, Rec2020, ProPhoto

Screenshot of an OkLCh color picker tool. The left panel shows sliders and numerical inputs for Lightness, Chroma, and Hue. The right panel displays a circular color gamut visualization, with radial axes for chroma (labeled 0.29, 0.40) and angular axes for hue (labeled h=0°, h=90°, h=180°, h=270°). A black dot indicates the currently selected color within the outlined P3 color gamut, and a white circle shows a cursor positioned near the outer edge of the chroma axis.

OkLCh~

A screenshot of a color picker tool for the OkLCh color model, featuring sliders for Lightness, Chroma, and Hue, and a circular color gamut diagram that displays the selected color and its position within the gamut.

OklCh

Screenshot of a color picker interface displaying OklCh color space controls. It shows sliders for Lightness, Chroma, and Hue, with their respective values and color gradient previews. A circular diagram on the right visualizes the color space with a selected point. Below the sliders, color values are shown in oKlCH format, along with options to display gamut for sRGB, P3, Rec.2020, and ProPhoto color spaces. The text "matuzo.social" is visible in the top right corner.

OklCh Color Picker on matuzo.social

Screenshot of a color picker interface demonstrating the OklCh color space, with sliders for Lightness, Chroma, and Hue, a circular color visualization, and options to show gamuts for sRGB, Display P3, and Rec. 2020.
matuzo.social
A photo shows two smiling men, both wearing lanyards. The man on the right has his arm around the man on the left and gives a thumbs up. A Firefox logo is visible above the man on the right.

matuzo.social

Three photos showing a man (likely the speaker) giving a thumbs-up with another individual. The left photo is associated with the Firefox browser logo. The middle and right photos are associated with the Google Chrome browser logo.

matuzo.social

Three photos, each showing two men smiling and giving a thumbs-up. The first photo features the Mozilla Firefox logo, the second features the Google Chrome logo, and the third features the Microsoft Edge logo.

All elements

A screenshot of a web page titled 'All elements' with navigation links and a recipe. The browser tab shows 'oli.css'.

oli.css

All elements

My love for Vienna and Strawberry Cashew Pancakes

Screenshot of a web page demonstrating `oli.css` with an olive branch logo, displaying various styled HTML elements and an example blog post.

My top 5 80s movies

Screenshot of a webpage displaying an article about 80s movies, featuring an image of VHS cassettes and a quote.

Let's get nerdy

I really like movies about hacking and coding.

  • Groundhog Day
  • Superbad
  • Monty Python and the Holy Grail
  • Airplane
  • American Pie
<div class="button">
  Hack the planet!
</div>

Rudy Gobert is from France.

Nikola Jokic not from this world.

Giannis Antetokounmpo is amazing.

A Victor Wembanyama jersey costs $120 (VAT included).

Luka Doncic plays for the Dallas Mavericks.

Scottie Pippen wrote Unguarded.

Allen Iverson once said "I'd rather have more heart than talent any day."

The term GOAT (Greatest of all time) describes the best player of all time.

FG% stands for Field Goal Percentage.

Rui Hachimura can read this: 君子は和して同ぜず.

Kobe Bryant died on January 26, 2020.

The formula to calculate the FG%: (FG + 0.5 * 3P) / FGA.

The term GOAT (Greatest of all time) describes the best player of all time.

FG% stands for Field Goal Percentage.

Rui Hachimura can read this: 塁子はは和して同ぜず。

Kobe Bryant died on January 26, 2020.

The formula to calculate the FG%: (FG + 0.5 * 3P) / FGA.

The computer calculated Steph Curry's 2024/25 FG%: 44.8

There is no `<nba>` element.

Watching the Wizards play in your browser, all you can do it press Alt + F4.

Jakon Pöltl's house has probably more than 100m².

Franz Wagner drinks H₂O.

There is a certain je ne sais quoi about Kyrie Irving's game.

Ivica Zubac is strong.

Jonas Valančiūnas is from Lithuania.

Dirk Nowitzki is still not active.

All the mentioned men here are or were NBA players.

img

A close-up image of a record player's tonearm and cartridge resting on a vinyl record.

Screenshot of a webpage demonstrating HTML tables

Screenshot of a webpage displayed in a browser. The page features two tables: one listing names, scores, and countries, and another listing names with scores across four quarters (Q1-Q4).

Demonstration of HTML Tables

Screenshot of a web browser displaying a local web page. The page features multiple HTML tables. The tables titled 'Total scores Group A' show scores for individuals (Michael, Robert, Dominik, David, Markus, Paul) across four rounds (R1-R4). Another section, 'Inputs in tables', presents a table with 'Name' and 'Score' columns, partially showing 'Michael' with a score of '27' and 'Robert'. A purple arrow cursor is visible on the right.

oli.css

Screenshot of a web page demonstrating the oli.css stylesheet, featuring a header with the "oli.css" logo and navigation links for "Demos", "Docs", and "Download". The main content area begins with the heading "All elements" and includes an article titled "My love for Vienna and Strawberry Cashew Pancakes". A subtle plant illustration is visible in the background on the right side of the page.

All elements

Screenshot of a web page demonstrating HTML elements with basic styling, featuring navigation links and an article about pancakes.

All elements

Screenshot of a web page titled "All elements" showcasing various HTML elements, including a navigation menu and a sample article titled "My love for Vienna and Strawberry Cashew Pancakes".

All elements

Screenshot of a web page displaying various HTML elements with base styling.

Customisation

Customisation

matuzo.social

An illustration of multiple fireworks exploding against a dark sky.
html {
	--magic: true;
}

Screenshot of oli.css on My love for Vienna and Strawberry Cashew Pancakes by Olivia

Screenshot of a web browser displaying a blog post on "oli.css" titled "My love for Vienna and Strawberry Cashew Pancakes". A faint illustration of plant leaves is visible in the background of the webpage.
@container style(--magic: true) {
	header, main, footer {
		--_inline-size: (((var(--oli-s-page-width) - var(--oli-s-page-max-width)) / 2);
		--_wrapper-layout: max(0px, var(--_inline-size));
	}

	main {
		--_main-margin: 0 var(--_wrapper-layout);
	}

	header {
		--_header-align-items: center;
		--_header-justify-content: space-between;
		--_header-margin: 0 var(--_wrapper-layout) var(--oli-s-header-margin-block-end);
	}
}
:root {
  --oli-s-magic: true;
  --oli-s-layout: horizontal;
  --oli-s-font-stack: transitional;
}
:root {
	--oli-font-stack-humanist: Seravek, "Gill Sans Nova", Ubuntu, Calibri, "DejaVu Sans", source-sans-pro, sans-serif;
	--oli-font-stack-geometric: Avenir, Montserrat, Corbel, "URW Gothic", source-sans-pro, sans-serif;
	--oli-font-family-old: "Iowan Old Style", "Palatino Linotype", "URW Palladio L", P052, serif;
	--oli-font-family-slab-serif: Rockwell, "Rockwell Nova", "Roboto Slab", "DejaVu Serif", "Sitka Small", serif;
	--oli-font-family-transitional: Charter, "Bitstream Charter", "Sitka Text", Cambria, serif;
	--oli-font-family-monospace-slab-serif: 'Nimbus Mono PS', 'Courier New', monospace;
}

body {
	@container style(--oli-s-font-stack: geometric) {
		--oli-s-font-family: var(--oli-font-stack-geometric);
	}

	@container style(--oli-s-font-stack: old) {
		--oli-s-font-family: var(--oli-font-family-old);
	}

	@container style(--oli-s-font-stack: humanist) {
		--oli-s-font-family: var(--oli-font-stack-humanist);
	}

	@container style(--oli-s-font-stack: slab-serif) {
		--oli-s-font-family: var(--oli-font-family-slab-serif);
	}

	@container style(--oli-s-font-stack: transitional) {
		--oli-s-font-family: var(--oli-font-family-transitional);
	}

	@container style(--oli-s-font-stack: monospace-slab-serif) {
		--oli-s-font-family: var(--oli-font-family-monospace-slab-serif);
	}
}

Download

Screenshot of the oli.css website, showing download and usage instructions for the CSS library.

Customize oli.css

Screenshot of the oli.css website showing download information and a customization sidebar with general settings, including layout options, with 'horizontal' selected in a dropdown.

oli.css

Screenshot of the oli.css website displaying download options, usage instructions with an HTML code example, and a customization panel for general settings.

Download

Screenshot of the oli.css website, showing options to download and customize the CSS, including adjusting base hue, chroma, and light with sliders.

Download

Customize and download oli.css

Download Customize

Usage

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="/path/to/oli.css">
    <style>
        html {
            --oli-g-colors-layout: vertical;
            --oli-g-colors-base-hue: 256;
            --oli-g-colors-base-chroma: 0.14;
            --oli-g-colors-base-light: 0.6;
        }
    </style>
</head>
<body></_body>
</html>

Customize oli.css

You can download the latest version of oli.css from our GitHub repository:

Step 2: Color

Base hue

Base chroma

Base light

Step 1 Step 3

built by matuzo in Graz

Screenshot of the oli.css website, showing a main content area with download options and a 'Usage' section displaying HTML and CSS code. On the right, a customization sidebar titled 'Customize oli.css' features color adjustment sliders for 'Base hue', 'Base chroma', and 'Base light'.

Customize oli.css

Screenshot of the oli.css website showing its customization interface. A panel on the right titled 'Customize oli.css' displays typography options, with a dropdown menu for 'Font stack body' open and 'humanist' selected. The main page content includes sections for 'Download' and 'Usage', displaying HTML and CSS code.

Download

Customize and download oli.css

Usage

<!DOCTYPE html>
<html lang="en">
<head>
  <link rel="stylesheet" href="/path/to/oli.css">
  <style>
    html {
      --oli-s-layout: vertical;
      --oli-s-base-hue: 256;
      --oli-s-base-chroma: 0.14;
      --oli-s-font-stack: geometric;
    }
  </style>
</head>
<body>_</body>
</html>

built by matuzo in Graz

Customize oli.css

You can download the latest version of oli.css from our GitHub repository:

Step 3: Typography

  • transitional
  • geometric
  • old
  • humanist
  • slab-serif
  • monospace-slab-serif

Font stack headings

A screenshot of the oli.css customization website. The page shows navigation links on the left, a main section for downloading and displaying usage HTML code, and a right sidebar for customizing CSS properties. In the right sidebar, a dropdown menu under "Step 3: Typography" lists font options including transitional, geometric, old, humanist, slab-serif, and monospace-slab-serif.

Customize oli.css

Screenshot of the oli.css website, showing a download section with an HTML usage example and a customization panel. The customization panel displays typography settings with dropdowns for font stack and headings, and a slider for base font size, with a cursor pointing at the base font size slider.

Customize oli.css

Screenshot of the oli.css website, showing a customization interface. The left panel displays a 'Download' section with a 'Usage' code example demonstrating CSS custom properties. The right panel, titled 'Customize oli.css', shows 'Step 3: Typography' options including dropdowns for 'Font stack' and 'Font stack headings' (both set to 'geometric'), and sliders for 'Base font size' and 'Font stack headings'.

Customize and Download oli.css

Usage

<!DOCTYPE html>
<html lang="en">
<head>
	<link rel="stylesheet" href="/path/to/oli.css">
	<style>
		html {
			--oli-s-layout: vertical;
			--oli-s-base-hue: 256;
			--oli-s-base-chroma: 0.14;
			--oli-s

Download

Customize and download oli.css

Download Customize

Usage

<!DOCTYPE html>
<html lang="en">
  <head>
    <link rel="stylesheet" href="/path/to/oli.css">
    <style>
      html {
        --oli-s-layout: vertical;
        --oli-s-base-hue: 256;
        --oli-s-base-chroma: 0.14;
        --oli-s-font-stack: geometric;
        --oli-s-page-base-font-size-m: 1rem;
        --oli-s-text-scale: 1.31;
      }

      main {
        --oli-s-font-stack: geometric;
      }
    </style>
  </head>
  <body>
  </body>
</html>
Screenshot of a browser window displaying the oli.css website. The page features a download section with two buttons labeled "Download" and "Customize," followed by a "Usage" section containing an HTML code block that demonstrates linking to oli.css and customizing its CSS variables. The oli.css logo with an olive branch icon is visible in the top left corner of the page.
:root {
	--oli-s-magic: true;
	--oli-s-layout: horizontal;
	--oli-s-font-stack: transitional;
	--oli-s-scroll-behavior: smooth;
	--oli-s-page-max-width: 80rem;
	--oli-s-page-width: 100%;
	--oli-s-page-start-column-width: 16rem;
	--oli-s-page-text-scale: 1.4;
	--oli-s-page-line-height: 1.7;
	--oli-s-page-padding: 2rem;
	--oli-s-page-background-color: var(--oli-g-colors-color-5);
	--oli-s-page-color: var(--oli-g-colors-black);
	--oli-s...
}
html {
  --oli-s-break-points-m: 48rem;
  --oli-s-break-points-l: 64rem;
}

matuzo.social

html {
	--oli-s-break-points-m: 48rem;
	--oli-s-break-points-l: 64rem;
}
html {
    --oli-s-break-points-m: 48rem;
    --oli-s-break-points-l: 64rem;
}
@media (min-width: var(--oli-s-break-points-m)) {
	body {
		background: blue;
	}
}
An emoji showing a sad, crying face is in the top right corner.
@media (min-width: var(--oli-s-break-points-m)) {
  body {
    background: blue;
  }
}
An emoji of a crying face is in the top right corner.

matuzo.social

@custom-media --medium-window (width ≥ 48em);

@media (--medium-window) {
  body {
    background: red;
  }
}
An emoji depicting a crying face.
@custom-media --medium-window (width >= 48em);

@media (--medium-window) {
  body {
    background: red;
  }
}
A crying face emoji is in the top right corner, above the code.
html {
  --oli-s-break-points-m: 48rem;
  --oli-inline-size-m: min(var(--oli-s-break-points-m), 100vi);
}

@container style(--oli-inline-size-m: var(--oli-s-break-points-m)) {
  body {
    background: red;
  }
}
min(10px, 50px);

matuzo.social

min(10px, );

matuzo.social

min(100%, 50px);

When 100% is less than 50px

min(100%, 50px);

matuzo.social

100% > 50px

min(100%, 50px);
min(48rem, 100vw);

matuzo.social

100vw < 48rem

min(48rem, 100vw);

matuzo.social

100vw > 48rem

min(48rem, );

matuzo.social

html {
	--oli-s-break-points-m: 48rem;
	--oli-inline-size-m: min(var(--oli-s-break-points-m), 100vi);
}

@container style(--oli-inline-size-m: var(--oli-s-break-points-m)) {
	body {
		background: red;
	}
}
html {
  --oli-s-break-points-m: 48rem;
  --oli-inline-size-m: min(var(--oli-s-break-points-m), 100vi);
}

@container style(--oli-inline-size-m: var(--oli-s-break-points-m)) {
  body {
    background: red;
  }
}
@property --oli-inline-size-m {
	syntax: "<length-percentage>";
	inherits: true;
	initial-value: 100vi;
}

html {
	--oli-s-break-points-m: 48rem;
	--oli-inline-size-m: min(var(--oli-s-break-points-m), 100vi);
}

@container style(--oli-inline-size-m: var(--oli-s-break-points-m)) {
	body {
		background: red;
	}
}
A party popper emoji with confetti is in the top right corner. The text "matuzo.social" is next to it.

CSS Café meets CSS Day: an in-Person Pop-Up Event!

Screenshot of a Meetup event page for "CSS Café meets CSS Day: an in-Person Pop-Up Event!".

CSS Café meets CSS Day: an in-Person Pop-Up Event!

Screenshot of a Meetup event page.

matuzo.social

Componentisation

Componentisation

Componentisation

matuzo.social

<div class="card">
  <div class="card-inner">
    <div class="card-content">
      <h3 class="card-heading">Demo</h3>
      <p>Content</p>
    </div>
  </div>

  <img src="image.jpg" alt="" class="card-med
</div>
Screenshot of HTML code showing a 'card' component structure with nested divs for 'card-inner' and 'card-content', containing a heading and paragraph, and an incomplete image tag as a sibling to 'card-inner'.
<div class="card" style="--card-size: l">
  <div class="card-inner">
    ...
  </div>
</div>

<div class="card" style="--card-size: l; --card-axis...">
  <div class="card-inner">
    ...
  </div>
</div>
<div class="card" style="--c
<div class="card-inner">

    ...

</div>
</div>

High Fidelity

High Fidelity is a 2000 romantic comedy-drama film directed by Stephen Frears, starring John Cusack, Jack Black, and Iben Hjejle.

A code editor displays HTML code. To its right, a UI card features an image of a record player with a vinyl record, alongside text about the film "High Fidelity".
<div class="card" style="--c">
  <div class="card-inner">
    ...
  </div>
</div>

High Fidelity

High Fidelity is a 2000 romantic comedy-drama film directed by Stephen Frears, starring John Cusack, Jack Black, and Iben Hjejle.

A web component card displaying "High Fidelity" text and an image of a vinyl record spinning on a turntable with the needle down.

.card-custom {
  --card-size: l;
  --card-axis: x;
  --card-scheme: dark
}
<div class="news">
	<div class="card" style="--card-size: s;">...</div>
	<div class="card" style="--card-size: s;">...</div>
	<div class="card" style="--card-size: s;">...</div>
	<div class="card" style="--card-size: s;">...</div>
</div>
<div class="news">
  <div class="card" style="--card-size: s">...</div>
  <div class="card" style="--card-size: s">...</div>
  <div class="card" style="--card-size: s">...</div>
  <div class="card" style="--card-size: s">...</div>
</div>
<div class="news" style="--card-size: s">
    <div class="card">...</div>
    <div class="card">...</div>
    <div class="card">...</div>
    <div class="card">...</div>
</div>

The flexible base CSS

An accessible, robust, and versatile base stylesheet

oli.css is an an accessible no-class stylesheet built with modern CSS. It allows you to create beautiful websites without writing any CSS.

How it works

All you have to do is include oli.css in your website. It contains rules for most elements in HTML and makes the boring default styles in your browser look nice. If you still don't like how certain parts look, you can use our extensive API to customize it to your needs and preferences.

Check out the demos.

Examples

Here are some examples of how the same website can look very differently simply by changing properties provided by our API.

Features

olicss.com

A browser window displays the oli.css website, showing its homepage with text content and navigation links (Demos, Docs, Download). Below the main content, there are three small thumbnail screenshots illustrating different visual variations of the oli.css website.

Firefox 151 CSS style() queries

A title card for a video segment, displaying the text "Firefox 151 CSS style() queries" against a top-to-bottom orange to blue gradient background.

matuzo.at website

A screenshot of a web browser window displaying the website matuzo.at. The browser's address bar shows "matuzo.at". Below the address bar, a dark blue navigation bar is visible with links for "Home", "Blog", "About me", and "TIL". The area below the navigation bar is mostly white.
r third-party.overrides {
  oot {
    --oli-s-layout: vertical;

← ↑ That's me and this is my website.

Screenshot of the matuzo.at website homepage, featuring the owner's photo and introduction.

← ↑ That's me and this is my website.

Screenshot of the matuzo.at website.

MATUZO VIC

FRONT-END / AIIY / HTML / CSS

← That's me and this is my website.

I'm a frontend developer, consultant, accessibility auditor, book author, speaker, and teacher from Austria. I'm specialized in HTML, accessibility, and CSS. You can learn more about me and my work on my About page

If you want to work with me or otherwise get in touch, write me an email or find me on social media

Recent posts

Screenshot of Manuel Matuzovic's personal website, featuring a black and white photo of a smiling man.

MATUZO VIC

Screenshot of a personal website with a profile picture and introductory text.

MATUZO VIĆ

Screenshot of a desktop showing two open browser windows. The prominent left window displays the homepage of matuzo.at, featuring the title "MATUZO VIĆ", a black and white photograph of a smiling man, and introductory text. The partially obscured right window displays a GitHub repository page for "matuzo.social".

MATUZO VIĆ

Screenshot of the matuzo.at website displayed in a web browser.

Context-aware headings in HTML

Screenshot of a blog post titled "Context-aware headings in HTML" on matuzo.at, featuring a profile picture of the author.

The headingoffset attribute

Yesterday, I heard about a new experimental attribute that offers a better solution to this problem. The heading offset content attribute allows us to offset heading levels for descendants. Let's take the outline from the page in the screenshot and see how we can make it more context-aware.

<h1>Museums</h1>
<section>
  <h2>Free entry to the museum</h2>
</section>
<section>
  <h2>All museums and collections</h2>
  <h3>Alphabetical</h3>
  <h3>By district</h3>
</section>

First, we turn all headings into H1s. Then we add the headingoffset attribute with a value of 1 to every parent element where we want to increase the heading level by 1.

<h1>Museums</h1> <!-- heading level 1 -->
<section headingoffset="1">
Screenshot of a webpage from matuzo.at displaying an article titled "The headingoffset attribute". An overlayed color picker tool shows the selected color as a dark purple with RGB values 31, 2, 247. The webpage content, including code syntax highlighting, is seen adapting to this color.

MATUZO VIĆ

FRONT-END / A11Y / HTML / CSS

More blog posts >

I wrote a book!

The Web Accessibility Cookbook provides you with dozens of recipes to help you build common components on the web, such as navigations, forms, filters, tables, and dialogs, in an accessible manner. Each recipe not only explains how to build things but also why.

About the book >

Work with me!

Screenshot of the website matuzo.at. The left side features a site title "MATUZO VIC", a tagline, and primary navigation links for HOME, BLOG, and ABOUT ME. The main content area displays a list of two recent blog posts and a link to view more. Below this, there is a prominent section titled "I wrote a book!" which includes the cover image of "The Web Accessibility Cookbook" by O'Reilly, showing a brown dog. A description of the book and a link to learn more are also present. The bottom of the page has a heading "Work with me!" and a scroll-to-top button.

MATUZO VIC

Screenshot of the matuzo.at website. The page displays the website's navigation links (Home, Blog, About Me), a recent blog post entry, and a prominent section titled "I wrote a book!". This section showcases the book cover for "Web Accessibility Cookbook" by O'Reilly, which features an illustration of a dog.

MATUZO VIC

FRONT-END / A11Y / HTML / CSS

04.02.24 Introduction to the new HTML element <geolocation>

More blog posts >

I wrote a book!

Web Accessibility Cookbook

The Web Accessibility Cookbook provides you with dozens of recipes to help you build common components on the web, such as navigations, forms, filters, tables, and dialogs, in an accessible manner. Each recipe not only explains how to build things but also why.

About the book >

Work with me!

I can help you with...

Screenshot of a website, likely a personal blog, featuring information about a book titled 'Web Accessibility Cookbook' with an illustration of a dog on its cover.

I wrote a book!

Screenshot of a personal website displaying a section about a book titled "Web Accessibility Cookbook" authored by Matuzo Vic.

Screenshot of Matuzo.at featuring "Web Accessibility Cookbook"

Screenshot of the matuzo.at website displayed in a web browser. The website features the cover image for "Web Accessibility Cookbook", which depicts a brown dog.

MATUZO VIC

Screenshot of the matuzo.at website, showing the author's name, navigation links, and a section promoting the "Web Accessibility Cookbook" with an image of the book cover featuring a dog.

MATUZO VIC

FRONT-END / A11Y / HTML / CSS

Screenshot of Matuzo Vic's personal website (matuzo.at). The site displays his name, expertise areas (Front-end, A11Y, HTML, CSS), navigation links (Home, Blog, About Me), a section titled "I wrote a book!" featuring "The Web Accessibility Cookbook" with a dog illustration, and a "Work with me!" section. The browser tab title is "04.02.26 Introduction to the new HTML element <geolocation>".

Screenshot of Matuzo Vic's website, featuring the Web Accessibility Cookbook

Screenshot of the matuzo.at website. It displays the site navigation, a blog post, and a section about the 'Web Accessibility Cookbook' including its cover art featuring a dog.

MATUZO VIĆ

FRONT-END / AI1Y / HTML / CSS

  • HOME
  • BLOG
  • ABOUT ME

04.02.26 Introduction to the new HTML element <geolocation>

More blog posts >

I wrote a book!

O'REILLY
Web Accessibility Cookbook
Creating Inclusive Experiences
Manuel Matuzović

The Web Accessibility Cookbook provides you with dozens of recipes to help you build common components on the web, such as navigations, forms, filters, tables, and dialogs, in an accessible manner. Each recipe not only explains how to build things but also why.

About the book >

Work with me!

I can help you with...

Screenshot of the matuzo.at website displayed in a browser. The website features the title "MATUZO VIĆ", navigation links, a recent blog post, a section about a book titled "Web Accessibility Cookbook" with its cover showing a brown dog, and a "Work with me!" section.

slides: matuzo.at/cssday26

BREAKING WITH HABITS

and why. And I also predict it will change even more with many of the new features in modern CSS, thanks to the Interop efforts. The thing is, it didn't happen. At least not for me. And there are several reasons for that. The first reason is that I just didn't have a project where I could put my ideas and predictions into practice. The second reason is that I've realized that I've been following certain principles, approaches, and an understanding of what's a good and a bad practice for 10, 15, or even 20 years without second-guessing them. And for some things, that totally makes sense. Progressive enhancement was a great idea 20 years ago, and it's a great idea today. But to get the most out of some new features in CSS, we may have to reevaluate how we approach problems in CSS. Here's an example. I wrote a blog post about cascade layers a while ago, posted it on social media, and someone replied and said, "Hey Manuel, thank you. That was really useful. I tried it out. I put my CSS in layers, but I didn't see any difference." I'm not sure what they expected, but we chatted a little bit, and I learned that they were using BEM. So, they already had a tool in place that solves the problem cascade layers are supposed to solve. You know, making working with the cascade and specifically specificity easier. For this person to really see a difference, they would probably have to stop using BEM and change how they write their CSS selectors.

matuzo.at/cssday23

And this is why I came up with this talk and why I named it "Breaking with Habits". Now, before I start, I have to make a quick last-minute change. This year I've been to several events and many of them featured talks about AI, and I also had a lot of conversations about AI. I heard some things I can't get out of my head that I want to share with you. I talked to a friend who's really into AI, and he told me that ever since he fully integrated AI into his workflows, he's had more work than ever. Listening to

A small embedded video thumbnail showing a speaker on a stage.

MATUZO VIĆ

FRONT-END / A11Y / HTML / CSS

Dank je wel!

A photo of Manuel Matuzovic smiling, looking up at the camera. He is standing on a paved surface with the word "HELL" painted in white behind him.

MATUZO VIĆ

FRONT-END / A11Y / HTML / CSS

Dank je wel! ❤️

matuzo.social

A headshot of Manuel Matuzović smiling.

MATUZO VIĆ

FRONT-END / A11Y / HTML / CSS

matuzo.social

Dank je wel! ❤️

A smiling headshot of a man.

MATUZO VIĆ

FRONT-END / A11Y / HTML / CSS

Dank je wel! ❤️

A headshot photo of a smiling man.

matuzo.social

MATUZO VIĆ

FRONT-END / A11Y / HTML / CSS

Dank je wel! ❤️

A headshot of a smiling man is displayed on the left side of the slide.

matuzo.social

MATUZO VIĆ

FRONT-END / A11Y / HTML / CSS

Dank je wel! ❤️

A smiling man's portrait photo.

matuzo.social

MATUZO VIĆ

FRONT-END / A11Y / HTML / CSS

Dank je wel! ❤️

A portrait photo of a smiling man, Manuel Matuzovic.

matuzo.social

MATUZO VIĆ

FRONT-END / A11Y / HTML / CSS

Dank je wel! ❤️

A photograph of Manuel Matuzović, a man with short dark hair, smiling while looking up at the camera.

MATUZO VIĆ

FRONT-END / A11Y / HTML / CSS

Dank je wel!

A headshot of a smiling man. A red heart emoji is displayed next to 'Dank je wel!'.

MATUZO VIĆ

FRONT-END / A11Y / HTML / CSS

matuzo.social

Dank je wel! ❤️

A headshot of Manuel Matuzović smiling.

MATUZO VÍC

FRONT-END / A11Y / HTML / CSS

Dank je wel! ❤️

A smiling man with dark hair looks up towards the camera. Behind him, on a cracked concrete surface, the white painted letters "HELL" are visible, suggesting part of a larger phrase like "HTML HELL".

A pattern of black, grey, and blue rectangles arranged in a block-like formation on a light background.

LAST DAY

Stylized wordmark "LAST DAY" formed by black rectangular blocks on a light background.

People

  • Andy Bell
  • David DeSandro
  • Elad Shechter
  • Eric Meyer
  • Harry Roberts
  • Lea Verou
  • Leonie Watson
  • Matthias Ott
  • Nicolas Gallagher
  • Temani Afif

Technologies & Tools

  • Cascade layers
  • Container style queries
  • CSS anchor positioning
  • CSS clamp()
  • CSS min()
  • CSS pow()
  • dialog element
  • Lit
  • Normalize.css
  • OKLCH
  • Popover API
  • Relative color syntax
  • Sass
  • Shadow DOM
  • transition-behavior
  • Utopia
  • Web Components

Standards & Specs

  • Custom media queries

Concepts & Methods

  • BEM
  • Fluid type
  • Gamut clipping
  • ITCSS
  • Progressive enhancement
  • Type scale

Organisations & Products

  • Firefox
  • Interop
  • MDN
  • modernfontstacks.com

Works

  • A More Modern CSS Reset
  • The New CSS Reset