When organizing my Much less CSS information in a multi-page net software (MPA), I usually have a folder stuffed with modules through which every .much less
file represents a novel part. For essentially the most half, the order through which these modules are imported is irrelevant since they symbolize remoted definitions. The exception to this rule is the theming and design system modules. In an effort to work with the CSS cascade, it is essential that these design system modules be imported first such that different modules can override properties regionally with out having to fret about CSS selector specificity. Fortunately, Much less CSS makes this straightforward with its automated (default) deduplication of import paths.
For this exploration, I’m utilizing this bundle.json
file:
{
"scripts": {
"construct": "lessc --glob ./src/principal.much less ./dist/principal.css"
},
"devDependencies": {
"much less": "4.2.0",
"less-plugin-glob": "3.0.0"
}
}
The much less
bundle is the Much less CSS compiler; and the less-plugin-glob
bundle permits me to make use of *
and **
in my @import
paths.
Now, think about my modules
folder with the next .much less
information (I am together with the content material of every file in a single snippet right here to be able to scale back the noise):
/* file: ./modules/a.much less */
.a::earlier than {
content material: "a" ;
}
/* file: ./modules/b.much less */
.b::earlier than {
content material: "b" ;
}
/* file: ./modules/c.much less */
.c::earlier than {
content material: "c" ;
}
/* file: ./modules/design-system.much less */
.design-system::earlier than {
content material: "Design System" ;
}
If my principal .much less
file seemed like this:
@import "./modules/*.much less" ;
… then, compiling the CSS file will import every .much less
file into my principal.css
. The much less information will likely be imported in lexicographic order (ie, alphabetically) by file title. Which ends up in the next CSS output:
.a {
content material: "a";
}
.b {
content material: "b";
}
.c {
content material: "c";
}
.design-system {
content material: "Design System";
}
As you’ll be able to see, every file was imported in lexicographic order by file title. And, sadly, this places our design system content material on the very finish, which is problematic from an overrides perspective. Contemplate this HTML:
<h1>
Testing CSS Cascade
</h1>
<p class="design-system c"></p>
The intent right here is use the bottom kinds from .design-system
after which override a few of these kinds with .c
. Nonetheless, as a result of CSS cascade guidelines, rendering this HTML web page leads to the next output:
As you’ll be able to see, .c
did not override the .design-system
as a result of the .design-system
was outlined final within the CSS file (and has the identical specificity).
To repair this, we will replace the primary .much less
file to particularly import high-priority Much less CSS information first, earlier than executing our globbing import:
// In an effort to work with the cascade, we have to embody our design system definitions
// first. This manner, all different modules can devour after which override properties of the
// design system, even when the selector specificities are the identical (final one wins).
@import "./modules/design-system.much less" ;
// NOTE: The design-system will NOT BE included twice.
@import "./modules/*.much less" ;
As you’ll be able to see, each @import
statements reference the ./modules/
folder. However, we’re explicitly importing the design-system.much less
file first earlier than globbing the remainder of the ./modules/
folder. And, once we compile the CSS file this time, we get the next output:
.design-system::earlier than {
content material: "Design System";
}
.a::earlier than {
content material: "a";
}
.b::earlier than {
content material: "b";
}
.c::earlier than {
content material: "c";
}
This time, the design-system.much less
file content material was positioned on the high of the compiled CSS output on account of our specific @import
. And, most significantly, it wasn’t included a second time as a part of the *.much less
globbing. It is because the Much less CSS compiler will not import the identical file twice (the default habits).
Now, if we go to render the earlier HTML web page, we get the next output:
This time, for the reason that design-system.much less
file was included first, out c.much less
file definition is ready to override the content material
property.
This can be a slightly useful habits when the execution / import order of a small variety of .much less
information is essential. It signifies that we might be specific about importing a number of information first after which simply brute-force globbing the remainder of the information with out having to fret about duplication. This retains life easy.
Epilogue on CSS Layers
Current releases of contemporary browsers are actually implementing CSS layers. CSS layers provides us extra management over the cascade specificity, whatever the order through which CSS properties are declared. I’ve by no means truly checked out this earlier than; however, let’s hack one thing collectively as a proof-of-concept.
In our design-system.much less
file, let’s wrap the CSS property block in an @layer
known as ds
:
@layer ds {
.design-system::earlier than {
content material: "Design System" ;
}
}
Now, in our principal.much less
file, as an alternative of explicitly together with this design-system.much less
file first, we will simply declare the ds
layer first:
@layer ds ;
@import "./modules/*.much less" ;
Once we compile our Much less CSS, we get the next CSS output:
@layer ds;
.a::earlier than {
content material: "a";
}
.b::earlier than {
content material: "b";
}
.c::earlier than {
content material: "c";
}
@layer ds {
.design-system::earlier than {
content material: "Design System";
}
}
This tells the browser to push the ds
layer onto the layer stack instantly. Then, when the next design-system.much less
block is executed, it’ll push kinds onto the already-defined ds
layer. This places the ds
layer above the “nameless” layer—that’s, the block of unlayered CSS in .a
, .b
, and .c
—though the .design-system
block continues to be outlined final.
And, once we run the above HTML with the layered CSS, we get the next output:
As you’ll be able to see, though our design-system.much less
file was the final to be imported, the .c
block was nonetheless capable of override the content material
property as a result of it was declared in an nameless layer larger up within the layer stack.
This native layering stuff is fairly cool! Undoubtedly one thing value trying into.
Need to use code from this publish?
Try the license.
https://bennadel.com/go/4630