Winning With Layers
Goal
You write a stylesheet that uses @layer and check with the calculator
which declaration wins. This answer is single even without a browser.
Why it matters
In the sort order, layers are decided before specificity. So once you start
using layers, the question "its specificity is higher, so why does it lose?" appears, and if you don't know the answer,
people go back to !important.
The rules are two lines. A declaration not put in a layer goes into the very last layer,
and for normal declarations the later layer wins, while for !important the earlier layer
wins. Put these two lines together and a normal declaration outside a layer is the strongest, while an
!important outside a layer is the weakest.
What to build
It is one file, /root/work/layers/theme.css, and two prediction files. No HTML is
needed — the grader resolves the cascade assuming the elements below.
div#app > article.card > h2.title
div#app > article.card > h2.title.u-hidden
div#app > article.card > a.btn.primary
div.toolbar > button.btn
The calculator
cd /root/work/layers
python3 /opt/lab/checks/css-layer-lab/layercalc.py theme.css
For each declaration it shows the layer, the media condition, the specificity, and the order, and at the top it prints the layer order. If it meets a selector it can't handle, it does not silently skip it but says "cannot interpret."
Steps
@layer reset, base, components, utilities;at the very top- Fill in the four layers and confirm that the later layer wins
- A rule outside a layer wins even with lower specificity →
03-predict.txt !importantflips the order →04-predict.txt- A default with specificity 0 using
:where() - A utility beats a component without any specificity
- Save the calculator's result as
07-resolve.txt - Remove the
!importantoutside a layer - Wrap-up →
09-notes.md
Notes
- This calculator handles
:where()and:is(), but it does not handle selectors with a combinator inside the parentheses. Put in just one thing, like:where(.title). - Write the prediction file first and then run the calculator. If you reverse the order, what you learn disappears.
Pin down the layer order
Create /root/work/layers/theme.css and write @layer reset, base, components, utilities; as the first rule. Then put at least one rule in each layer.
Run mkdir -p /root/work/layers. Layer order is decided by the order in which names first appear. If you put one blockless declaration statement at the very top, then from then on the order is fixed whichever file is read first.
The later layer wins
In each of the two layers base and components, put a color rule that matches div#app > article.card > h2.title, and make components win. At this step you don't use !important.
For normal declarations, the later layer wins. You don't need to raise specificity — because the layer stage is decided before specificity. Check the winner's layer name with the calculator.
Outside a layer is the strongest
Write one heading color rule outside an @layer block. The specificity of that selector must be lower than the components rule. Then write the winning place and the winning value in /root/work/layers/03-predict.txt.
A declaration not put in a layer implicitly goes into the very last layer. You will see a 0,1,0 beat a rule with specificity 1,2,0 — the calculation isn't wrong; specificity just never got its turn. The prediction file must contain 레이어 밖 (the Korean phrase for "outside a layer") and the winning color value.
important flips the order
In the reset layer and the components layer, put !important color rules that each match div#app > article.card > a.btn.primary. The specificity of the reset selector must be lower. In 04-predict.txt, write which layer wins and why.
For normal declarations the later layer wins, but for !important the earlier layer wins. The specification explains that this is the same logic by which important reverses the origin order. The prediction file must contain reset and important.
A default with specificity 0
In the base layer, write a default heading weight using :where(), and within the same layer put one more weight rule that has specificity. The :where() rule must come later in the file.
:where() always has a specificity of 0,0,0. If you see it lose to the earlier tag selector even though it was written later, that proves the decision was made by specificity, not order. Put just one thing inside the parentheses, with no combinator.
A utility wins without specificity
Put .u-hidden { display: none } in the utilities layer, and in the components layer put a display rule that targets the same element with higher specificity. The utility must win without !important.
The grader computes what wins for div#app > article.card > h2.title.u-hidden. The practice of putting !important on utility classes becomes unnecessary once you have layers — declaring the utilities layer after the components layer is all it takes.
Check with the calculator
Run layercalc.py and save the result as /root/work/layers/07-resolve.txt. The number of saved lines must equal the number of declarations in the current sheet, and the layer order line must be included as is.
python3 /opt/lab/checks/css-layer-lab/layercalc.py theme.css | tee 07-resolve.txt. This is the calculation you do in your head when you look at a struck-through rule in the developer tools.
Remove the important outside a layer
There must be no !important outside a layer anywhere in the sheet. And add a color rule for .toolbar > button.btn to the components layer so that the toolbar button color comes from components. The total number of !important declarations must not exceed four.
An !important outside a layer loses to the !important of every layer. It is the spot where what you wrote to be the strongest becomes the weakest, and it is the accident that happens most often in sheets that have introduced layers. Delete it or move it to reset.
Why specificity doesn't get its turn
In /root/work/layers/09-notes.md, write at least three lines (at least 120 characters). The text must contain 레이어, 특정성, and important (the first two are the Korean words for "layer" and "specificity"). The sheet must also still pass the criteria of the earlier steps.
The core is one thing — in the sort order, layers come before specificity. The rule that if it is decided at an earlier stage the later ones aren't looked at runs through the whole cascade.