Order Tailwind Styles in Layers
Here's how to order Tailwind CSS styles in CSS @layers
.
Insertion Order
This is for the veterans out there.
You find yourself using Tailwind to compile your CSS. It's your pal because you haven't had to create a .css file in a while. Well, there's that one file, maybe global.css
, where you're importing tailwind. Let's consider that file.
The imports come in 3 bits:
@tailwind base;
@tailwind components;
@tailwind utilities;
This specifies where the tailwind styles will be inserted into the file.
If you want your code to show up in one of those ordered spots, write your styles inside of @layer
directives. Tailwind specfies 3 special layers: base
, components
, and utilities
. So if I write custom code in:
@layer components {
.my-component {
color: red;
}
}
Once built, that .my-component
selector will show up in the @tailwind components
position.
There's a downside, in my opinion, though. It will have stripped the @layer
at-rule.
Layer Order
You see, CSS as a @layer
at rule. Tailwind seems nice because it's using the native keyword, but its directive acts differently by stripping the at-rule.
If you leave the @layer
at-rules in the built CSS, you get to control specificity/order with layers as well as the other tools of CSS. When Tailwind strips the @layer
at-rule, all those Tailwind-defined styles become immediately more specific than any of our app's layered styles.
Here's a grand diagram on where layers fit in the cascade.
How will we get layers back if tailwind is stripping them away? We can specify them again in our project globals.css
file.
@layer tailwind-base {
@tailwind base;
}
Now Tailwind's base styles will be in a layer we called "tailwind-base".
And if we extend that pattern, we can control all of Tailwind's styles and they interleave with our design system and project styles.
A full example of a global.css
:
@layer important-overrides, tailwind-base, design-system-base, tailwind-components, design-system-components, tailwind-utilities, project;
@import "design-system-base.css" layer(design-system-base);
@import "design-system-components.css" layer(design-system-components);
@layer tailwind-base {
@tailwind base;
}
@layer tailwind-components {
@tailwind components;
}
@layer tailwind-utilities {
@tailwind utilities;
}
@layer important-overrides {
.design-system-widget {
color: blue !important;
}
}
.my-project-widget {
color: red;
}
To note:
- We've defined our layer specificity order. Last one in wins (ie,
tailwind-utilities
). - It's the first instance of a
@layer
declaration that defines the order. This is the first line ofglobal.css
, where the order is given in one csv of layer names, without block bodies. - When
!important
is used, layer specificity is reverse. First one in wins (ie,important-overrides
). - Stylesheet
@import
s can be put into a layer if they don't have one themselves. This is done with thelayer()
function on import. - Selectors without a layer are more specific than any selectors in a layer. In this case
.my-project-widget
will have the most specific attributes.
Now you are rightly ordered, and you have beaten Tailwind.