Kevin Powell expertly showcases how contrast-color() shifts the burden of accessibility from fragile manual logic to robust browser-native intelligence. This property marks a definitive step toward a future where inclusive design is a default behavior rather than a developer's afterthought.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
Build bulletproof color systemsAdded:
Hello, my front-end friend. Contrast color is now here. It's part of CSS. It is baseline newly available, meaning it's in every browser. People always say, "Kevin, you're only looking at things I can never use." This one is newly available, meaning h maybe not quite yet, but we're getting very close.
And I want to show you why you should keep your radar on it and pay attention to the browser stats, or if you're working on a new project, why it might come in handy, cuz we're going to look at the classic of all demos of buttons.
But anything that deals with color theming, this opens up a lot of possibilities. people are doing web components I think might get very excited about this but even other types of components too. Um I think this can definitely come in handy and the button is just a nice simple way to take a look at it. And so we're going to start this by looking at uh how just the basics of how it works and then we'll move into a bit more of a involved setup but it would about how I'd actually use this if I was going to be doing it in production. So at the very basics um I have first of all I have these like themes for my buttons. Again, we'll come in with those in a second, but let's look at how this would normally work just by uh exploring the the basics here. We'll clean this up a bit and dive in with a uh background color. So, background color is going to be my var and we'll use neutral 100 for now. So, we're actually going to switch this over to 900 so you can actually see it and it's going to become very close to white. Uh, and now we can't read our text. That sucks. So, what can we do to fix that? Well, we could declare an actual color here, obviously, or we could say color is my uh contrast contrast color. And in the contrast color, I'm going to do the same color that I actually declared as my background. So, we're going to copy that, paste it in here, and like magic, the text will update. Cool, right? Uh we'll say our and hover and focus is going to have a background background color of let's say Rebecca purple and then once again the color of it will change. So the color of it now will be my contrast color. Same function as before but in here we can once again drop the Rebecca purple and remember to have a semicolon at the end. And now when I do that the text color changes with it. Cool, right? And I'm not actually declaring any color. It just goes, "Oh, this is the color that we're going to." And I want to take a contrasting color to that. And it will work with white or black. And I know for some people that will be a deal breaker cuz you might have other colors you have to put in there. If it is a deal breaker, let me know in the comments below. Uh there was an old version or the original version of the spec which was color contrast instead. And that would actually allow you to put the color you're like the background color you're going to be using and then a set of other colors and it would pick the best one. I think the problem with that was what happens if there's no minimum.
I didn't read about why they actually changed it. I should have kept a closer eye on things there, but this is the current implementation. It is possible we get more things in the future, but for now it will always be either white or black. And I'm really happy with it.
But let's see how we can actually use this in a way that's a little bit easier to set up and to use. So, I'm going to start by taking both of these off and I'm going to actually come up to here and I'm going to set something that's going to look a bit weird. You might have seen me do something like this before, but I'm going to do a custom property with an underscore at the front. And we'll see why in a second.
Uh, but we're going to call this one button uh button surface. And my button surface is going to look for a variable called button surface without the hyphen in front of it. And this was an idea that was proposed by Leavu uh a while ago as a private property essentially.
And we'll we'll explore the the benefits of this. Uh but it it looks a little strange when you're setting it up, but it is worth it. And the reason it's worth it is we're going to look for a button surface. And this is not declared anywhere. So on here, I'm going to also have a fallback value of let's do another I'm going to do white. Uh yeah, we'll do white as our our fallback. I would normally do another custom property here, but it starts getting kind of long for a demo. So, we're just going to say white. And so, then I'm going to set another one. Let's do a button surface uh hover now. So, hover.
And we're going to say var. You guessed it. Button surface hover without the underscore. And let's make this one.
We'll do fire brick this time just to have a a different color when we hover as a default. And that means we do need to set those up. So here this will be my var of with the underscore button surface. And what that means is uh let's just copy this here. Copy that. Whoops. Copy that and paste that here. And let's check if it works. And then I'll explain it if you're a bit confused. Uh it is not currently working cuz this one should be or it is working. Sorry. It is white. Uh and then we want to do the same thing in here but where both of these are going to be looking at our hover instead. And let's fix my indentation. And with that done now, there we go. It is working.
And so what this is doing is it's looking for my button surface. So it goes and looks what's my button surface.
It's looking for this variable. This variable isn't defined anywhere. So it's going to white. And then my hover when I hover on top. Same idea. It's looking for my surface hover. Goes to look here.
That's looking at this. This isn't defined anywhere. And then it goes to the fire brick instead. And you can see the color is automatically changing because the contrast color is getting that automatic change. And why this is useful is now if I want to make changes, I can go and I'm doing my modifier here with a data class. If you'd rather do this with a modifier class or I said a data class, a data attribute. If you'd rather make your modifier with a modifier class, that would be completely fine. But now what I can do is without the underscore, I can come in and say my button surface is going to be let's do my var. I have a primary set up and then my uh let's just do primary. So you can see that one has changed and the color of the text is automatically changed because it's button surface which is getting here that's going over to here.
You know the layering is happening but the contrast color is kicking in and working. And then we can say the same thing here. Button surface is going to be my var of accent.
And when I do that, that one will switch over. And super duper, except I need my hovers. Really quick interruption here.
Sorry about this, but I as I was editing this, I realized I forgot to mention I have my script. It was in there and I didn't say it and I really need to mention it that I'll be speaking at both CSS day and ZurichJS this year. So CSS day, the name says it all. It's the CSS conference. The lineup for it is just mind-blowing. Imposter syndrome is hitting me hard just looking at it.
Yeah, that is happening on June 11th and 12th. So that is coming up like incredibly fast. So, if you don't have tickets for that and you plan on being able to make it or you didn't know about it and now you want to go, now is your chance to go get some tickets for that.
And ZurichJS is happening on September 11th in Zurich as the name implies. And that one also bit of a different vibe I guess from CSS day being a JavaScript conference, but I'll still be there talking about CSS. Uh, and so that one, as I said, is happening on September 11th. So, a little bit more time to plan for that one. And of course, if you're able to make either one of them, make sure to stop me and say hi while you're there. With that, let's jump back into the video. And now for the hovers, there's different things we could do, but in my root, which is in another file. I'm not going to worry about it.
Uh, or did I put it at the top of this one? I did put it at the top. I don't have like variations of these. I just have my accent in my primary. You might, but let's throw in another fun CSS property here. Uh, I could use a relative color, but let's say I know I just wanted to get either lighter or darker. Um, we could do that. And actually my neutral colors here, I'm going to use my neutral because there's a light dark on these. So for my button surface hover, I'm going to do a color mix. Again, you don't have to do this.
Uh but we're going to say color mix. I'm going to mix my var of primary with uh oh, and we have if you're doing a color mix, we have to say what color space we're using. So I'm going to say in sRGB.
We can always change that if we need to after. It's the one that just came to mind off the top of my head. Uh, so we're going to mix my color primary with var uh neutral 100. Let's see what that gives us. It might look a little bit weird. Uh, so there we go. We can actually that that's working better than I expected where we can see it's getting darker and this one is actually getting lighter which is interesting. Oh, that's only on my primary. Okay, that makes sense. This one is getting darker.
I don't know why that one's actually getting Oh, the lighter is going to fire brick. That's why. Uh, so we can do the same thing here, but just switch this out for my accent. And in switching it out for the accent, now both of them get darker. Now, if I wanted to, I could actually make this a lot darker. We can mix it with like 90% of my neutral 100.
Uh, and that would work where now it's going to get like super dark or we could say it's only 20% of each one of them.
And now it will only get a little bit darker, like barely at all. So you could find the balance that you want for these uh which is interesting. And let's just say we are doing it where we'll do it the other way around actually. Let's say these are with my 900 which is white. So it's going to lighten them. And now when it lightens them you can actually see the text color is automatically switching for both of those as well when that happens because the color contrast is kicking in. It's automatically working. Uh it's super cool. And right now these are lightning or sorry these are dark. Yeah they're lightning. And let's come in. I'm going to open up my dev tools here and I'm going to go to this paintbrush in Chrome and I'm going to choose prefers color scheme light. And now they're actually going to darken a little bit. So you can see those getting darker. This one's the same, but these two are lightning and darkening. And the reason for that is if we look at the colors that I'm using on here, my neutral 900 is actually using a light dark right here. So if it's a light color scheme, it's the neutral 900 is dark. And if it's a dark color scheme, my neutral 900 is light. And so it's automatically working for those. And the color contrast is automatically kicking in depending on what the contrast is based on the color. It's also cool. And modern CSS is amazing. If you'd like to learn more about light, dark, there is a link in the description to a video that takes a little bit more of a look at that. And if you're interested in stepping up your CSS game and starting to write it with more confidence, I'd encourage you to check out my course CSS demystified, also linked down in the description. And with that, I'm going to say a very big thank you to Johnny, who's my enabler of awesome, as well as all my other patrons and channel members for their continued support. And of course, until next time, don't forget to make your corner of the internet just a little bit more awesome.
Related Videos
Agentforce NOW AMA: Build with React and Salesforce Multi-Framework
SalesforceDevs
490 viewsβ’2026-05-28
How agent o11y differs from traditional o11y β Phil Hetzel, Braintrust
aiDotEngineer
450 viewsβ’2026-05-28
WEB TECHNOLOGIES UNIT-2 | Degree 4th sem BCOM Computers web technologies unit-2 full explanationπ―β
LearnwithSahera
1K viewsβ’2026-05-29
More tests are always better? How to use AI to identify tests that bring little value
Alliance4Qualification
335 viewsβ’2026-05-29
Search Algorithms Explained in 60 Seconds! π€π¨
samarthtuliofficial
218 viewsβ’2026-06-01
People of Game of Thrones using JavaScript DOM
AltCampus
296 viewsβ’2026-05-30
Introduction to Problem Solving Part - 1 | Lecture 1 | Intermediate DSA
ascensionix
107 viewsβ’2026-05-29
So What's Odin Lang Even Good For
TechOverTea
131 viewsβ’2026-06-01











