 These days, some websites have multiple different color themes available to them, which is just really awesome, and luckily thanks to modern CSS is actually relatively easy to do. Hello, my front-end friends! Thank you so much for coming to join me once again, and if you're new here, my name is Kevin, and here at my channel I help you fall madly, deeply in love with CSS, and modern CSS solutions just take a lot of the old pain away, so I think that's one of the nice ways that we can use it to fall in love again with CSS, and today I want to look at color theming. We're going to be looking at how we can use modern CSS to do it with zero JavaScript, but then also how we can use JavaScript as a bit of a progressive enhancement, and the only issue with the CSS we will be using today is browser support isn't perfect, so at the end we'll wrap it all up by looking at how we can add a couple of lines of JavaScript to do it all with that as well, so you can have perfectly good browser support. And so yeah, let's jump into the code, and as you can see here I have a sample page set up, and I've set up a few custom properties here. It's not really how I would normally name my custom properties, but I wanted to make it really obvious what each one was doing for this type of demo, and so we have the body's background, the card background, the text color I'm using, and a heading color just so we can separate the two, and then I'm using those, so on my body I have the colors set up, my heading I'm using the color there, and then if we find my card I have the color for the bg set up there, so just really fast if I change my heading here to have like a 70% we should see that a little bit of red comes in, maybe make that a 50, and as you can see there we go, this is controlling all my headings, and so on and so forth, I think it's pretty straightforward how it's working. So what we want to do takes a little bit of work, our initial setup I should say, because we need first of all something that will allow us to change between the different colors, and so we're going to be using checkboxes to be able to do that, and I'm just going to set it up right up here at the top, and we'll throw in a form right here, and inside this form I'm going to use a field set, and the reason I'm using a field set is first of all for accessibility reasons, it lets me put a title really easily by using a legend, and so here we could do pick a color scheme, and we're going to sort of hide stuff and make this look a little bit better as we go through, but let's do pick a color scheme there, and then we can come here, let's hit save, we should see it actually show up on the page, there it is at the top, so pick a color scheme, and then what we'll do is we'll come in with our different colors, so first we can have a label, plus we're going to have an input, and the label I'll put these each on their own line just so we can see things a little bit easier, and so we have our label and then the input, and so label for, and we can call this a theme, because it's our color theme, I'm going to come here and do this type isn't going to be text, type is going to be radio, and then here we're we have radio, we're also going to do the name is equal to theme, and we're also going to come here as well as the name equals theme, let's put word wrap on just to make sure we can see everything that's going to be on here, so we have the we'll do we'll do it like this probably be the cleanest way, the name is going to be theme, and then we can also give it an individual ID, and we'll make this one my light theme, so the current theme we have now, I'm going to say light, just like that, so we get light with a little checkbox there, now when the page first loads, if this is the default theme, it also makes sense for that one to be the active theme, so I'm just going to copy this, and then here so we have our ID, and then prettier was coming in and formatting that for us, but we'll also add a checked here, and the checked just means that by default that one will be the one that is checked, which makes sense, then I'm just going to come and copy this really fast, and we're going to put in two, three, four, five different themes, and I'll just update the different properties and labels here, and I'll be back in just one second. All right, so there we go, now we have the different themes set up along the top here, now it currently looks really really ugly, one thing I've already done, and I'll put a link to this more information on this visually hidden class, but I've already included it in my CSS, and that the reason I have this class is because I want to make sure I have pink theme, blue theme, like I want that text to be there, I want my label to actually be something that's labeling what the radio button is doing for accessibility purposes, but I don't actually want to see that because we're going to style this to make it really obvious how things are working, so on each one of these labels, I can throw in a class of visually hidden, if you're using something like Bootstrap, or you might also see SR only for screen reader only, I just find visually hidden for me makes a bit more sense, so you can see my pink theme has actually disappeared from there, so I can just grab this class, and I can drop that on all of these, so we're just going to quickly place it on all of my labels, save that, and now we just end up with the check boxes that are here, and I'm also going to do that on my legend over here, where we can add the visually hidden, so I end up with something that looks a little bit like that, again, it'd be obvious what's going on, or if you want to keep the choose a color scheme you can, but I'm hoping it's obvious enough for sighted users that it's not, you know, we don't need those there necessarily, so with that done, one more thing we should do is on this form come up and give this a class, and we'll call this color picker, just to make it easy to select in our CSS, so there we go, and now we can come on over to our CSS, and we can write in color picker, I'm just all the way at the bottom, doesn't matter too much, and the field set thing has like this default black border thing that comes around it, which is right here, so we can just say color picker field set, so if the field set is a direct descendant of the color picker, we can say border zero to turn that off, also going to come in and say that it has a display of flex, and we already have some spacing between the items, but the nice thing with the display flex is that we can use gap and say it's like a two rem, we can give it the background color, so we can, you know, distinguish it a little bit from our page, I could say this is a custom property instead, but I want to keep it white all the time, even if the other colors end up changing, I think, we could always modify that later, and I just realized on my body, I forgot to do a margin of zero to get rid of that, there we go, so that looks a little bit better, just really fast here, we have the display flex, let's also come in and say that the width fits content, so we can still wrap maybe if we ever had it to, even though it won't wrap now, this will just be, you can see it's fitting the content that's around it, we'll add a bit of padding here, right now it's using the default padding from FieldSet, so maybe I say that it's one rem on the top and bottom, three rem on the left and the right, and let's throw in a border radius here as well, zero on the top, the top two, and then maybe like a one rem, we can make it pretty big on those sides, and that's where my padding, we'll throw in a margin inline here of auto to put it right in the middle, there we go, so we have something that looks a little bit more decent, but of course it doesn't do anything yet, but at least it's in place, it's looking okay, we can now make those into like their individual colors, so to be able to make them into the individual colors, what I'm going to do is let's choose them, so we want my color picker, and then if we have an input that is type equals checkbox, since I didn't give these a specific class on them, it's probably the easiest way to select them with our attribute selector there, and then custom checkboxes are kind of annoying to do a little bit, but what we can do here is appearance of none, which is going to strip away, did I misspell that? I'm going it's not working, that's because I put a checkbox here and it should have been radio, because they're radio buttons, so appearance none, I thought I made a typo, but it's because I had the wrong thing there, and there's even thing, there's no checks in there, they're radio buttons as I was talking, but then I didn't anyway, whatever, appearance none, which strips away all the default styling from form elements or most of it, and then what we can actually do is give it a width and a height nice and easily, so we can say width is like, I don't know, one rem, and a height of one rem as well, and then we'll give them a border of 3 pixels solid, maybe, there we go, and a border radius of 50% to make them circles. Now the interesting part is when we want to be able to like change the colors, so people know what they're choosing and what theme they're actually choosing, I'm going to make these a bit bigger too actually, maybe 1.5 would have been better, 1.5, and the reason we can do something interesting here is I can do a var of, we'll do radio color, like that, and I'm not going to declare it, I'm not even going to put a backup in because it's sort of, the backup is the current color anyway, it's going to use the text color, so, oh that does break it, okay, so then we can just do current color, does that fix it? It does, I didn't know that would overwrite it like that, okay, so it's going to use radio color if there is one, and if there isn't it uses current color, which is like the og variable of whatever the current text color is on it, perfect, and then what we can do is on these guys, when I created them, we had the IDs that we put on there for like light, my pink has pink, my blue has blue, etc, so we can leverage that a little bit, just to make it a little bit more obvious, and I know we don't have to do this and it's raising specificity, but we already have an ID on there which is super high specificity anyway, it just makes it a little bit more obvious, and if you really wanted to, you could even do the color picker, some people might not like all of this and you just want to put the pink, but it just makes it super obvious that it's being used like in this context, I'm doing it this way, if you just want to put hashtag pink, you can do it that way, you could also give them all classes if you don't like the idea of using IDs, and then my radio color could be pink, and let's just hit save, and you can see that one is actually switched over, what's also interesting with this is the radio color there, now let's do two of them, just so we can really see how this is going to work, so I'll just copy or duplicate that one, so we have pink and then we had, I think one of them is blue, so then here, I'm just using quick colors here, blue put actual better colors in, but you can see they're, it's coming through and it's working, right, and now what we could do is for the fill color, so when one of them is actually checked, we want to fill that space in like a checkbox would, so to be able to do that, we can quite easily do it where we say, let's grab this selector, so when we have the color picker input radio and when it is checked, we're going to do a background color is going to be my bar radio color, so only if it's checked will it get it, so now when I go and I click on one of them, you can see it actually fills in, because what it's doing is when it is checked, it's setting the background color to that color there, and I just realized I'm using border, I'm going to switch this for outline, which looks almost exactly the same, you can see it's a little bit further out, the advantage here is we can do an outline offset of like three pixels, and now it actually looks more like the checkbox when it's filled in, so instead of that like completely filled in style, just a different approach that you could take for it, so that works really well, so I'm just going to very quickly copy this over and see you, you know, I've changed all the colors here and I'll be back in just a second, all right, I got all of that set up and now I can click through and you can see it changes between each one perfectly, so we can see which one is selected, now we need to make the magic happen, and to be able to make the magic happen, we're going to start off by using the has selector and see how that can work, then we're going to have to look at progressively enhancing it a little bit with a bit of JavaScript, and then at the very end we'll come through and look at if the has selector is not for you, how you can do it with just JavaScript, since has support is not perfect, but to start off with what we can do is we can say root has, and so I can say pink checked, and what that means is if the root so anywhere on my page has a pink that is checked inside of it, we can do whatever we want, so just as an example we could say here like font size of my whole page will become like 50 pixels, I'll throw an important on here to make sure it would work, and now if pink is checked the font size actually increases, so has is super cool, but you might have already guessed what I'm actually going to do is take all of these custom properties and I can just redefine them, and come here and put whatever values I want, so I already have some properties off screen here, so I don't have to do this the long way, and I can just come in and paste that in right there, and so now if I switch over to the pink scheme you can see it is switched over, and you can just repeat that over and over again for each of the different themes, so I'll be back in just a second as I do that, so here you can see I have my pink, my blue, we're checking if each one is checked, and when each one is checked I've changed the values of the colors that I'm bringing in, so now as I go through there you can see it is changing and we're getting all the different color schemes the nice and easy, I think that looks pretty cool, now the one downside of this is somebody picks the color scheme, they spend some time on your website, and then they come back another day and it goes back to the default, and then they have to choose again, so this is where a little bit of JavaScript and using some local storage can go a long way, so let's jump on over to my main JS here, and the first thing we're going to do is we're just going to we need to be able to get our form element basically, we want to get each of the check boxes, so we can say const color themes is going to be equal to document dot query selector, let's turn on word wrap here, and actually we're doing JavaScript, so we'll we'll sort of extend this out a little bit, query selector, and we want to get all of these, and there's different things we could do to search for those, but if we look back at our index, when we set all of these up all of them had the name of theme, and when you're using radio buttons this is what like connects them is their name, so because the name of oh I made a mistake there, I put the forest theme on each of these two, so this would actually be for light, and this would be my pink, we want to link that to the id not to the other one, so I'm going to fix that, sorry about that, but this would be blue, we do want to have the four here to be actually working properly, so our label has a purpose and dark there, I do apologize for that, but now what we want to do is focus on this name equals theme, because this name of theme that is on all of my inputs here is what's really important, and is what connects them all, so I think the easiest thing to do here is we can do query selector all, so we can get our list, and my query selector here we can use any type of CSS selector you want, so we can use an attribute selector up in here, and say that name is equal to theme, just like that, and so now we have access to all of them right there in our color themes, and I think that's going to be enough for what we want to do, so there's actually two different things we want to do, one of them is we need to store the theme when someone selects it, and then we need to be able to apply the theme, apply theme when someone loads the page loads, we want to apply the actual theme, so what we're going to do is do constant, we'll call it store a theme, I think that's a good name for it, and we'll just have it be a function, this function will take a theme here, so we're going to say theme, and what we want it to do is store the theme into local storage, so to do that it's just local storage dot set item, and then you choose the name you want, and the name you're putting here is the name you want to put it, so I'm just going to call it theme, and then here I'm going to write theme, now I'm writing theme and theme, that's just because what I've written up here is how we're going to be using this, now the reason that I have it set up here, and the apply theme is going to come in a second, let's get rid of that, we're just storing, we'll keep that there, but we're just storing our theme right now, and when do we want to store it, well it's anytime somebody clicks, we need to update that in our local storage, so what we can say now is our color themes and do a for each, so this just means we know we're getting each one of these checkboxes through this query selector, so we're going to go through each one of those, so each one of those we'll call it theme option I guess, for each theme option, so and again the word I'm putting here is completely you get to choose what that is, so we have all these different color themes, and for each one of those themes, you could even just put theme here for each theme, but just we'll say theme for each theme option, we want to do something, and what do we want to do, we're going to add sorry we're going to do our theme option dot add event listener, so we want to listen for a click, and if somebody clicks, we want to do something, so we'll put an arrow function right there, and what do we want to do, well we want to store theme, and we need to now pass in the theme that is being selected, the easiest way to do that is actually to do the theme option dot id, because the id of each one is what the theme's name is, right, so to give you an idea, let's hit save on here, we could use console log to find all of these things, but we can actually see if this is working by checking the local storage in the browser, and so when you're in your dev tools and you come and get to you know open them up, you should have an application tab, if you can't see the application tab, just click on this little arrow, it usually just means the dev tools are too small, so it's hidden away, and you should have an application in here somewhere, and you click on application and it will open it, it might not be on local storage right away, but you should see storage local storage, and then you should see the address that you're working on, because I'm doing local development, I see it right here, and if you have that open, I'm just going to move it off to the side here a little bit, but here you can see a key and a value, and if I click here we should see it set the key my theme to pink, and if I go to there it's now my theme of blue, my theme of green, and this is happening because what we're doing is we're getting all of our buttons right here, all of our checkboxes through our query selector all here, we're going through each one of those adding an event listener, so when we click on any of them, it's going to look at that item, and so it looks at like that blue there, and it's going to look at the ID on there, and it's going to store that as the theme, so it's actually passing say here it's passing blue in here, so theme is if we look back here, theme is the key, and then the value is whatever is being passed through, so for each one of those we're storing that theme in here, so storing the theme is great, we need to do that, but then we actually need to apply that theme, because if I refresh it doesn't do anything, so we have to tell we have to use JavaScript now to like explain to the browser how we should actually be using that theme, or that information is there in the browser, we need to know, say what do we want to do with that, so we want to apply the theme now, it does apply the theme, but we're going to call it rich, we wanted to get that information from where we just were right in reality, so what we're going to say here, we're going to call it we'll do a const of, or actually let's put this up here with our other one, so we're going to do a const of we'll call it retrieve theme is equal to function, this time I don't think we need anything in there, we're just going to do our function, and what do we need it to do, we need it to find that from the local storage, so here we're doing a local storage set item, what I'm going to say here is I'm going to do a const of active theme is equal to this, but instead of setting it we can actually retrieve or get theme, get item, so I can say get item, so I now have my active theme saved, we know we'll be able to get it, we have what it is, but we need to actually do something with it now, and because we're using has at this point to be able to actually like change everything over, the easiest way to just keep taking advantage of that is just to make sure when the page refreshes that the correct theme is actually checked, so we could do that by looping through and checking if the theme option or you know checking which one should be checked, so to do that we're going to do color themes for each, and so again for each theme option we want to go ahead and do something, so we're going to use an arrow function, and we're going to say if theme option ID once again, because remember the ID here is what we're grabbing, so when we do this active theme it's going to be getting the value, the pink, the blue, the different things we were seeing before, right, we're not getting the word theme, we're just getting the ID, so if the theme ID is equal to our active theme then we want to have that theme option be checked, and to be able to do that we just do dot checked equals true, so now this is in place, we have something that can retrieve the theme, we just need to actually retrieve it when the page loads, because right now it's never, this is never being called so it's never doing anything, we only really need this to actually run when the page does load, in general you're probably using a module or you're probably including your JavaScript at the end of the file or using a defer or whatever it is, but just to be safe we'll do a document dot on load is equal to, and then we can call that so it's retrieve theme, retrieve theme, and hit save, and so when the page loads it's going to run through this, it's going to loop through, or it's going to get the active theme, whichever one was stored in the local storage, and then it's going to see which one of those was the selected one, and it's going to switch the active checkbox to the one that matches the theme that was selected, and so if I click here, or let's go to dark mode, I'm always a fan of dark mode, if I refresh we should see it jump over, and it's not working because I made one mistake with the get item, because I copied and pasted it from up here, when we get an item, we can't have the theme here, and the reason I found that out is I opened my dev tools when it didn't work, and on caught reference theme is not defined, and so I'm like theme is not defined, and then I was looking at this going what's happening, but it's actually this one, so we don't need that because we're getting an item, so there we go it just worked, so if I go to my pink, let's go back to green, hit refresh, and you can see it does that little flash because it has to load the page, then the JavaScript kicks in and it switches it, you'll always get that little thing, I'm sure you've seen it on other pages too, that you visit frequently where the theme might switch to a dark theme after half a second, so there is going to be a split second little jump there, but you should be able to have it, it's stored in my local storage, it's retrieving it, and it's switching it to the correct checked one, and this is all relying on has, I like this solution with has, but of course browser support isn't perfect, so if you do want to make it completely reliant on JavaScript, whereas right now if the JavaScript doesn't load it just means that it always go back to the default theme, but at least the functionality is always there, if you want it to be fully functional with JavaScript because has support is not perfect, I'll be the first to say that at this time, and there'll be a link down below for has support, so if you're watching this in the future maybe you don't have to worry about this next step, but I am going to do one more, we have retrieve theme here, I'm going to do one more that we'll do it as a const set theme, and we'll even put a thing here, fall back for no has support, so this one is going to once again be a function theme, and what we want to do this time is very very simple, and it's basically I want to do, we're going to have to do two things actually, so one of them is to come back up to here, and on all of these I'm going to add in a class selector here, so I'm going to do pink and we'll do a dot blue, so like the class, if something has the class of pink it's also going to be using these, so then we can come here do my dot green, and the reason for that is we're going to be using this, dot green and dot dark, and the reason I'm doing this is because we're going to be applying this class onto the html element, which is going to be setting these that way instead of having the has selector do the work for us, which is this, in both cases root is my html anyway, so if the has selector is working it's changing my custom properties, if not we're going to be changing the class on my html, which is going to be changing the custom properties, and it has the same effect in the end, so to be able to do that what we're going to say is document dot document element, which is your html element, so our root right there, and we're going to say class name, and I'm not using class list add, because say it was pink, I don't want to be like pink, then blue, then green somehow, I don't know, whereas if you just use class name, we're just setting what the class name is on that element, and we want it to be equal to theme, so theme is what we're putting in there, and this is going to kick in when the page loads, so that's when we were retrieving our theme initially, we're going to not only retrieve, I guess this is also like setting our theme, I don't know maybe my naming on these could be updated a little bit, but then here we're going to get the active theme, it's going to run through this, and then we could, you know, in general what you'd actually be doing is you wouldn't be using this anymore, but here then we could do a set theme and active theme, and so we're going to do it the other way, except I just realized there's a problem, say I choose my dark theme and I refresh, it is setting the dark theme, but the checkbox isn't being selected, so we still want to make sure that it's actually, we're still using that because this is what's making sure the correct checkbox is on there, so we don't want that to actually be out, actually I think just looking at this, I don't know if we'd really need to do that with its own function, we could just sort of retrieve, retrieve, we could just call this set theme here actually, set theme, so we're getting what it is there, this is setting the checkbox, and then this we could just replace it with what we had here at the bottom, and again this is the fallback for no has support right there, so now let's just double check, it's still working, and if we go here and I refresh, it didn't work because we need this to be here set theme, when the page loads, there we go, it's all working, and if I refresh it's jumping on over to the theme that I'd picked, and there we have it, I think that's working pretty good, it works with has, it works with a little bit of an progressive enhancement, and a very simple fix here actually to add in the extra support if has doesn't work, so I hope you enjoyed this video, if you'd like to see more things that has can do, I have a video right here where I explore some really awesome stuff that you can also do with it, and with that I would like to thank my enablers of awesome who are Jen, Johnny, Michael, Mr. Dave, Patrick, Simon, Steven, and Tim, as well as all my other patrons for their monthly support, and of course, until next time, don't forget to make your corner of the internet just a little bit more awesome.