Warning: containment breach in cascade layer!
CSS cascade layers are the ultimate tool to win the specificity wars. Used alongside the selector, specificity problems are a thing of the past. Or so I thought. Turns out cascade layers are leakier than a xenonite sieve. Cross-layer shenanigans can make bad CSS even badder. I discovered a whole new level of specificity hell. Scroll down if you dare! There are advantages too, I’ll start with a neat trick. To setup this trick I’ll quickly cover my favoured CSS methodology for a small website. I find defining three cascade layers is plenty. In I add my reset styles , custom properties, anything that touches a global element, etc. In I add the core of the website. In I add classes that look suspiciously like Tailwind , for pragmatic use. Visually-hidden is a utility class in my system. I recently built a design where many headings and UI elements used an alternate font with a unique style. It made practical sense to use a utility class like the one below. This is but a tribute, the real class had more properties. The class is DRY and easily integrated into templates and content editors. Adding this to the highest cascade layer makes sense. I don’t have to worry about juggling source order or overriding properties on the class itself. I especially do not have to care about specificity or slap everywhere like a fool. This worked well. Then I zoom further into the Figma picture and was betrayed! The design had an edge case where letter-spacing varied for one specific component. It made sense for the design. It did not make sense for my system. If you remember, my cascade layer takes priority over my layer so I can’t simply apply a unique style to the component. For the sake of a demo let’s assume my component has this markup. I want to change back to the normal letter-spacing. Oops, I’ve lost the specificity war regardless of what selector I use. The utility class wins because I set it up to win. My “escape hatch” uses custom property fallback values . In most cases is not defined and the default is applied. For my edge case component I can ‘configure’ the utility class. I’ve found this to be an effective solution that feels logical and intuitive. I’m working with the cascade. It’s a good thing that custom properties are not locked within cascade layers! I don’t think anyone would expect that to happen. In drafting this post I was going to use an example to show the power of cascade layers. I was going to say that not even wins. Then I tested my example and found that does actually override higher cascade layers. It breaches containment too! What colour are the paragraphs? Suffice it to say that things get very weird. See my CodePen . Spoiler: blue wins. I’m sure there is a perfectly cromulent reason for this behaviour but on face value I don’t like it! Bleh! I feel like should be locked within a cascade layer. I don’t even want to talk about the inversion… I’m sure there are GitHub issues, IRC logs, and cave wall paintings that discuss how cascade layers should handle — they got it wrong! The fools! We could have had something good here! Okay, maybe I’m being dramatic. I’m missing the big picture, is there a real reason it has to work this way? It just feels… wrong? I’ve never seen a use case for that wasn’t tear-inducing technical debt. Permeating layers with feels wrong even though custom properties behaving similar feels right. It’s hard to explain. I reckon if you’ve built enough websites you’ll get that sense too? Or am I just talking nonsense? I subscribe to the dogma that says should never be used but it’s not always my choice . I build a lot of bespoke themes. The WordPress + plugin ecosystem is the ultimate specificity war. WordPress core laughs in the face of “CSS methodology” and loves to put styles where they don’t belong . Plugin authors are forced to write even gnarlier selectors. When I finally get to play, styles are an unmitigated disaster. Cascade layers can curtail unruly WordPress plugins but if they use it’s game over; I’m back to writing even worse code. Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds.