Color Theming with CSS Custom Properties and Tailwind
CSS custom properties not only improve code efficiency, but also create more possibilities in CSS, especially in theme design. The Atomic Smash team uses Tailwind CSS (a utility class framework). This article will explore how to use custom properties for theme design and how to integrate it with Tailwind to maximize reusability of your code. This article will not explain the introduction to Tailwind - please check the official documentation - but even if you are new to Tailwind, you may find some tips useful.
Topic Overview
Suppose we have a "CTA" component that contains the title, body, and buttons.
Writing a regular (non-Tailwind) CSS for this color scheme looks like this:
<code>.cta { background-color: #742a2a; // 深红色 color: #ffffff; // 白色} .cta__heading { background-color: #e53e3e; // 中等红色 color: #742a2a; } .cta__button { background-color: #e53e3e; }</code>
With Tailwind, we will apply these colors as utility classes in HTML:
<code><div> <h3 id="Join-our-mailing-list">Join our mailing list</h3> <div> <p>Get the first to know our new products</p> register</div> </div></code>
I deliberately omitted classes that are not related to the basic color scheme, but you can see the full example in this demo:
Now, if we want to apply a different color scheme to our component, we need to override the color value of the original component. In the absence of Tailwind, a common approach is to attach the theme class to the component itself and redefine the color value in the cascade. So for components with the ".cta--blue" (using the BEM convention) modifier class, we will apply the CSS value of the blue color scheme:
<code>.cta--blue { background-color: #2a4365; // 深蓝色} .cta--blue .cta__heading { background-color: #3182ce; // 中等蓝色 color: #2a4365; } .cta--blue .cta__button { background-color: #3182ce; }</code>
If we use Sass or other preprocessors, we can use variables to simplify our work, and we might nest .cta__heading and .cta__body selectors. It doesn't make our code more concise, but by updating these values in one place, it does make the code more manageable.
Now, let's say we have 10 different color schemes, like I've experienced in a project recently. Our code starts to get longer because we basically repeated the above example 10 times before changing these color values. Now imagine that each component in our design system requires 10 color schemes, and many components are much more complex than our simple CTA. Maybe our theme also needs different fonts. Suddenly, we need to write a lot of CSS.
Use Tailwind for theme design
On the other hand, if we use Tailwind, we need to change multiple classes in the HTML itself. Even if we use JavaScript frameworks (like React or Vue), this is not an easy task. To ensure unused styles are removed in production versions, Tailwind discourages the use of string concatenation to create class names (at the time of writing). So building our topics might mean adding a lot of logic to our components.
Use custom properties for theme design
By using custom properties for our color themes, we can drastically reduce the amount of code that needs to be written and reduce the maintenance burden. Let's first look at how to do this in regular CSS.
We define the custom attribute as: a variable on the root selector, making it a global variable. (The body selector also applies.) We can then use these variables to replace the color attribute value in the selector:
<code>:root { --primary: #742a2a; // 深红色 --secondary: #e53e3e; // 中等红色} .cta { background-color: var(--primary); color: white; } .cta__heading { background-color: var(--secondary); color: var(--primary); } .cta__button { background-color: var(--secondary); }</code>
This is where it's really magical: Now creating code for each topic just requires updating these custom attribute values. No matter where we apply the theme class, the new value will be inherited:
<code>.th-blue { --primary: #2a4365; // 深蓝色 --secondary: #3182ce; // 中等蓝色}</code>
If we want a blue color scheme, we can apply the .th-blue class to the component, and even in Use it on the tag to apply the page-wide theme and then overwrite it on individual components as needed. Using utility classes may save us more of the code writing effort than component-specific classes (such as .cta--blue in the original code), as it can be applied anywhere in our code base.
Handle legacy browsers
Like many agencies, many Atomic Smash customers still need our support for Internet Explorer 11. While I can accept progressive enhancement methods in most cases (for example, providing a simpler fallback layout for browsers that do not support CSS Grid), I found theme design to be an area that usually does not allow for easy compromises. Customers want to see their brand colors and fonts, even on older browsers. Providing a fallback with a feature query will require a lot of extra work, which will offset the benefits of using custom properties. To overcome this problem, we need a polyfill.
There are several options to provide polyfill for custom properties in IE 11.
postcss-custom-properties
The first is to use a PostCSS plugin called postcss-custom-properties. If you are already using PostCSS in your workflow, adding this plugin is fairly simple. It works by processing your CSS and outputting the result of the variable as property values. So if you have the following CSS:
<code>:root { --color: red; } h1 { color: var(--color); }</code>
The result after processing will be:
<code>h1 { color: red; color: var(--color); }</code>
Browsers that do not support custom properties will ignore the second rule and fall back to the regular property value. There is also an option to remove rules with custom properties from the output, so the file size will be smaller. This means no browser gets custom properties—it's a problem if you update variables dynamically—but you can use them for static values in your code without adverse effects.
Unfortunately, this polyfill has some limitations:
- You need to specify a file (or file) that defines custom properties in the configuration.
- Custom properties can only be defined on the :root selector.
The first limit is relatively trivial, but the second unfortunately makes this polyfill completely useless for our topic design use cases. This means we cannot redefine variables on the selector to create our topic.
ie11CustomProperties
This polyfill option involves providing client scripts instead of preprocessing CSS. We can add the following script to our head to make sure that polyfill is loading only in IE 11:
<code>window.MSInputMethodContext && document.documentMode && document.write('');</code>
This allows us to take advantage of the custom properties as we did in the example here, so this is the solution I decided to use. It has a limitation that custom properties set in the style attribute will not be polyfilled. But I've tested it against the above topic design example and it works fine.
But what does this have to do with Tailwind?
As we have seen, utility classes—one-purpose classes that can be applied anywhere in HTML—can make our code more reusable. This is the main selling point of Tailwind and other utility class frameworks – the size of the CSS file you deliver will eventually become smaller as a result. Tailwind provides multiple color classes: .bg-red-medium will give us the red background-color property value, .text-red-medium is for color, and so on, for border, box-shadow, or anywhere you can think of where color values may be needed.
Colors can be defined in the configuration file:
<code>module.exports = { theme: { colors: { red: { medium: '#e53e3e', dark: '#742a2a' }, blue: { medium: '#3182ce', dark: '#2a4365' } } } }</code>
If we want to use custom property values for our Tailwind class, we can specify them in the configuration:
<code>module.exports = { theme: { colors: { 'th-primary': 'var(--primary)', 'th-secondary': 'var(--secondary)' } } }</code>
I prefixed the subject-related class names so it's obvious that they are particularly relevant to the subject design, but you can feel free to use any convention that suits you.
Now we can use these classes through Tailwind. Using .bg-th-primary is equivalent to writing:
<code>.some-element { background-color: var(--primary); }</code>
In our CSS we can define custom properties of the theme as before:
<code>:root { --primary: #742a2a; --secondary: #742a2a; } .th-blue { --primary: #2a4365; --secondary: #3182ce; }</code>
Let's apply these classes to our HTML. The first example provides us with a component with a default theme (variables defined on :root). The second has our blue theme. The only difference is that the .th-blue class was added to the component. (For simplicity and clarity, I omitted classes that are not related to the topic.)
<code><div class="bg-th-primary text-white"> <h3 id="Join-our-mailing-list">Join our mailing list</h3> <div> <p>Get the first to know our new products</p> <button class="bg-th-secondary">register</button> </div> </div> <div class="th-blue bg-th-primary text-white"> <h3 id="Join-our-mailing-list">Join our mailing list</h3> <div> <p>Get the first to know our new products</p> <button class="bg-th-secondary">register</button> </div> </div></code>
Using configuration as a style guide
Tailwind encourages you to define all variables in your configuration, and personally, I agree that this is a better approach. This means that the configuration file can be a single source of fact, rather than (probably) ending up with multiple places to define the color and other theme values. Fortunately, we can also use the values in the Tailwind configuration file for our custom properties. We need to first define all colors in the configuration (assuming we don't use the default palette included by Tailwind):
<code>module.exports = { theme: { colors: { red: { medium: '#e53e3e', dark: '#742a2a' }, blue: { medium: '#3182ce', dark: '#2a4365' }, 'th-primary': 'var(--primary)', 'th-secondary': 'var(--secondary)' } } }</code>
Then we can access the theme object in CSS:
<code>:root { --primary: theme('colors.red.dark'); --secondary: theme('colors.red.medium'); } .th-blue { --primary: theme('colors.blue.dark'); --secondary: theme('colors.blue.medium'); }</code>
Summarize
I'm so happy to be able to use custom properties without worrying about browser support, and I'm even more happy to be able to integrate it seamlessly with our existing workflows. It's hard to exaggerate the time they will save us in terms of theme design. I hope that even if you are not a Tailwind user, this article may encourage you to try custom properties for this use case.
The above is the detailed content of Color Theming with CSS Custom Properties and Tailwind. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



If you’ve recently started working with GraphQL, or reviewed its pros and cons, you’ve no doubt heard things like “GraphQL doesn’t support caching” or

With the recent climb of Bitcoin’s price over 20k $USD, and to it recently breaking 30k, I thought it’s worth taking a deep dive back into creating Ethereum

No matter what stage you’re at as a developer, the tasks we complete—whether big or small—make a huge impact in our personal and professional growth.

It's out! Congrats to the Vue team for getting it done, I know it was a massive effort and a long time coming. All new docs, as well.

I'd say "website" fits better than "mobile app" but I like this framing from Max Lynch:

I had someone write in with this very legit question. Lea just blogged about how you can get valid CSS properties themselves from the browser. That's like this.

The other day, I spotted this particularly lovely bit from Corey Ginnivan’s website where a collection of cards stack on top of one another as you scroll.

I was just chatting with Eric Meyer the other day and I remembered an Eric Meyer story from my formative years. I wrote a blog post about CSS specificity, and
