为之漫笔

_小生_正在翻译

Dynamic App Themes with CSS Variables and JavaScript

原文链接: itnext.io

Hello there! In this post I’d like to discuss my approach for creating a dynamic theme loader in a web app. I’ll talk a little bit about react, create-react-app, portals, sass, css variables and other fun things. Read on if this is something that interests you!

The app that I am working on is a music app that is a mini clone of Spotify. The client side code is bootstrapped with create-react-app. I added sass support to the CRA setup with node-sass-chokidar.

Adding sass to the CRA setup is not too difficult. I just had to install node-sass-chokidar and add a couple of scripts into the package.json file to tell it how to build the sass files and a watch them for re-compile during development. The include-path flag is to let it know where to look for files that are imported into sass files via @import. The full list of options is here.

With sass integration added, the next thing I did was start defining a list of colors that would be a base template for the app. It doesn’t have to be an exhaustive list, only the minimum colors needed for the base template. Next, I defined sections of the app where the colors would be used and gave them descriptive names. With these variables in place, they can then be applied to various components of the app that will define the theme of the app.

Here you can see I’ve defined a base set of color variables and applied them to the default sass theme variables. These theme variables will be used throughout the codebase’s stylesheets to apply the color palette to the app and give it life!

Next, I’ll need a way to easily update these variables on the fly. This is where CSS variables come into the picture.

CSS Variables are a newer browser spec. It’s very close to 100% browser support. With this in mind, the app I am building is a prototype so I am not too worried about supporting older browsers here. That being said, there are some folks who have put out some shims for IE.

For my use case, I need to sync the SASS variables to CSS variables. To do this, I chose to use the css-vars package.

I basically did the same thing for my app as described above in the README …

With this now in place, I can use the CSS variables throughout my stylesheets instead of using SASS variables. The important line above is $css-vars-use-native: true; This is telling the css-vars package that the compiled CSS should compile to actual CSS variables. This will be important later for then needing to update them on the fly.

The next step is to add a “theme picker” to the app. For this, I wanted to have a little fun and chose to add a hidden menu. It gives it a little bit of an easter egg feel and just makes it more fun. I’m not overly concerned about proper UX for this — in the future I will probably move this out to make it more visible. But for now, let’s add a secret menu to the app that will be displayed when the user presses a certain combination of keys on the keyboard.

This container will listen for the key combination CTRL + E and when it hears it, it will display the hidden menu modal. The Modal component here is a react portal …

It attaches and detaches itself from the modal-root page element. With this in place, I can create the Theme component which contains the select menu to select a variety of different theme palettes.

Here, I am importing a list of palettes which have color variables that match the variables we defined before. On selection, it is going to set the theme globally in the app state, and then it will call updateThemeForStyle which is a function that updates the CSS variables using JavaScript.

This function takes the name of selected theme, finds the theme palette in the themeOptions and then for each property it updates the property on html element’s style.

The theme options is just a list of options that have the same variables as the variables that were defined for the CSS variables.

With all of this in place, the theme selector can now update on the fly!

And here is the result, dynamic theme updates!

Here is the commit where I added feature. The full codebase is here.

You can try out a working version of the app here. (requires premium spotify membership). And yes, if you press CTRL + e in the app, the hidden theme modal will display! 😄

Thank you for reading and happy hacking!