Anti-patterns
Recognise the bad patterns before they become normal.
Apply
Each section pairs a familiar problem with a clearer LSCSS approach — shallow selectors instead of deep chains, named components instead of utility stacks, state classes instead of modifier soup, and urgent fixes kept in the hacks layer. Use these in reviews, teaching, and refactors when you need concrete before-and-after patterns, not only the written rules.
.page .content .card .header .title {
margin-bottom: 1rem;
}.product-card > .title {
margin-block-end: var(--space);
}Deep selectors couple CSS to markup structure. Short scoped selectors make ownership obvious and safe to change.
<article class="p-l m-b-xl bg-dark text-light radius-m grid gap-m">
...
</article><article class="product-card product-card--featured">
...
</article>Repeated utility stacks usually mean a component is trying to exist. Name it once instead of explaining it forever.
.button--loading {}
.button--active {}
.button--disabled {}.button {}
.button.is_loading {}
.button.is_disabled {}Permanent reusable variants are modifiers. Temporary UI behaviour should be visible as state.
Do not move old CSS into new components and call it progress. Create a legacy layer first, then improve active work safely.
@layer legacy, settings, base, utilities,
layout, components, theme, hacks;Legacy should stay visible and low priority, not quietly spread. When vendor CSS and inherited first-party CSS both need containment, declare thirdparty before legacy in@layer and import each file into the matching layer — details on layers.
If a hack will still exist in six months, it is probably a real fix pretending to be temporary.
@layer hacks {
.checkout-banner {
margin-top: -3px;
}
}Keep hacks visible. Hidden hacks become architecture by accident.