Theming Tailwind with CSS Variables

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we're going to take a look at how we can make multiple themes or skins for telling css leveraging the power of css custom properties or css variables let's get straight into it right so let's take this call to action bit of ui here and imagine that we want to create multiple skins or themes for it i'll just give ourselves some room for the code here this call to action is using multiple shades of the blue color let's say we wanted to create another one of these which uses red color shades so i could grab the entire component here and duplicate it and come here in our new component and grab all the instances of blue so there's another one two three and change that to red and now we have two pretty good looking call to actions with different skins this is not technically theming though this is just two different components or blocks of markup one could argue that a real theming approach would mean that you don't change any classes on your markup you take the exact same block of html and then depending on the theme that is applied things look different so let's look at how we would go about achieving this in a utility first css a presentational class names world so for example we could have a theme primary class here and this by itself would apply different styles to the component to do this we're going to leverage the powerful css custom properties also known as css variables for this example i want to focus on the colors only so by theme we're just going to change the color scheme for each skin okay so the first thing to consider when making an interface steamable is the naming convention we're going to use for colors we want to steer away from hard coded curl names like for example here bg red 700. instead we want to go for a name that doesn't make any design assumption and rather opt for a more semantic descriptive naming convention to get started let's take a look at our component and try to identify what sort of themeable colors we want to be working with here so if we start with text you can see that we have this white color here applied to the headline and also this button we have a slightly muted version of this color for the paragraph and then we have an inverted color for when the text is on white background color so in terms of descriptive semantic names we could think of that as here the text base this could be the text muted and this could be the text inverted so let's jump in our css file and we're going to declare a few css custom properties to represent these names that we've just identified so i'll come down here and we'll do our work in the base layer so at layer base and now we'll define default values for our css variables so we want them to be available globally so we can use the root scope for that we'll start by defining our base color and we can call this color text base and in the case of our default theme this is just going to be white so ffff next we'll have our text muted so color text muted and for this one we're going to go with c7d to f e finally we'll have our inverted text color here so color text inverted and that one will be 4f4 6e5 alright so i think we're good for our text colors here and now we're going to look at the background colors that we want to work with the most obvious one we have here is the background color or fill color so i'll declare this one as color fill 4338a and then we have our different buttons here so this is the primary button or the accent button and this one might be called the muted button so let's go next with color button accent and here it's going to be white as well so fff fff and notice that when i hover over this accent button there's a slight color change so we'll also have a color for the button accent hover color button accent hover and that color here will be eef2ff and i'll just move that to make things align nicely and i think we've got one more color to handle for the muted button the hover color change is actually a background opacity change here so we'll just use one color color button muted and we'll go with 6366f1 so we've now defined seven css variables and the name of these doesn't contain any design opinions cool so now with this in place we want to go and create themeable tailwind utilities so let's head over to our config file remember we want to use the exact same utility class for everything so instead of using different keys for each theme we want to use a single key that encompasses all the different possible themes and i'll use skin so for the text colors i will extend the text color object i can open my skin key since we already came up with names in our css variables we're going to mirror this naming convention but we might skip the text word and just use base here so now in here we're going to use our css variable value and the way you consume a css variable is by using var and then the name of the variable so in our case it's color text base so let's test that out and what i'll do is i'll duplicate the call to action and i'll adjust the window once again and now we're going to replace the hard coded colors in our first component with our themable utility classes so we've identified this text base color to be used in two places the first one being this h2 tag here so i'll go find the hard coded text white color and instead of white we're going to use skin and we should have the text skin base available yep and let's save that and so now nothing changed because the css variable is holding the white color so this is the exact same color but let's come in our css and change here the value of the text based color and let's make it black instead so zero zero zero zero zero zero and you can see that it has adjusted to the new value of the css variable so it's working well it looks like it's working it's almost working but as you'll see in a little bit there's a subtle detail that we need to address and we'll do this at the end of the video so let me revert back to ffffffff for white and we'll go back in our tailwind configured add more colors so let's duplicate that one and this one instead of base and i can also select the name of the variable is going to be muted and i can do that one more time select both and this time it's going to be inverted okay so let's add our other colors and this one will go in the background color object because they're background colors again i'll open a skin object inside of that the first one here will be for the fill color so fill and it's going to be var dash color fill i'll duplicate that the next one is going to be button accent and here it's also button accent we have the hover variation of this so i can select both button accent and add hover at the end and we have one more for the muted button so here accent hover is going to be replaced by muted so that's our seven colors mapped to the seven css variables that we've defined there's one extra little thing that we need to make themable it's not directly obvious on this design but if you look at the background image you can notice that it's more visible on the bottom right than it is on the top left and there's actually a gradient overlay that goes from a solid color via a solid color to a transparent color so if i go in the html and actually remove this for a second you will see what i mean now we can see the image through the entire call to action and the text is a little bit harder to read so what we've done here is layer and absolutely position div over the image and have a background gradient to bottom right and the from and via colors are the same solid color which happens to be the same color than the fill so we're going to reuse that css variable and then finally the 2 value is set to transparent so this overlay is going to use the color fill css variable because it's always the exact same as the background color but since it defines gradient stops we're going to extend another object which is the gradient color stops object once again let's scope out to a skin object and we'll call this one hue and like i mentioned we'll consume the same css variable then the fill so color fill right so now we should have all our themeable color utilities available so let's go and replace the hard credit values in the first component here with our themable color utilities so we want to replace all the hard coded color values and essentially that's anything that contains red so you can see there's a bunch here but also white because we have this white hard-coded background color and oops remember how i mentioned that the text white color was used for the heading tag but also for the muted button here so we also gonna change this with text skin base like we've done here for the heading tag so starting from the top we have first our bg red 700 here which is our fill background color so instead of bg red 700 i'll use skin and we've called it bg skin fill so when i save this the color should become this color fill color which is our purple indigo color so you can see that the background color is actually correctly applied to this indigo color but we have a gradient overlay on top of here and if i come down here you can see that we have from red 700 and via red 700 and both this red 700 can be replaced with the skin dash hue color that we've defined for the gradient stops very nice moving down the next instance of red i believe is this text red 200 which is our color muted so instead of red 200 i'll go with the skin and we'll go with text skin muted perfect so next we're going to take care of our buttons i can see some text red here so for the first link instead of text red 700 here we're going to have our inverted text since it's on the background that matches the base color so text skin inverted and here the background white is going to be instead skin and since this is the accent button background skin button accent finally our hover state instead of bg red 50 we're going to have bg skin button accent hover utility so let me save that button and you can see the text with the correct color and when i hover we have this subtle very light purple perfect just the last button to go so we've already applied the tech skin base which is the white color and then this bg red 600 will become instead bg skin and you tell me which one button muted and let's save that and here we go we've now completed our themeable component which is now ready to welcome multiple color schemes now if we compare our themeable component here with the hard coded component below if you have attention to details you might have noticed something that actually is not working if i look at the muted button here you can see that we've lost the hover effect and we actually have a full solid background color we've lost the transparency the opacity of the background if i come down here this button here changes opacity on hover turns out that the way that we've implemented the colors here in our config works fine with solid colors but it doesn't support opacity utilities with what we have here all the colors will be always 100 solid even if we try to apply text opacity or background opacity utilities like we are in this button muted i'll show you at the end of the video how to fix this but before that let's create a few more themes and see how a component handles them because after all we've done all this work of creating custom css variables naming them properly to be able to support multiple themes all right let's quickly get rid of this reference component because we've implemented it properly and let's do this our current default css variables here are scoped to the root which means that they're available globally one super cool thing about css variables is you can redefine their values at any point which means that you can create new scopes where the values that this variable holds is different so let's create a new scope and i'll create a class here that's called theme swiss because why not and inside there i'll actually copy all these seven custom properties and we'll redefine them with different values so let me really quickly change that and i'll repeat the same process one more time to create one more theme and this theme we're going to call theme neon and again i'll fast forward while i change the colors and there we go so you can see we have now three themes or the default theme and then two themes theme swiss and neon that redefine the same variables with different colors so now i'll go in the html and i will triplicate this component to 3. so now we have three times the exact same component but it's technically able to receive a theme so let's go to the top here and let's test out the scoping of our themes so if i take the wrapping parent here which wraps the three components and here i apply the theme swiss class all our three components should now become swiss and look at all this red and white it's working on all three components but now if i move the steam class away from the wrapping parent and i apply it just to the first one only the first element should be swiss themed and then the other two still have the default so we're gonna go and we leave the second one as the default theme so we don't apply any class and the third one here will have the theme neon class to use the other theme so let's make that bigger now and so we have a swiss theme here our default theme and our neon theme and as you can see the neon has a text which is darker than the background so the text inverted here is actually white on dark instead of being a color on white and this is why we carefully name the text color text base and text inverted instead of text light and text dark so like i promised before we wrap up i want to show you how to fix this transparency thing where we have broken the opacity support for our colors what's coming up now is specific to colors in talwin and we first need to understand how teluin handles colors under the hoods so i'll just make a quick simple example to illustrate what's going on here right at the top of my html i'll create a little rectangle here so we'll have classes of first m6 to get some spacing we'll have a height of 12 a width of 12 as well and some rounded corners for no other reason than making it pretty and now here's what's important i'll go bg indigo 500 and also bg opacity 75 and here we have our 75 opacity indigo rectangle so looking at what css is actually generated by these utilities helps us understand what's going on if i hover over the background color you can see that tailwind first defines a css variable tw for tailwind's background opacity and sets it to one and then the background color is an rgba color and it's defining the values for red green blue and then for the alpha transparency it's actually using this twbg opacity color variable if you apply a background color by itself on an element because telling defines this background opacity to 1 and the color will be completely solid as you expect when we also add a background opacity utility to an element all it's doing is redefining the css variable to the amount necessary so here we have background opacity 75 so it's going to redefine this css variable to 0.75 so going back to our bg indigo 500 this value here is now overridden with 0.75 from this utility here and so the background color becomes a transparent rgba with 0.75 for the opacity layer the exact same principle happens with text opacity so tell when defines a text opacity css variable and sets it to 1 and then uses that css variable for the alpha transparency layer of the rgba color the reason it's implemented like this is there's actually no such thing in css than a text opacity properly or background opacity properly there's an opacity properly that lets you control the transparency of everything on an element but the only way to achieve a text opacity or background opacity is by using an rgba color and play with this alpha channel that will decide of the opacity okay so let me remove my little example here and now let's go figure out why it's actually not working with the way we've implemented our colors with css variables in our config file so if i take any of our themeable color utilities like for example the first one bg skin fill we're not defining here a tailwind background opacity variable we're literally just setting a background color which is the css variable so let's now go find our button muted which is supposed to compose opacity as well so i'll scroll down here and okay so here we have a bg skin button muted and once again you can see that there is no opacity variable and we're not composing an rgba value and passing this opacity variable as the alpha layer so what happens now when we want to add an opacity like here all we do is redefine this bg opacity variable but this is not used in the background color so it's going to be completely thrown out and ignored and the color is always going to be 100 opaque so if we come in our config file and look for the button muted color here it looks like currently we're literally just passing the button muted color css property which is just a hex color so it looks like instead of doing that what we want to do here is pass an rgba color and here use our css property for the color and then compose this with somehow an opacity variable but how do we get this opacity variable where does it come from well turns out that you can access this opacity value that tailwind handles internally by defining colors as a function instead of just a string so here i'll delete this and instead i'll define a function and now as an argument of this function i can receive the opacity value from tailwind so now here we want to do something like rgba var color button muted and then interpolate the opacity value here except this color button muted variable is currently a hex code we instead want values for the r g and b channels of the rgba color let me make a quick example so a color is a hex code so let's say ffff00 which is yellow and instead what we want is to have something like two five five two five five zero which is the rgb equivalent of this so if i wrap this in a r g b a color you will see that it's the matching color and then we want to have the alpha channel coming from the opacity variable and if it's one it will be full if it's 0.5 it'll be half transparent 0.1 almost transparent etc so what we want is these three values r g and b so there's many different ways that you can transform a hex code into rg and b channels but at the end of the day if we know that we want our g and b comma separated values we may as well define the css properties like so so let's try implement that as an example on the muted button for the default theme so i want to replace the value of this variable here and instead of the hex code i want the r g and b channels so you can easily find online a converter for hex to rgb colors but here in vs code i have an extension that allows me to do just that so you can see here i have this convert hex to rgba option and this is going to give me the rgba equivalent and now i can go and remove the rgba at the start and also remove the alpha transparency channel because we just want the three values for r g and b and now if we go to our default theme here you can see that we've completely lost the background color and it's because we need to implement that in our config file so let me remove that and we're receiving an opacity value and what we want to do is return and we'll go with rgba var color button muted which is now rg and b channels so we can compose our rgba with the a channel which is our oppa city value now we shouldn't make the assumption that opacity value is defined necessary here so i'll just add a guard block and say if opacity value is not undefined then we can return this and if it's undefined what we can do is return rgb only with our var color button muted okay so let's try save that and if we've done things correctly it should work again and yeah great you can see now on hover we have this opacity change and you can see the image of the microphone go through the button perfect so let's update our css variables definition for the swiss theme and the neon theme because they're still using hex colors for now so i'll scroll down and for both my color button muted properties i'll select both and i will once again transform hex to rgba remove the rgba and remove the alpha transparency to just keep the three channels that we want and let's check it out the swiss theme is working the default theme is working and the neon theme is working perfect the muted button here is the only place in our ui where we've used an opacity utility but we shouldn't make the assumption that this is the only place where we want to actually support opacity properly realistically we want this to be the standard and every color utility to be able to support this so to wrap it up let's quickly go and implement support for this everywhere now i'm pretty confident that you don't want to be writing this code for every single color definition so the first thing we could do is abstract that away to a function that gives us the opacity value so i'll come to the top of my config file here and define a function that'll call with opacity and this function will receive one argument and it's the name of the css variable that we passed to it and this function is actually going to return another function which is where we're going to receive our opacity value and this function in turn will return what we had before so it will check if the opacity value is not undefined if that's the case it's going to return an rgba value with the alpha layer using the opacity value and otherwise just an rgb but instead of passing the hard-coded variable here in both places we want to use the variable name that's been passed to the function instead so variable name so let's go down here where we've used this and instead of doing all this work down here now we can just call the with opacity function and pass the name of the variable we're not going to pass this var call because up here we're already doing the varco so we just pass the string of the css variable that we want and here it's color button muted so now if i save this and with a bit of luck everything should still work properly and also if we look at the output of the html markups so here i'll go on the bg skin button muted you can see that once again we're now defining a background opacity value and this is using this internal opacity value that we've grabbed from the function and then we defining the background color as an rgba we're using our rg and b channels from our css variable and then using the internal bg opacity variable to handle the opacity all right so you're almost completely done let me just do a little bit of magic here i'll select all the hex codes so i can select just the first pound signs to make sure i've got all of them and then select the whole color and now all in one move living dangerously i am going to transform these to rgba boom look at this and then for all of them i can remove rgba and the 1.0 alpha layer so now all our colors are defined as rgb so it's going to break everything so now we're going to implement this with opacity function everywhere so let's see if we can do a little bit more multi-cursor magic so i'll select v-a-r and this everywhere and i'll replace this with width opacity open the parenthesis and the quote and then at the end i will move my quote inside the string it looks like every color is calling the width opacity with a string with the css variable so let me save and everything should fall back in place perfectly nice and that is it thank you so much for watching this comprehensive tour on how to handle themable components in tailwind css while making sure that we support color opacity properly along the way alright i'll see you in the next one bye for now you
Info
Channel: Tailwind Labs
Views: 30,550
Rating: 4.9753928 out of 5
Keywords:
Id: MAtaT8BZEAo
Channel Id: undefined
Length: 27min 24sec (1644 seconds)
Published: Tue Mar 30 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.