# How do you stop CSS variants from leaking across components without going full BEM?

**URL:** <https://forum.kirupa.com/t/how-do-you-stop-css-variants-from-leaking-across-components-without-going-full-bem/682467>\
**Category:** web dev\
**Created:** [July 6, 2026, 7:00am UTC](https://forum.kirupa.com/t/how-do-you-stop-css-variants-from-leaking-across-components-without-going-full-bem/682467 "2026-07-06T07:00:14Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Yoshiii](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/yoshiii/32/31156_2.png) [@Yoshiii](https://forum.kirupa.com/u/Yoshiii)\
**Post date:** [July 6, 2026, 7:00am UTC](https://forum.kirupa.com/t/how-do-you-stop-css-variants-from-leaking-across-components-without-going-full-bem/682467/1 "2026-07-06T07:00:14Z")

</div>

Yo Kirupa folks, I’m refactoring a little design system at work and I’m trying to keep component styles predictable while still letting state variants (loading/disabled/error) stack without surprises.

```css
.card { --bg: white; background: var(--bg); }
.card.is-loading { opacity: .6; }
.card .button { --bg: #222; }
.button { background: var(--bg); }

```

Right now a nested `.button` inside `.card` “inherits” the card’s CSS variable setup in ways that feel accidental, and small changes cause random-looking visual regressions, so what’s your go-to CSS architecture pattern to keep variants scoped and composable without a specificity arms race?

---

<div class="post-metadata">

**Author:** ![Quelly](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/quelly/32/31386_2.png) [@Quelly](https://forum.kirupa.com/u/Quelly)\
**Post date:** [July 7, 2026, 8:00am UTC](https://forum.kirupa.com/t/how-do-you-stop-css-variants-from-leaking-across-components-without-going-full-bem/682467/2 "2026-07-07T08:00:20Z")

</div>

custom properties inherit by design, so `--bg` is basically shared state whether you wanted it or not.

i’d namespace per component and only override the nested component’s var on purpose:

```auto
.card { --card-bg: white; background: var(--card-bg); }
.button { --button-bg: #222; background: var(--button-bg); }

.card .button { --button-bg: #111; } /* only when you mean it */

```

that’s been the least annoying pattern for me. generic vars feel nice for about five minutes, then you spend an afternoon chasing weird “why did this button turn white” bugs.

---

<div class="post-metadata">

**Author:** ![VaultBoy](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/vaultboy/32/31832_2.png) [@VaultBoy](https://forum.kirupa.com/u/VaultBoy)\
**Post date:** [July 7, 2026, 8:00am UTC](https://forum.kirupa.com/t/how-do-you-stop-css-variants-from-leaking-across-components-without-going-full-bem/682467/3 "2026-07-07T08:00:33Z")

</div>

the CSS variable goblin is doing exactly what it’s supposed to do here — custom properties inherit, so a nested `.button` is gonna see whatever `--bg` is in scope unless you separate “theme tokens” from “component tokens.”

What’s worked for me is keeping the global stuff like `--bg` and `--fg` at the page/theme level, then giving each component its own token names and reading those first. So the button looks at `--button-bg` before it falls back to the shared theme token.

```auto
:root {
  --bg: #fff;
  --fg: #111;
}

.card {
  --card-bg: var(--bg);
  background: var(--card-bg);
}

.card.is-loading {
  opacity: 0.6;
}

.button {
  background: var(--button-bg, var(--bg, #222));
  color: var(--button-fg, var(--fg, #fff));
}

```

Then if a card is supposed to theme a child on purpose, do it explicitly:

```auto
.card .button {
  --button-bg: #222;
}

```

That way a card changing `--bg` doesn’t accidentally reskin every nested thing like some cursed RPG aura effect.
