1

My goal is to have an architecture where the shadow is defined once, but the color changes depending on HTML attribute data-color-mode.

Note: code provided is just for the isolated problem demonstration.

For some reason when nesting variables in CSS, the value doesn't seem to update.

I am having some hypotheses about why this happens, but I don't really know. AI produces faulty answers and says to remove functionality.

:root {
  --dark-color: #333;
  --light-color: #f0f0f0;

  --responsive-color: var(--light-color);

  --responsive-shadow: 0 20px var(--responsive-color);
}

[data-color-mode="dark"] {
  --responsive-color: var(--dark-color);
}

div {
  background: var(--responsive-color);
  box-shadow: var(--responsive-shadow);
  
  color: grey;
}
<section>
  <div>Expected: Background color and shadow color to be light</div>
</section>
<br>
<br>
<section data-color-mode="dark">
  <div>Expected: Background color and shadow color to be dark</div>
</section>

One dirty solution (which I want to avoid) is to duplicate --responsive-shadow: 0 20px var(--responsive-color); to inside [data-color-mode="dark"] {} CSS block. It works. But horrible for many or variable amount of color palettes.

Idea's?

5
  • Seems to be working fine or am I missing something? Both background and shadow are set to dark-color. Commented Sep 8 at 11:14
  • 1
    You missed the shadow of the second block. It should (= I would expect it to) be dark, just like background. So visually 2 light + 2 dark blocks. What we see is 2 light + 1 dark 1 light. The only difference is that in the example of shadow a variable is nested inside another variable. This breaks the reference and seems to collapse to an absolute value or something. Commented Sep 8 at 14:10
  • As explained in the linked post, it won't re-evaluate. In this case (if it applies to your actual project), you can also consider using :root,[data-color-mode="dark"] {} instead of :root {} to re-evaluate the result. Commented Sep 8 at 20:32
  • @SyndRain :root,[data-color-mode] {} worked when added as a separate selector and is the only place that contains vars that use vars! Can we make a proper answer out of this? Commented Sep 10 at 7:47
  • 1
    @Slava What I mean is to change the :root selector to :root, [themes] with nothing else changed. See jsfiddle.net/vta1gdpn . But glad you found an answer! Commented Sep 10 at 13:05

1 Answer 1

1

css variables are not reactive!
--responsive-shadow is evaluated when --responsive-color = --light-color!

This will work well:

:root {
  --dark-color: #333;
  --light-color: #f0f0f0;

  --responsive-color: var(--light-color);
}

[data-color-mode="dark"] {
  --responsive-color: var(--dark-color);
}

div {
  background: var(--responsive-color);
  box-shadow: 0 20px var(--responsive-color);
  
  color: grey;
}
<section>
  <div>Expected: Background color and shadow color to be light</div>
</section>
<br>
<br>
<section data-color-mode="dark">
  <div>Expected: Background color and shadow color to be dark</div>
</section>

Sign up to request clarification or add additional context in comments.

2 Comments

This does work, but completely defeats the purpose of the question. Which is: defining box shadow (and similar properties that use color variable) once, and NOT per palette or element selector. Imagine scenario where color palettes are added dynamically (white label product) and only the colors are supplied, no stuff like '0 20px'.
I've come to a solution thanks to SyndRain's comment on the question! There needs to be a third selector :root,[data-color-mode] {} which will be the only place that contains vars that use vars. Then we can have a signle source of truth for any vars that contain vars.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.