Skip to main content
891

April 7th, 2025 × #CSS#Accessibility#Frontend

Light and Dark Mode

Discussion on adding light and dark modes to sites, considerations when doing so, and new CSS features to help

or
Topic 0 00:00

Transcript

Scott Tolinski

Welcome to Syntax. Today, on Monday, we're gonna be talking about color schemes. We're gonna be talking about light and dark mode in 2025 Node that some of the features that arrived in the browser are continuing

Wes Bos

to have more and more support every single day, we're also We're in a much better place now. I'm I'm really excited about this stuff.

Topic 1 00:15

Light and dark mode support improving

Scott Tolinski

We're in a much, much better place. In fact, some of these tips and techniques are things that you can use today to add effortless light and dark mode to your apps. And you know me, I'm a big fan of that. So to kick things off, my name is Scott Tolinski. I'm a developer from Denver. With me, as always, is Wes Bos. What's up, Wes? Hey. I'm excited about all of this light Yarn mode stuff. It's I think I feel like it's finally at a space where it works really Wes. You don't do a ton of hacks. No. You know you know what? I was maybe a little skeptical of some of these things when they first launched, like, their utility if if I would use them. And then once I got, you know, comfortable using these tools, it all just became way easier for me Vercel. And I I think it can be way easier for you as well.

Topic 2 00:22

In much better place for light/dark mode

Scott Tolinski

And you know what else can be easier for you JS fixing your app when it goes down or even knowing if it went down at all because CenturyLink now has uptime monitoring, as in they can ping you the moment your app goes down. That way, you spend no time wondering or having to check to make sure your app is up or even worse, not even knowing that it's down. Because if you want people to give you money for your application or, heck, you just want people to use it without being upset at you, well, you're gonna wanna make sure that that thing is actually online.

CenturyLink offers uptime monitoring to know when app goes down

Scott Tolinski

Man, it's so many neat features in Century lately, whether that's uptime monitoring, performance tracking, or session replay Wes you can actually see a video, a scrubbable video of the user clicking around your site and getting angry when your app isn't working. So check it out at century.i0/syntax.

Scott Tolinski

Sign up today using the coupon code tasty treat.

Topic 4 02:06

Discussing light and dark mode in 2025

Scott Tolinski

Wes, let's get into it. Light and dark mode twenty twenty five.

Scott Tolinski

What do you have to consider?

Topic 5 02:11

What to consider for light and dark mode

Wes Bos

Yeah. Let's talk about how to do, like, dark mode from scratch and all of the things available to us, and then we'll talk about, how do you shoehorn a website that doesn't have dark mode into it, as well as how to manually override the system settings of it because sometimes people wanna flip them on. So first of all, from scratch, we're starting a brand new website. Let's talk about how do we set up the the CSS. And there's there's kinda a lot of ways to go about this, but what I've been Node, and I'm curious to see what your thoughts are on this JS Yes. You set up all your, like, color variables first. Right? You have your your white, your black, your green, your your your grays.

Wes Bos

You can have multiple variants of those if you want. Right? Like, you can go through the whole Tailwind color scheme. I generally just kind of pick my colors and name them white, green, black, whatever, and then I will set up variables off based off of those. Right? So you have foreground, background, primary, secondary.

Topic 6 02:54

Setup color variables, then foreground and background

Wes Bos

I I don't know. Sometimes I dip into, like like, button color, but then I don't know if I should be doing that or not. And those variables are simply just referencing the other variables, which are white, green, black, pink.

Scott Tolinski

What are your thoughts on that? Yeah. I I tend to do it the same way. I'll have a link to, my drop in CSS, which JS, like, the CSS starter I'm using for most things these days. Yeah. It's not perfect. It's still, you know, being tweaked. But the way I tend to do it JS, yeah, I define my color palette with actual color names, yellow, orange, red, pink, blue, whatever. Mhmm. I then define the foreground and background, using the light Yarn functions. Then I, define some tints and shades that can go along with that. Now that's for a very simple color palette. On the Syntax site, we have it broken out into, you know, HSL or HS variables, and that way Wes can create, I I think it's HSL. It might be okay l c h okay l c h, where we're tweaking the lightness value or whatever. And then that way, you Sanity a little bit more flexible with it. It can be a programic. It's a lot of variables going that way. So it really depends on, like, the type of project and how many of those tints and shades and versions of colors I need.

Scott Tolinski

Sometimes, like, in my drop in one, the the color system I have JS the default palette is just like six hex values. And, that can be as much as you need sometimes. And other times, you need a lot more than that. Yeah. I'm always torn between

Topic 7 04:29

Color mix and relative color good for calculated colors

Wes Bos

trying to calculate some things and then simply just using the straight up color.

Wes Bos

I think for variations, I like to calculate it. You know, if you have something that is blue and you wanna have, like, a border around, a button is a really good example. Right? I may have, like, six or seven different button colors, and the border of that button is simply just going to be calculated based on the button's background color and to be either a little bit lighter or a little bit darker.

Topic 8 05:15

Calculated colors can get out of control

Wes Bos

And so if it's red, you'll have a little bit of a darker red border around it. And that's really nice because then you don't have to go and make a million variations, but that can kinda get out of control really quickly if you if you go overboard on, on all the different calculations.

Scott Tolinski

Yeah. But now with things like, color mix and relative color, to which the degree at which those are supported, which actually, I haven't checked on relative color in a while. Because can I use, color mix itself has had pretty good support for a little bit? So color mix is available 91% of browsers globally. It's available in Firefox going back to May of twenty twenty three. So you can use color mix. But relative color has always been lagging behind.

Topic 9 06:04

Relative color and color mix well supported now

Scott Tolinski

Relative color is in all of the browsers with 90% support. So eight ninety versus 91, that's actually yeah. That's a lot better than I was expecting. So with relative color and color mix, if you find yourself being able to use those, functions based on what you need to support, those are well worth your time for calculating,

Wes Bos

colors and making a programmatic scheme. In fact, I'm probably gonna use these in the new syntax site. Totally. I've been using them on for for probably about a year now, and I've been really happy with it because what they do is relative color will allow you to take in any color. Let's say you have a hex Node, and then you can break it out into RGBA, HSLA, okay well, l c l g h a. And, basically, it just takes the color, slaps it into those different channels. Right? The red, the green, the blue, or the the hue, the saturation, lightness, whatever format you're using. And then you can use calc to up or down each of those. So if you wanna just increase the lightness slightly or if you wanna simply just take that value and make the opacity 50%, it's very doable. And then color mix is simply you just take two colors, and then you provide it how much you want to mix them. Is is that right? Yeah. Yeah. You can you can do that, and you can mix colors with transparent

Scott Tolinski

as well, things like that. I have a, I have a snippet in here I'll have in the show notes that I use for tinting and shading, which simply just mixes the foreground color, which we'll talk about in a second, with transparent for either 95 or 90%. It it's a I have tint tint or shade and tint or shade harder. So if you're in light or dark mode, it's going to either tint or shade it, based on what you need. So that way, it gives you, like, a a slightly lighter line or even a even less slightly,

Wes Bos

lighter line each time. So Those are my favorite lines. Probably simpler if you're simply trying to, mix something with with white, black, or transparent. Yeah. Right? You wanna make it lighter, darker. And then if you need a little bit more control over each of the channels, you wanna you wanna reach for a relative color.

Topic 10 08:15

Use foreground and background variables

Scott Tolinski

Yeah. Totally. So one thing that I like to do, like I mentioned here, is I like to have foreground and background variables, which kind of connects directly to the color and background color properties.

Scott Tolinski

You know, in CSS, I always found that to be such a weird thing that text color was color and background was background color. Yeah. And and so for me, I I've kind of always stayed with this foreground and background because to me, having those two tightly related in the way that they're named just makes a lot of sense to me. Right? So I use f g b g for anytime I want to have a foreground or a background variable.

Wes Bos

I like that. That makes a lot of sense to me. You can kinda think about it as, like, in dark mode, your background will be black, your text will be white, and and vice versa. And, obviously, they they are not always going to be like that. You can choose whatever colors you want, but that's a nice way for me to to think about it.

Wes Bos

Totally. Let's talk about actually setting it. So on the root of your document or really on on any element, you set what's called the color scheme property in CSS, and that will allow us to specify which color schemes are available.

Topic 11 09:13

Color scheme property allows light/dark modes

Wes Bos

And the you can in this case, you probably will be setting color scheme light Yarn, but there there are some other options. What what is this? Normal? What does that do? I think normal is just the actually, that's a good question. I was gonna say it's just the normal behavior, but how does that differ from just Normal indicates that the element can be rendered using the page's color scheme settings. If the page does not have a color scheme set, the element is rendered. Okay. So I think that would be sort of Node is that is that unsetting it? Because the kind of cool thing about color scheme is that you can set it on the entire page. But if you have one element that you want to be dark mode or light mode, you can always just set it on that element, and then your your values will flip.

Scott Tolinski

Yeah. So, like, for instance, just to toss this out there, if you, on your root of your document or any element, you set color scheme Yarn, that's going to change the default CSS for your site to have a black background and white text. So it's actually changing the default CSS Wes, color scheme light is kind of how it's always been. But if you use something color scheme light and then a space and then dark, that is going to respect the user's light and dark mode settings. So on their computer, on their phone, if they have their appearance mode set to dark, then you will get that black background, white text automatically. This is also known as the system color scheme.

Topic 12 10:55

Can override with color scheme on elements

Scott Tolinski

You you'll typically see this on, like, in an app where it says light Yarn Node. It'll be like light dark system.

Scott Tolinski

It's often the way that you'll see that to say, like, just use whatever the whole system is or force this dark or force this light. And you can do that flow simply by changing the color scheme light or color scheme dark here. And I usually make a class for that, like Node dark or just dark, where it sets the color scheme to only dark and then updates the background and the color.

Wes Bos

So that way, those things get updated when whenever you change that color scheme. Yeah. It's a Scott of I've seen people use data attributes, you know, like data dash color Yeah. Or data dash scheme. You can add a class to it, or you could simply inline, the value. I probably wouldn't inline it because then you're you're dealing with weird specific issues if you wanna later override that thing.

Topic 13 11:50

Manually override needs inline script

Wes Bos

Yeah. Once you have color scheme light Yarn set in your CSS, yeah, you can use a number of different ways to set your your colors. Right? There's the the way we've had for a while is the prefers color scheme media query.

Wes Bos

And that's always been a little bit verbose, but that will allow you to write a media query and attach it to a specific selector. In in that, generally, what you're doing is you're simply just flipping variables. You know? You're setting your foreground to to to dark and your background to light or vice Vercel. But you can in that case, you can do anything you want, which may be other things like adjusting text shadow or box shadow or or really, maybe swapping out, like, a background image that for for a different version. Yeah. Totally. But now we have the light

Scott Tolinski

Yarn function in CSS. It's light hyphen Yarn, and it's a function, so that means you got parens and everything like that. So it's a light dark function, and the first, is it argument or parameter? Man, this always gets me.

Wes Bos

The parameter is is what the function is defined as, and the argument is the actual value. So I always think a parameter is a placeholder, argument is actual.

Scott Tolinski

Okay. So the first argument

Wes Bos

is the light is the first argument or first parameter? Wes don't even know. Yeah. In when you're using it, it's an argument. When you're defining it, it's a parameter.

Scott Tolinski

Man, that's my specificity right there. I cannot get that straight.

Scott Tolinski

Either way, the first value the first value in the function is going to be what is going to be used when it's in color scheme light. And the second value is going to be, what it uses when it's in color scheme dark. And this can be super handy for, like, so, you know, the default for color scheme dark is to have a black background with white text. But if you wanted this to be your own colors here, you could do something like the b g is light hyphen Yarn, where you first have a lighter gray then a darker gray. And the opposite of that with the foreground Wes it's like light Yarn. In in light mode, you want that foreground color to be dark. So you have the dark color, and then the second value is going to be your light color.

Wes Bos

You're making my head ESLint. But, essentially, it's just Wes have code in the Wes have code in the show notes. Okay, folks. Function that flips based on light or dark. It's shorthand. It's really simple. You don't have to throw a media query in there, and it is well supported in all the browsers now, which is very nice. You can only pass it colors, which I think is okay. But in some cases, like a box shadow is something you often have to take off in, in dark mode.

Wes Bos

If that's the case or if you wanna adjust if for some reason you wanna adjust the padding or the spacing or the the walk of some text shadow or box shadow, you cannot use values in that case. So if that was the case, you probably would have to That's a good question. Like, how would you

Topic 14 14:30

Light/dark function doesn't work for shadows

Scott Tolinski

You reply to your color scheme.

Wes Bos

Oh, yeah. Oh, yeah. You just you do a a proper

Scott Tolinski

prefers color scheme, and then your Proper prefers color scheme. Because it's a media query. You can do anything with that. You can throw anything in there. And, for anybody out there, I think we harp on this enough. If you're in dark mode, don't make your shadows white. That makes no sense. Have you ever seen a white shadow? Like, come on. It looks awful. And it's kind of a bummer because, like, you're you're sort of seeing shadows go away in a lot of applications. Right? Like, I'm just looking at Riverside,

Topic 15 15:18

Shadows often removed in dark mode

Wes Bos

no shadows.

Wes Bos

MDN, no shadows. GitHub, no shadows. And the shadows have have kind of been stripped away because they don't look good at all.

Wes Bos

And then what a lot of people do is they they go sort of like gray mode or brown mode.

Wes Bos

Okay. Like, just light enough so that they they can still throw a shadow on it, but that's even bigger pet peeve is when your your dark mode is too brown. Doesn't look look very good. Not a fan of that. No. I'm not a fan of that at all. Alright. So let's talk about manually setting dark mode. You can manually set dark mode by simply putting a color scheme dark on an element, and that will force it. Generally, you wanna respect your users' settings, so what their their OS has been set to. But if somebody wants to have a toggle for for dark mode, that's how you now set it. You simply set color scheme dark in your CSS on either the root or on a specific element. Like, I use missive, and I use the sidebar in dark mode, and I use the authoring experience in light mode. So that's a very easy way to do it. You simply just set it on the sidebar, and then all the variables will sort of trickle down, for each of their light and dark modes.

Wes Bos

Yeah. One thing with manually setting dark mode or light mode, via JavaScript is that when the page loads, you have to apply that that class or you have to apply something to your markup so that it kicks in.

Topic 16 16:38

Apply dark mode class on load to avoid flash

Wes Bos

And we we talked about this on the Syntax website as well. We tried to Vercel render it, but then that then the dark mode class was getting into the the cache, and it was being shared. Or in our case, the theme was getting set. If somebody had a theme set and they visited a page, then the cache would reflect, that theme for that page. So that was a bit of a an issue.

Wes Bos

So the way that you can set dark mode is you you use JavaScript, and you can check if somebody has saved a value in local storage.

Wes Bos

You can use window dot match media, to to inherit their sort of light or dark mode default. So if someone has not set it, then you'll get that. Otherwise, you can put it into local storage. But when the page loads, you have the split second where the CSS JS loaded, but the JavaScript has not yet run.

Wes Bos

And then you'll get a flash of light mode, and then it'll flip to dark. So the only way around that that I've ever found is with some blocking JavaScript. So you do a very short little script tag before any of your HTML renders, and what that will do is it will check if local storage has that value set, and then you can put it on the HTML before the, any of the CSS has been applied to it. It is blocking, so it stops everything else from running, but it is fast enough that you don't get that little flicker.

Scott Tolinski

Yeah. Well, you could also set the color scheme via CSS in server side rendering so that it's there on the initial load if you have it saved in a cookie. Like, if you have that, parameter saved into a cookie, you could then have that available on the server to get written so that it's a part of that initial HTML payload as well if you're doing

Wes Bos

server side rendering that way. But but if you're if you are getting into caching, especially if you're getting into sharing caching Oh, yes. Then it's a pain. That's what happened on Syntax website. Like, Ben had, like, some weird wave race theme set on the Syntax website, and he was, like, the first person to visit a page. Like, the the cache clears every, like, five minutes or whatever.

Topic 17 18:44

Set color scheme in server rendering

Wes Bos

And then randomly, some pages would have the wave race theme. I love Node wave race. JS going on here? And it was because we were server rendering that value. So if you are rerendering every single time someone visits a page, you're not doing any caching. You're not sharing caching between users. Right. Yeah. That's probably fine. But caching ruins my life.

Scott Tolinski

Yeah. I know. Right? No kidding.

Wes Bos

Tailwind CSS has a really good snippet for how to get that that JavaScript in there. And Tailwind CSS obviously has their own implementation of dark mode as well. They work the same way, but you can simply just prefix your values with dark colon, and then that will allow you to flip the colors. Next up, we have shoehorning in dark mode. So, like, let's say you have a website that was not built. This is my own personal website.

Topic 18 19:59

Converting site to dark mode

Wes Bos

It's not built for dark mode. How do you shoehorn that in? And in most cases, it you should hopefully, you've used CSS variables throughout your application. If not, it's probably a good time to refactor your CSS and say, like, anywhere I've used, like, this hex code, replace that with a variable called white and and and dark and and whatnot.

Wes Bos

And then you can kinda go through the whole process of of what we've done as well. It's simply just Wes you Yarn in light and dark mode, you can flip those, the values of those variables.

Wes Bos

It's I think it's a relatively easy thing to do if you don't have a ton of hard Node hex values, and you probably shouldn't have that anyways.

Topic 19 20:45

CSS variables make conversion easier

Scott Tolinski

Yeah. And and it also can find, like, color drift Wes your variables have drifted slightly here and there, and maybe you have, like, three different hex values for a color that's similar. I hate to say this, but, like, AI is pretty dang good at, doing that task. You can say, convert my convert all of my hex values into CSS variables. And, obviously, you check to make sure the work is good, but, like, I found that to be a task that AI is decently suited at because it won't, won't goof up your thing. It's just a, like, a fancier find and replace at that point. Yeah. So yeah. I I would say definitely good at that. And, like, it can handle context much better than, like, a like, a regex or something.

Scott Tolinski

Totally. Yeah. Which I found to be tough sometimes, especially, like you said, if you have that color drift. And then once they're all in variables, maybe that's where you find the color drift, and then you can do find and replace to make your stuff a little bit more aligned.

Scott Tolinski

Mhmm. So, yeah, once you're in CSS variable land, you know, to me, I I yellow throw a light Yarn mode on there and just see how it looks and then start repairing with the light and dark function where needed is really what it comes down to. Yeah. Yeah. You could probably get, like, what, 90% of a website done with simply just swapping variable values.

Wes Bos

And then you have to sort of go through the cases where it doesn't look good. Right? Because it's not simply just changing the colors.

Topic 20 22:01

May need manual overrides

Wes Bos

Sometimes things just don't look the same way when you invert their colors. So then you kinda go through and say, alright. Well, in this case, I need to override

Scott Tolinski

the text color or or the border on the specific element. Word. What about other things to consider here? One is color contrast. You Node, color contrast is something you're gonna have to manage manually at this very moment. The contrast color function in CSS is kind of MIA, which is it's always kind of weird because it's just it feels like it's been in limbo for for so long here in terms of where this thing is. And I don't have any reports on, wind color contrast or, contrast color. They've changed the name a couple of times, when that will be available. But I did find this this new ish post from May of last year from Le Verou about emulating color contrast using color mix.

Scott Tolinski

And, I think it's using color mixers or it's using a relative color. And, man, this JS a brilliant blog post. I'd never seen this until today. I can't believe I haven't seen this post, but go go and read this whole post because you can get pretty dang far with today's CSS features to emulate a degree of contrast color Mhmm. Which to me, this is something I've been reaching to JavaScript for forever and ever and ever. So there there's some really neat stuff inside of here, for getting contrast color with just CSS at the moment right now. Yeah. The reason why they haven't rolled it out yet is they're still trying to figure out,

Topic 21 23:45

Still issues calculating contrast

Wes Bos

can you like, what's the algorithm for calculating contrast to color? Because there is like, in dev tools, they'll tell you if something's not perfect, but, like, there are lots of edge cases where things just don't look right even though mathematically, they do have a high enough contrast. So you'll have to think about that. As well as, like like, even on the syntax website is the the yellow doesn't necessarily if the yellow text is too small, it doesn't look good. Yellow doesn't look good on white in general. So, like, it that's that's something we have to go through and say, alright. Well, it's yeah. We can flip between white and black, but our primary color yellow is staying there. But there are lots of cases where we'll have to change things, where maybe we should flip the logo to white in that case, or or maybe there needs to be a background on something.

Scott Tolinski

Yeah. Totally.

Wes Bos

I have that with my my logo right now.

Wes Bos

I cannot figure out how to make it look good

Scott Tolinski

on Yeah.

Wes Bos

On, in dark mode. I just like I'm I'm at a point now where I'm like, do I just put a background on it or or something like that?

Scott Tolinski

There's a a really great even, like, demo in the Le of Aru post. It's like showing a teal background with some white and dark text, and they're basically saying, would you believe that the, the white text fails and the black text version? But when looking at them, the white text is clearly more readable. So, yeah, there's a lot there. Even Totally. Even just white on red is inaccessible. Yeah. Like like, YouTube's red. It always looks better.

Wes Bos

Yeah. It does.

Wes Bos

ESLint doesn't make sense to me. You know? Let's talk about icons and and images in general.

Wes Bos

If you need to swap the source of an image, based on light or dark, then you have to use a picture element with multiple source tags, and those source tags themselves can have media queries. So you'll have picture source whatever light dot Pnpm, and then you have a media query in line right on that element.

Topic 22 25:46

Can just change SVG fill color

Wes Bos

If you're using SVG ESLint, you can simply just switch the fill color with CSS, which is really nice Wes you're able to do that. That comes with a bunch of upsides and downsides.

Scott Tolinski

If you're bundling the SVGs in your application, that can be a little bit big. But it's really nice to be able to simply just change the fill color and call it a day. Yeah. Those are these Yarn, like, what you're getting into at the end of the project when it's like, alright. I gotta test everything. Then you add if you choose to add color schemes, which I can't recommend, then you gotta deal with all that stuff too. So hey.

Scott Tolinski

The whole thing, again, you'll want to always check all of your modes for accessibility.

Topic 23 26:26

Ensure accessibility in all modes

Scott Tolinski

We've talked about this in the contrast color bit. But the best way that I do that is using the browser Polypane, which will give you any alerts about any accessibility items throughout your site, not just color based. So Mhmm. I always throw my app into Polypane. And I usually develop quite a bit in Polypane as I go to make sure that those those things are taken care of. But it's it's important to make sure that you do have, enough contrast there. You have the,

Wes Bos

the right colors and everything that you you need. Beautiful. Alright. I think that's all we have for light and dark mode. Anything else to add?

Scott Tolinski

I don't. Yeah. Let us if you have any, pro tips and pro techniques for light and dark mode, let us know. We wanna see how you're doing it. Are you doing things differently than we are? Drop a comment below.

Scott Tolinski

Smash that subscribe button. Hit the like. All that good stuff, and we will catch you in the next one. Peace.

Share