Color-Scheming
Speaker Introduction and Color Scheming Talk Overview
Speaker A introduces Sarah Joy with a playful flapper theme before Sarah takes over to outline her talk on building light and dark modes in modern CSS. Sarah introduces herself as a veteran web developer who made a career change into web development in 2022 and now works at pirateship.com, and frames the talk as an evergreen, practical guide to CSS features that are usable today. She gives an accessibility warning about flashing color transitions and demonstrates a live helper widget that will switch between light, dark, and auto modes throughout the presentation.
Physical Reasons for Preferring Dark or Light Mode
Sarah explores the physiological reasons why people have strong preferences for dark or light mode, covering pupil constriction, visual floaters in the vitreous, and astigmatism. She explains why dark mode suits some users (reducing glare for those with floaters) while light mode suits others (sharper focus due to smaller pupil aperture, and better readability for those with astigmatism, who see light text on dark backgrounds as a blurry, painful blur). Sarah concludes that both preferences are valid and sets up the case for offering users a genuine choice.
CSS Color Scheming Features and Default HTML Dark Mode
Sarah introduces the CSS features she will cover — color-scheme, light-dark(), color-mix(), system colors, and contrast-color() — explaining each one's baseline availability status and what that means for browser support. She then demonstrates that browsers already have a built-in dark mode for default HTML, and shows how a single color-scheme declaration in either the HTML head or CSS root immediately enables it, saving developers from manually re-styling inputs, links, and form elements. A live CodePen demo shows the effect toggling via DevTools.
System Colors and the prefers-color-scheme Media Query
Sarah demonstrates the Canvas and CanvasText system colors, showing how they can be used to make elements automatically adapt to light or dark mode, including locking individual sections (like a header or footer) permanently to one scheme. She explains a key subtlety: color-scheme applied to a child element requires that element to have its own explicit color and background-color, otherwise it inherits transparently and nothing happens. Sarah then contrasts this with the familiar prefers-color-scheme media query, noting that the two mechanisms do not tally up — a point that has been debated but left unresolved due to backwards-compatibility concerns.
Single-Property Dark/Light Mode with Transparency, color-mix(), and light-dark()
Sarah demonstrates three compact techniques for expressing colors that automatically adapt to light and dark mode in a single line: using hex opacity (e.g. 25% alpha on a hue), blending a color 50/50 with Canvas via color-mix(), and specifying explicit light and dark values with the new light-dark() function. She compares the trade-offs — transparency and canvas-mixing always dilute richness, while light-dark() allows full control over both values. Live demos show all three approaches updating simultaneously as the mode is toggled.
OKLCH Color Palettes, contrast-color(), and Upcoming CSS Features
Sarah demonstrates building a coherent color palette mathematically using color-mix() in the OKLab color space, feeding the result into contrast-color() to automatically select black or white text. She introduces the oklch.com tool (by Evil Martians) for exploring OKLCH values and gamut boundaries, and cautions that contrast-color() struggles with midtone backgrounds so it is best reserved for clearly light or dark values. Sarah also previews two upcoming CSS features not yet widely available: image and gradient values inside light-dark(), and a color-scheme() function that would expose the currently active scheme so developers could adjust font weights between modes.
Contrast Accessibility — Migraine Research and the Ravelry Controversy
Sarah shifts focus to the overlooked problem of excessive contrast, explaining that while low contrast is a common accessibility failure, too-high contrast can cause genuine pain for migraineurs. She presents a study in which both migraineurs and non-migraineurs were tested on their aversion to cranked-up contrast in static, drifting, and vibrating grating patterns — finding that a slowly drifting pattern was most aversive for both groups. Sarah connects this to neo-brutalist web design and the 2020 Ravelry redesign controversy, where a stark black-and-white redesign triggered widespread headaches and caused significant community distress, and briefly demonstrates the drifting grating effect live on screen.
Implementing Contrast Preferences and CSS-Only Color Scheme Switching
Sarah shows how to implement the prefers-contrast media query in CSS, applying Canvas/CanvasText for a high-contrast variant and a CSS filter for a low-contrast variant, and how to test these in DevTools rendering panel. She discusses limitations around OS-level contrast support and the confusing overlap between forced-colors and prefers-contrast on Windows. Sarah then introduces a CSS-only approach to user-controlled scheme switching using radio buttons: the CSS checks which radio is checked and sets color-scheme accordingly — extending the demo to include both light/dark and contrast selectors, giving users up to six combined options.
JavaScript Persistence with Local Storage and Session Storage
Sarah identifies the core limitation of the CSS-only approach — preferences are lost when navigating to a new page — and introduces JavaScript to persist the user's choice. She walks through a simple implementation using localStorage (kept across visits) versus sessionStorage (cleared when the user leaves, which she prefers for personal sites to avoid GDPR concerns), showing how to read the stored preference on page load and write it when the user switches modes. A DevTools Application panel demo confirms the mode key being written and restored correctly across page refreshes.
Accessible Button States with ARIA and Full JavaScript Implementation
Sarah adds aria-pressed attributes to the mode-switching buttons so that screen readers can announce which option is currently active, noting that many screen reader users are partially sighted and genuinely care about color scheme state. She shows the CSS to style the active button using the aria-pressed attribute selector and walks through the JavaScript that removes the attribute from inactive buttons and sets it to true on the selected one. The same pattern is then applied to the contrast toggle buttons, and Sarah closes with a summary recommending the use of color-scheme and light-dark() as a free starting point, experimenting with color-mix and OKLCH, and empowering users with up to six combined theme and contrast options.
Q&A: Color Mixing, WCAG Compliance, Forced Colors, and More
Speaker A chairs an audience Q&A covering a range of topics: the trade-offs between color-mix() with Canvas versus opacity; whether contrast-color() complies with WCAG AA contrast ratios; how color-scheme behaves under Windows forced-color modes; when to use the meta tag versus the CSS color-scheme property on :root (Sarah notes the meta tag helps avoid a flash of unstyled content); the flash-of-default-scheme problem when restoring stored preferences (Vadim McKeev's question prompts discussion of a Chrome-only HTTP header); a comment about avoiding inline JavaScript event handlers; and whether dark mode can be implemented progressively on an existing site.
Then, my dear friends, I would like to introduce you to our next speaker. She, she was born in the very early nineteen twenties, and she keeps herself looking so youthful through the power of the Charleston dance. You can see she's demonstrating it now.
So put your hands together for everybody's favorite flapper, Sara Joy.
Thank you.
Where's your banana?
It's down there. I I I'm amazed at who just came before me. Some people seem to be able to think in, like, five d space. I yeah. It's gonna be a little bit calmer from now on, maybe. Just okay, so color scheming, which for me is building light and dark modes in modern CSS.
It is not a fully new talk. I have given variants of it before, but it feels like it is evergreen, because I keep finding new ways to update it. They keep adding stuff that's available to use. Because progress in CSS is lightning fast the last few years. I mean, you sit out for five years, you have a really busy job, maybe you start looking at CSS again and you go, oh my god.
What I wanted to do was make a talk where almost all of it is usable now, and let you be comfortable in just using the thing. Because there's so many cool new things we can do, but they are not always completely available all the way across the board. For those who might find this to be old hat, you can take a nap.
That's fine. Hi, I'm Sarah. I'm both an old hand in that I was building my own website as a teenager in 1999. I kind of fell off the wagon for a while, and then I came back again. I'm not such a newbie anymore. I made my career change into web development in 2022, now working for pirateship.com, which Americans may have used.
Unfortunately, I cannot dog food it. I work in Hamburg and we've got the dev wing in Hamburg. But if you're American, let's parley. You may want to ship your packages cheap. Savvy. Yeah, our customer support do that as well. A little warning, there will be some abrupt changes between light and dark mode. So this whole page is going to flash a bit.
If you suffer from migraines, epilepsy, or strong astigmatism, and I apologize for badly saying that, I'm really, really sorry. My goal is, ideally, to make the web more comfortable for everyone. You may have spotted a little smiley. And at this point, I need to go to my laptop. At the moment here, this is in an auto mode.
I've done this using the technology that I'm going to tell you about. We can have light mode, which is exactly the same in this case, and into Dark Mode. So there's my little helper for this talk. It's mostly gonna sit there and smile at you in Auto Mode. And I need to click away. So Dark Mode versus Light Mode.
We all love a good polarizing argument, right? There are physical reasons to prefer one over the other. You're also allowed to just prefer light or dark themed websites. Even for no good or logical reason, that's totally fine because it's your eyes, your choice. But let's go, why dark mode then? Okay. So, pupils will constrict when they come across a bright page.
And that can be uncomfortable, especially when your page in front of you has way too much contrast with the dark surroundings your bed at night while you're scrolling or something like that. If people have aging vitreous membranes in their eyes or have had various eye problems, they might have floaters in their vitreous. That can get more noticeable when you've got brightness in front of you. If you've laid back and looked at the sky, sometimes you see little white wiggles if you have no actual floaters.
They're literally is it the white blood cells or the blood blood cells? They're literally things going through the capillaries in the back of your eyes. If But you've floaters, you get even more stuff that's in the way and these are like artists' impressions. So people with severe floaters, they might struggle to read text like that. And they might prefer dark mode.
So why light mode? Pupils constrict when coming across a bright page. And in this case, it's actually good because it's easier to focus when your pupil is smaller. If you're a photographer, you know that a small aperture means that your field of view is just much more sharp. You might have to take more light in by having your shutter open for longer, but more of your picture will be sharp.
And that's exactly the same for our eyes. So this is why as you age, as I do, I've started to notice, it's bit a dull in here when I'm trying to read. You may need more bright light to read. Suddenly, those reading laps from IKEA with the little directional down piece is really useful and for crocheting and all that stuff.
So And then also, astigmatism makes light text on dark backgrounds hard to read. And you can This is like an example of what it can look like, and it's not comfortable. And this upsets people enough that they make lots of annoyed simulations because they've had enough of dark mode. So here's lots of examples of strong astigmatism.
And it can cause eyestrain or headaches. And there, yeah, there's enough enough of us fellow nerds busy making examples. I don't only use dark mode. I hate it. Yeah. So, for example, I love this one. I am the douchebag who makes people read white text on a black background. So there are reasons not to like dark mode.
Why not both? Yeah. Alright. Definitely. Good question. So if you're starting from scratch, you've got a greenfield project, you can build up your design, system from scratch. You're starting anew, this is gonna be the easiest time to implement the stuff I'm gonna tell you about. It is slightly harder if you already have a design system and it's mature and you already have all your colors set out and they've already been put in their right places.
That's gonna be possibly harder to retrofit. But I wouldn't stop you. Exactly. So keep it in mind for next time you start a new project. What CSS do we need? So color scheme is widely available across browsers since February 2022. This one is so good it gave its name to the talk, just color scheming. And we'll also look at these helpful features that pair nicely with it.
So we've got light dark, which is newly available, but it's very soon to be widely available, I think in this month, maybe even. Color mix is widely available. That was spoken about by Lia. System colors exist. I'll intro introduce those in a minute. Contrast color is very newly available and has is newly widely available.
And in case you don't know what that means, these are baseline statuses. So you've probably seen them on MDN when you're looking something up or even I think caniuse.com also shows the baseline status. Once a feature is implemented across all the major browsers, it gets its newly available instead of limited tag. And then the clock starts ticking.
And then thirty months or two and a half years later, it's marked widely available automatically. It's not related to a global usage on caniuse.com, but sometimes it's useful to have a coarser measure. So it's just like right here is a gate post on. Right? It can be useful for bosses sometimes. So, right, let's get into actually what I'm trying to do.
We have default HTML themes. This is what we see every day before we've put our CSS reset in. And like Syd, she's desperate to go away from it and doesn't see it very often and takes it out of even her demos, which is fine. Did you know there is also a dark variant built in?
It's just there. It's already lightened up the links. It's already done all your input styles. It's already changed slightly the, maybe not the highlight, Either way, it's already done a lot of different things for you. They're already there. And it saves you having to style all those things already. They've got a nice baseline.
And we don't technically need CSS for this. If that's what we care about, we're not gonna do any other styling. We just want the default modes. We can just stick it in the head. It's another meta. But this is CSS day, so we can also just stick it in the CSS as well. Best stick it under root or HTML.
And what we're doing there is we're telling the browser, this site can be served in both. So if the operating system says, I'm running this one, it will give you that one. If it's running the other one, will give you that one. We're just telling them we have both available. So a little demonstration. Here's our standard HTML.
There's barely any CSS here. Just trying to make it bigger. Oh, and then the result's gone. Okay. Thanks, CodePen. Alright. I'll just get rid of this get rid of this comment even. And then we have our standard WebPerge. I can use my little helper and set it to dark mode, and then it just goes.
And even if we don't like sticking things in the head, we don't trust that. We'll do it here instead. It's not quite live coding, but nearly. And then we can see that it works there too. And just in case you don't trust my little helper, that's fine. I'm gonna be going in and out of DevTools here because it prefers color scheme dark and off it goes.
It's just automatic. It's right there. So we'll kill off that bit. And then there's lots of questions that come up with this, which is great. And I'm gonna get into them now. Where my slides want to advance. There we go. So here, I've started introducing a couple of system colors. We have Canvas, Text, and Canvas, and they do about what you expect them to do.
And you can see that I've switched them for the div, which is where How I Use is, where we have Canvas text is the background color and Canvas is the color instead, just to reverse them. Why not? I can go to my little switchy here and switch it dark. I can also decide that I'm only ever gonna want dark mode here and just do that.
And it can stay like that. And you can have that element, that or that section, maybe it's your head or your footer, you might always want them to be dark. And you can just leave it like that. Or vice versa, you might always want them to be light. Light's spelt the correct way. And then when it goes into dark mode, it stays light, for example. So these these canvas and canvas text are needed here.
If you don't apply a a color in a background color let's just kill those off. It's the elements are kind of just inheriting everything, and they're transparent. And then they don't do anything. Yep. Let's put this back to Inherit. And then because they have no there's nothing sort of for color scheme to work on, so it just follows whatever's behind it.
They need their own. If you're gonna do it on an element, it does need its own color. Right. So there are other system colors. It's not only Canvas text and Canvas. There is also, like, button background and I can't remember them all. There's there's like a stack of about 20 maybe of them, maybe even more. And you can use them, but you can see the sort of roll eye smiley there because this is this one is supposed to be that color.
This one is supposed to be that color. And this one is supposed to be that color. And it's not. Oddly, in dark mode this is Chromium, by the way. In dark mode, it's fine. Well, sort of fine because it's still not actually the active text color. It's a slightly different one. And I did a couple of screenshots just from Firefox because actually they get it much closer.
It's much better. So, you know, Chromium, fix it in light mode, please. So prefers color scheme is probably the thing that's most familiar to everyone. Right? This follows your OS preference. It doesn't follow the color scheme property. So it's it's quite familiar. I've done it in nesting here but, you know, you have your media prefers color scheme dark and you decide in dark I want this color. And I've done that in two different places just for fun. And they are not following color scheme.
So this is this is why it's harder to put it into an established design system or really old website, for example, because maybe you've got quite a lot relying on this, and it can be a bit tricky. If I go back into my Dev Tools, I do like this little button. I want this button to be elsewhere.
You see, the colors do flip then when it's the OS coming in from the outside changing it. So it's it's good to be aware that these two don't quite tally up. And there has been quite long discussions about whether they should be made to tally up, but then we've got backward compatibility issues. So you sort of have to choose one route or the other. But if you choose the preferred color scheme route, you are styling everything, including all your inputs and everything.
Right? What I challenged myself, I find kind of fun, is I wanted to do a one property line that will do dark and light mode at the same time. And I was trying to do this before light dark existed, so forget the bottom one. I thought, well, transparency is fine. So you got yellow here.
It would just be yellow. But I've added a hex four, so 25% opacity on that one. Here, I've used Color Mix. And when you don't give it a percentage here, it just goes fifty fifty. So it's mixing fifty fifty with Canvas. And I can choose to put 60% in here, it would be darker or 80. But we'll leave it like that.
I should have to get rid of it. There we go. And then you can be really specific with light dark. You could have your actual colors. And I've used name colors there because I'm lazy. But you can put anything in there. Anything that's like a proper CSS color can go into the light dark two points. And then, of course, they all change.
Oh, that was too fast. Yeah, 25% yellow on black isn't super nice. And when you're mixing things with Canvas, you know you're never going to get a really rich color because it's always gonna be mixed with something that takes its color out effectively. But then that's where light dark comes in. And you can have a play with that and put whatever you want in there.
What I quite like, even though Leah basically said it's terrible, it's really rubbish. But I'm quite simple. I quite like to mess around with this color mix. And you can see it's Okay Lab here that I've decided to use as the color space. You have to choose one. You can put sRGB in there or I guess just Lab or LCH. And then I'm choosing to mix things.
Oh, I'm still in dark mode. It doesn't matter. I've chosen to mix Rebecca purple with some percentage of some mixture. And the background color is then, yeah, I've done it as a custom property so I could also feed it into contrast color. Leah's already explained that, but I'll get into that in a second. So I'm quite simple.
I use nice round numbers to begin with. And let me advance this slide, please. Thank you. And you can get quite a nice palette with not complicated code. And I could, of course, choose to make that not Rebecca purple in, fuschia. Did I spell it right? Yes. Instead, for example.
So you could shove different colors in there. It's very likely that your designer, if you have a designer, will look at that and go, oh, and will want tweaks. Or maybe you do want different chromers after all. And, of course, but I'm I'm a simple thing. And I start with this and I try and start with a mathematical thing. And then I'll I'll mess with it until things look even to me. I realize that's like a personal website type of situation. That's not everyone gets to do that.
So contrast color that I'd used there. It's finally arrived across browsers. It was literally like two weeks ago or something. I can't remember. And it takes color and returns which has the best contrast against it, black or white. But then the best contrast here is a little bit tricky. So, I mean, for example, already, the 50% Rebecca purple is quite mid. And the black on the mid, it's alright, but it's not great. If I start going up a little bit, I start I start thinking, 75. You know, you kinda want it to switch it white to white at some point.
I think it's 76. Yeah. It finally goes. So, you know, it's there, and you can use it, but try and avoid the midtones on it. If you're gonna use it, try and keep it at either end. I think that just that saves the controversy about whether APCA or WCAG is the best. It's another can of worms for another time.
So using light light dark. This one's a bit simple, really. You can just use whatever color you want and just stick it in there. Hang on. Did I go back to this? No. No. No. Wait. I didn't even just drop this into dark mode. That's the whole point of it. There we go. So the thing that was really light becomes the thing that was really dark and vice versa because you've mixed them with Canvas and Canvas text.
Good. Alright. Next point. Yeah, we can get very specific. I've just shown an example of a named one, a hex, very simple hex, like the old fashioned hex, and OKLCH. Side note, OKLCH, just because I find this really useful, and Leah did a great talk, but this is Okay lch.com, which was done by some software house that I forget.
Either way, Evil Martians. Thank you. Yeah. And it's just super useful because you can plug in a nice turquoise color of a pretty dress. I don't know where she is, but she's somewhere. And you can see whether it Or you can see what OKLC Asia corresponds to, and you can start messing about with that chroma. It will start telling you when you're out of gamut and what your fallback is. So if you start moving it around and you find yourself in a fallback, you know you're out of gamut and it's starting to do something strange.
I don't know why the fallback goes in half though. It's like it's so far off, it doesn't like it anymore. So that was just an aside because I find that super useful. Okay. So so far, light dark is only allowing colors for now. I'm sure one browser's done it. Has Chrome done it already? Firefox has just done it.
I'm sure Safari's not far off, maybe. But we will be able to put images into light dark. So for example, we could change the background of a great big div into a different kind of background if we want a different kind of vibe, it also goes for gradients. So I I don't have examples for this because I'm I haven't played with it, to be honest, because I'm I'm quite lazy.
And when I see that lots of things have got red x's, I go, you know, I'll just check that out another time. I like to wait for things to be across the board. So light, dark, fine, all across the board, very nearly widely available. But image values, it'll be a little while. The other thing, yeah, lots of red.
The other thing I like the idea of is if, and extremely new, only just agreed, is color scheme as a function to tell us what's currently active on the computer that's viewing the thing. So this is what I really want this kind of thing for. You have text in light and dark mode of the same weight.
And I don't know how obvious it is there but certainly here, there's some bleed of the white which makes it look fatter, like it's a heavier weight. That's exactly the same. Don't look for differences between those two but that is then 300 instead of 400. And maybe that'll be even better in the future if we have interpolated variable fonts where we can get like three fifty or something. But I want to be able to do that.
And it's not quite there because we've got some red x's. And they've only I say only just agreed. It was 2025, but the getting this color scheme function will be a little way off. I want it. If you want it, tell them as well. Go to the state of the CSS thing and tell them you want it right there.
Okay. This is a slightly tangent, but I find it really interesting. When we are making UI, we often worry about making it high contrast enough. That's normally the problem, that if we've grays on grays, mean, it's horrible. We don't wanna do that. We want everyone to be able to see it at a high contrast. But it can have too much high contrast.
So migraineur, which is such a lovely word, but people who suffer from migraines can actually suffer pain if the contrast is too high. And of course, you can turn down your monitor. But I I find it interesting that there's a balance here somewhere. Right? So neo brutalistic web design, if if you know what I mean, very square edges, very dark, big drop shadows that are really solid. They've become issues for some of us.
So, migraineurs in high contrast. There was a study, it was a few years ago now, but they tested sufferers for their aversion to contrast based on the movement of a grating pattern. So if you imagine you've got light well, you won't have to imagine because I'm gonna show you in a minute. You've got lines of black and white, and they're either just static and they're constantly cranking up the contrast, or it's drifting slowly and they're cranking up the contrast, or it's vibrating and they're cranking up the contrast. These are the contrast levels at which the people who were not migraineurs and the people who were migraineurs went, no no no, stops too much.
So, it kinda makes sense that the migraine sufferers have lower numbers, but I found it super interesting that drifting was worse than vibrating for both of them. Stark monochrome websites, I think they look super cool. I love that stuff, but they also have similar similarities to a black and white grating pattern. And if we scroll them, they're drifting.
You may or may not be like a yarn crafter if you do crochet or something like that, but there's a website called Ravelry, and I think it was in 2020, everyone was really stressed out, they were stuck at home, they were doing lots of crochet. There was Black Lives Matter and all sorts of things going on. And Ravelry sent out a new website and it was neo brutalistic.
And everyone went, oh my god, I'm getting headaches. And it was terrible. It was a big stress for a lot of people. There was huge arguments. You've never seen so much drama in a crafting community. So what I'm going to demo is just a little little taster of what possibly being in this study was like. Yeah, if you get migraines, if you have epilepsy, please look down.
It probably isn't a good idea to watch. Because this is such a big screen, I'm gonna make that a bit bigger. And I'm gonna set it drifting. And I'm not gonna do it for very long because I feel like it's, I mean, firstly, there's some jaggies as it's updating, right, so it's a little bit wobbly. And it's not pleasant.
And at least you got it on a projection and there's lights here as well. I'm gonna stop it now because I don't like it. Imagine you're watching that and somebody's cranking the contrast and it's getting brighter and yeah. At some point, you're just gonna go, no, stop, please. It's horrible. And you should just be aware of that, I think.
So it's safe to look up. Anyone who is looking down, can now look up. We can increase and decrease contrast fairly easily. So say you've got your site and it might have some nice colors and it might be slightly muted already, in which case you're probably safe but it might not be. You could increase contrast. You could use the media query to begin with.
And you can say your background color is canvas and your foreground color is canvas text. And you might start putting borders in where you didn't have them before, just to really, like, push the push the UI or vice versa, you might. I'll come to this again in a minute. Someone who prefers less contrast, you might just put a filter over the whole thing.
So just a little example. You can test this in DevTools. We can go to Rendering, which is down here, which you can't always find. It might be in this list. Right? There's this whole list that comes out of a Context button. No, I don't want paint flashing. There is a Prefers color scheme. That's media types, forced colors, forced colors, we'll get to that.
Prefers contrast. I could go to more and it's just gone canvas, canvas, text. I could go to Less. And it's just doing a filter of 60%. 60% may be a bit too much, you probably don't need that. But it's a bit more obvious for you guys to see it here. Gonna make sure that's not doing that anymore.
Good. But there are issues. How does a user specify low contrast in their OS? Has anyone ever found a setting like that? I know I haven't. I think preferred color scheme probably came before the OSes started implementing color schemes. You could argue it might come, but I don't know.
And why in Windows do forced colors sometimes equal prefers contrast more? These these two are completely linked in a way that is confusing to me, and also, Killian is here somewhere. He wrote about it. You can ask about him. Yeah. They're they're linked in a way. So if you use windows and you choose your high contrast theme, it doesn't only tell websites, hi, I'd like you to be more contrasty, please. It doesn't do that.
It injects forced colors into them to just make them contrasty. And that probably makes sense if you really need it. You can need it to happen across the board. But it's tricky. So that's an interesting situation. And then also another issue is that some people like to keep their OS UI in light mode and view dark mode web pages or vice versa. I'm kind of vice versa on my phone and the other one on my laptop for reasons I don't understand.
And so I've already said this to someone but I'd love to have the color scheme toggle, maybe even a contrast toggle somewhere in the actual browser, not hidden in the dev tools. I want it in the browser. Anyway. Oh, yeah. You like that one? Okay. So last year, John Olsop gave gave his DAO of CSS.
And I I love this idea of, giving everything up to the browser and the users. This is this is what I want to do. I want to code without coding. I want to stop fighting the browser. I want to trust the user and delete all the unnecessary code and let the system work for me, for you, for everyone.
The DAO of CSS is the path of least resistance. Oh, John, some days I would love to code less. So the deal is to allow true choice. I feel like we need to roll our own switches at the moment. We we have websites and we want to give people choice because they should be allowed choice. And yet the browser doesn't quite do it and the OS doesn't quite do it. So what we gonna do?
We're gonna do it ourselves. So if you rely on Prefers ColorScheme, this is kind of a pain. We override it with JavaScript and injecting classes and trying to check Windows match media thing and then inject the class before the page loads and trying to avoid the FlashArt one style content. Is that right? There's two that sound rude.
I'm not gonna say what they say. And so we can avoid this. It's much easier if we use color scheme to begin with. Can we do it with CSS only? Yeah, sort of. Has is really nice. So please go to HTML without dropping the result. No. Okay. Whatever. We have a field set.
And it has a legend. And it's just got simple radios in it. And when they're checked, they're checked. You know the deal. The CSS checks for the ID mode switcher and checks whether its value light is checked or whether its value dark is checked. And this sets the color scheme.
And you're done. Result. Still in light mode. And because it through the magic of CodePen embedded, it seems to follow, I think. So it just it just does it. And there is a question, and I'll come back to that in a minute. We can also do it with Contrast if we want.
Yeah. I'll show you the picture first. And then I'm gonna disappear here. Oh, I see it, it stayed. Wonderful. Okay. So now we've got two. We've now just got another. We're doing it with Select this time. I mean, I know some people don't like actions to happen on Select or Radios because you should be hitting a Submit button.
That's a thing. That's fine. But I am demoing and we'll come to the other one in a minute. Yeah. So we've got two Selects. And because I'm scaling this, it's very confusing. Let's put the Select dropdown up here. We can get to dark mode. And you know what? I want high contrast dark mode.
Or maybe I want low contrast dark mode. Let's have a look at the CSS. We've got the same things as we have before. And then we've got here we go. Only needed because of a low contrast filter. You need it's the same sort of thing.
You can't filter anything that doesn't already have its own color. So, they kind of have to have a color, the text in the background. Otherwise, you're filtering nothing, sort of. It just doesn't work. Yeah. So we now got all these options depending on what so we've now got, like, a six, effectively, different options depending on whether we want light or dark mode or we want high contrast or low contrast or we don't care.
In this case, it's only four. Yeah. Oh, and they're just pretty fine. You don't need to know that. So, again, we've just put a filter across it. And here, I've just added canvas and canvas text in everywhere because it's just sitting there for me to use. Why the auto setting? You could just have you open up a web page, you're in light mode, you hit a button once and you go to dark mode. That would be simpler for the user, but I kind of like knowing where I am.
Maybe this is maybe this is the tap that I'm that I'm doing. I'm like, there's three settings. Let them have all three settings. Maybe you just want light dark. It does save you work because otherwise you need to check which mode. You're doing the Windows match media thing, you need to check what mode the computer's in so that then you put the right thing on the button to know which one you're switching to.
So you end up having to do all these pre checks just to show your button properly or whichever state you're in properly. And it's a bit tricky. So Having the Auto Setting does save you work, but that depends. You might be slightly more like, no, no, I just want to give the user two and leave them to it, but then it's just a bit more JavaScript, that's fine.
You can do this anyway, And skip order if you like. I won't stop you. It's just your choice to complicate matters. So CSS only limitations. You've probably already spotted this. You it's magical but only works per page. So if you've got more than one page to your website, which you probably do, as soon as you go to another page, it's just gonna flip back into whatever it was.
So it's gonna flip into your OS mode, even if you've chosen dark. And the preferences isn't getting saved while browsing the site. So and you can't use buttons because you you have to put the JavaScript in there to make the button do the thing. So what JavaScript do we need? And I like Jeremy Keith's maxim, which I've decided to call it, but JavaScript should only do what only JavaScript can do.
So, at this point, I've hit my limit on CSS. I'm gonna try some JavaScript. So I I like very simple functions and you're gonna find that this looks very repeated because I want to be very clear with what I've done. So it's gonna look like a lot of code but it's all gonna look quite the same in some places.
You can undry it later. Undry? Just dry. No. You can wet it later. Okay. So we've three things here. We've got some buttons. We've got another field set, and we've got a select. They're very dumb, they're not talking to each other. I can set this one on dark. I can set this one on light. It's just taking the last thing and, like, writing it.
And, back to dark again. Let's leave them all on auto. Right. So HTML is quite familiar, probably. The CSS is super simple. We've just got the light dark and just trying to make it look nice. And then we are getting a variable for HTML because it's much easier that way. And when I want switch auto, I want it to set color scheme to light dark.
So it will do whatever. When I choose Switch Light, I want it to just put light in there, Switch Dark, just put dark in there. And this one is slightly less dry than this is the version you would use when you're trying to save some bytes, which is absolutely fine. And that's what this one is, what that one is using.
We can use buttons. But this still is only working per page, and it's lost when the page is reloaded. Useful. So we need to store the preference for the user. And for this, we can use session storage or local storage. And I think everyone loves local storage or knows local storage, but I have a thing about session storage.
For my personal website, I prefer that because people aren't visiting it very often. It's not like they're logging in every week to check something. They're just not. If I have them automatically land on CSS LightDark, they will always come in on their OS settings. So it won't be jarring, hopefully. And then they can pick one.
And then while they're on my website, they can browse around however they like. It will stay on that one until they leave, and then that information is destroyed. And it's not GDPR to save this stuff in Local Storage, but it makes me feel better. Yeah, Local Storage is kept between visits until the user clears their browsing data. So, let's just do that.
We have three buttons. We have our simple CSS. And we are now just checking for things. There is some redundant code here. I'm alright at JS JS. I would spend more time trying to fix it, I just wanted to make it very clear what I'm doing in every function. So we're now also pulling out the mode from local storage, get item mode, and seeing if there is one.
And if it's dark, I automatically switch dark. If it's light, I automatically switch into light. And Auto, we just remove the Item Mode. Don't need it. And we're setting the Item Mode into whichever one we're switching into. And let's go into, no, not f 11, f 12. I'm gonna go and have a look at the application.
And there's so many Code Blends here. I think, there we go, Mode light. Mode dark. I should be able to refresh the page. At this point, you may have noticed my slides are me subtly changing color the whole time. And it will come back dark. So it's just saving it there. If I go back to auto, it will kill it, and it's gone. So we just got that.
And then every time you come back to that page, it's sorted. Okay. But this is this is still not everything. It's okay, cute. We've got three buttons. But what current what's the current mode we're in? We can see what mode we're in, but it might be auto. I don't know. Am I in light mode or auto mode?
Is it important? I don't know. But I like to know. So it's not too difficult to set a class with your JavaScript while you're at it on the active button, and then style it according to that class. But there's this Harrier Prester attribute, and it's a useful one, and screen readers can read it. Not that someone using a screen reader necessarily wants to know what color scheme they're looking at, but actually a lot of them might.
Not everyone who uses a screen reader is completely blind, often they're just sort of partly, and it'd be really useful for them to see which one is pressed. So that's exactly what this attribute is for. It has the benefit Screen Reader can announce which option is currently active when they're they're going down through the buttons. So we're back. Now our HTML is a little bit more complicated.
Not only has it an ID, but each one has an aria pressed attribute. And the one that is currently active has got the area pressed true. I can switch. And it's not gonna be shown here because that's my starting code. CodePen isn't live in quite that way, but then we can see in the CSS, I've just added a little bit here.
So button, when ARIA pressed equals true, it goes transparent to match the background, and it gets a slightly bigger border width. You might do it much more obviously than that, like, you know, five or something. And then it does get a bit bigger. So now I'm just setting up variables for all the switches, that's because a little bit easier than having Document Query Selector everywhere.
And this is where I think there's probably a smarter way to loop through. But I wanted to show you that effectively I'm taking ARIA pressed off the two others and putting it into true on the one I've just chosen. So switch auto gets area pressed auto, true. Here we are, it's off the other two, and light is true for switch light.
Yes, it's getting a bit obvious at this point. Good. We can also do the same with our contrast switches. The JavaScript now is getting quite heavy, but also because I'm repeating myself a lot. You are very likely to be able to make this a bit less repeated.
So I'm just doing the same thing. Like, here's another bunch of pullings in. I'm just got just it's just contrast buttons instead. I am writing to local storage. I am setting attributes, and they are coming across in their various places. And while we're at it, I do like watching it in DevTools. There we go.
Auto, light, dark, contrast, light, high, low, auto. You guys, oh, you guys will be able to style it a lot more nicely than this. So my summary is, after all of this, is just we can offer choice. And we can offer more choice than the computers are offering right now. So I'd like to say use color scheme, light dark, for your free dark mode.
Get that free, and then start building on top of there. Experiment with Color Mix and Canvas and Canvas text and Okay LCH and all these other things. Yes, if you are working with a proper branding, you will need to specify your colors as to where it is, but then you've got light dark for that, and that's fine.
And you can honor your user's color and contrast preferences. And experimentation and playing at this point is just the thing for me. Get on Neo Cities and do it on your phone. Get on CodePen and just sort of just see what what happens, what works, what doesn't work. And then from the two choices, from the Contrast and the Light mode, you can have up to six options.
And then you've got this whole six options of theming which you weren't sure even existed half an hour ago. There's some further reading. These slides will be up. The I no longer understand first contrast is what Kilian wrote. There's so many, like everything in CSS, there will be some shotguns and some things that are confusing.
Shotguns, footguns. But if we don't try, we don't get anywhere. Thank you.
Thank you, Sarah. To the chair of interrogation, Oh,
wait. I've got to take that out of my back pocket. I'm not getting in trouble.
Lots of questions. Some I don't know when these questions came in, so you might have answered them. Subsequently because I went out for a pee. I'm sorry.
It's okay.
And it took a while.
It's hard when your prostate gets old.
Yeah. It's my age. Anyway, you probably didn't want that. That was not a question that was asked. I just gave you that little extra bit of info. So Gaultier Gaultier, somebody's name begins with a g, said, is there an advantage to using ColorMix with Canvas instead of opacity?
I don't know. I mean, you don't wanna do opacity on a whole div because that takes the text with it. But I I have both methods. I I'm I've been enjoying playing with color mix, but I don't think there's anything wrong with using opacity. It's it's interesting. They're almost the same thing. Right? But there might be slight differences depending on which color space you use. You might end up with something brighter.
It's yeah.
So it's the traditional web dev answer of it depends.
Yeah. Nice.
One that I was wondering about, and Dion has nicely asked it for me, does contrast color give a contrast in color that complies with the WCAG required contrast values?
I think that's exactly what's happened. I think they've gone very exactly on the WCAG based on the mathematical formula that the success criteria will hit. Unfortunately, actually, perceptually, there are times when that thing can be a success, but it can kinda look not so good. There there is movement in that way, but it's it's just avoiding those mids, really, as a background, I think.
And presumably it's the 4.5 color contrast ratio for AA compliance rather than the seven, is it, for Trevali?
I don't I don't know. I imagine it's doing the easier one. It's got to flip at some point. Yeah.
We'll ask Castell later. She'll know. Thysthis said this is a comment rather than a question. Said, thank you for showing the astigmatism examples. They look completely normal to me, so I'm going to the ophthalmologist tomorrow.
Oh, good. Yes, to you. You might save yourself some headaches. Yeah.
Kalil wonders, how does color scheme behave in forced color modes?
I think once you've chosen your forced color mode, it sort of does nothing.
Yeah. That that kinda takes priority over everything, doesn't it?
Yeah. I mean, it just injects. And when you choose the forced color mode in Windows, I think you choose from a light and or dark one. I think you pick one. And then it sticks and force those in. I dare say it breaks some websites. I don't really know. I should test that more.
A guy called Josh Tumath
Oh, dear.
Asked a question, and that's pretty rubbish because he's a speaker, he's supposed to know everything. So Josh said, do you think it's useful to be able to use the color scheme property to change the color scheme of an element in the middle of your page? Do you have use cases for that? Wagging his finger as
you write this.
And when should you use the color scheme meta tag versus setting the CSS color scheme property on the root? Do you wanna read the question? Because it's
I don't know. I don't know. I mean, I just wanted to show that it was possible. Mhmm. But if they had a go at putting color scheme on element, it wouldn't do anything until you gave it some color. I mean, yeah, if you wanted your header to always just be light, you're probably just gonna give it white, aren't you?
You're not gonna give it canvas and canvas text and then say color scheme light is a little bit silly. But it's there and it's possible. What was the second part?
The second part was d and when should you use the color scheme meta tag versus setting the CSS color scheme property on the root?
Again, I don't really know. But if you're not going to use any CSS or if you think your CSS is gonna take a while to load or anything like that, then it's in there early. And you might avoid that Flash of Anstile content where it all flashes white first and then goes dark or vice versa. Not entirely sure, but I'm fairly sure that would help it.
Mhmm. Oh, good. Brahma says yes. Okay. And so does Josh. Yeah. Were testing me.
Happy now, Josh? Yes. Good. Good. Any more daft questions from speakers? Right. This
is my first time here. Know?
On the subject of Flash of Default Color, Vadim McKeev, who is from Firefox and Jolly Good. And we had a podcast together. He's a fabulous chap.
I'm actually using his slide framework. Are you using Showa? Yeah. I was Showering.
SPEAKER Vadim. That's a proper speaker, Josh. Vadim says, have you tried solving the flash of default scheme problem when using stored user color scheme preferences? It can be quite disturbing. There's a Chrome only sexy h not sexy h.
Seck sexy. C h prefers color scheme header.
No. No. Sorry. Was the the question was have you tried? No. No. I haven't.
Should she?
Yeah. Probably should.
Yeah. Let's talk later. This is what we like. Tim feels loudly and wants to say, inline JS in HTML attributes is a crime against humanity. Please don't.
Yeah. I I did that for simplicity.
He'll be waiting outside in the car park with knuckle dusters on.
So I should be using event listener?
Yeah.
Yeah. Use event listener.
Or just use React. Rajeeh says, is there a way to progressively implement dark mode in my existing website, or do I need to implement it everywhere at once?
Not entirely sure how you could do it progressively. Like what starting with one page and then doing the rest? I mean, you need to be quite creative, I think. And if you then do one page and then you don't do the rest, then you've got flashes as you're roaming around. You can maybe do the background, leave the no.
I don't know. I don't know.
Just just do it, Roger.
Try. Yeah.
And with that, I shall release you from the chair of interrogation. It's our first time on this August stage. Give it up for Sarah Joy.
People
- Jeremy Keith
- John Allsopp
- Josh Tumath
- Kilian Valkhof
- Lea Verou
- Vadim McKeev
Technologies & Tools
- caniuse.com
- color-mix()
- color-scheme
- contrast-color()
- DevTools
- light-dark()
- localStorage
- matchMedia
- oklch.com
- sessionStorage
- Shower
- variable fonts
Standards & Specs
- APCA
- aria-pressed
- Baseline
- CSS System Colors
- forced-colors
- OKLab
- OKLCH
- prefers-color-scheme
- prefers-contrast
- Sec-CH-Prefers-Color-Scheme
- sRGB
- WCAG
Concepts & Methods
- Flash of Unstyled Content
- neo-brutalism
Organisations & Products
- CodePen
- Evil Martians
- Ravelry
Works
- Dao of CSS
Building a site that supports multiple themes touches color-scheme and a
growing set of related CSS functions. Sara Joy weighs up what’s genuinely
production-ready today against what’s still experimental, and where
theming support is headed next.















