1

I'd like to use CSS variables to define some compound properties. In this example, I'm defining a --border-width variable as well as a --border variable that uses the --border-width variable. I then override the border width value on certain elements:

:root {
  --border-width: 1px;
  --border: var(--border-width) solid #000;
}

.demo {
  border: var(--border);
  margin: 1em;
}

.demo.active {
  --border-width: 10px; 
}
<div class="demo">
  Should have thin border
</div>

<div class="demo active">
  Should have thick border
</div>

I know that the new variable is being applied to the element; I can see it in the inspector and if I add an explicit border-width: var(--border-width) property to .demo, it applies the expected width value. However, it appears that --border hasn't been recalculated to reflect the change to --border-width.

I don't want each of my elements to have to specify all of the longhand properties each time I use something with a shorthand, but it seems like I'm missing something fundamental about CSS variables.

For example, I'd prefer to not have to do this:

:root {
  --border-width: 1px;
  --border-style: solid;
  --border-color: #000;
}

.demo {
  border: var(--border-width) var(--border-style) var(--border-color);
  
  /*
  Or this
  
  border-width: var(--border-width);
  border-style: var(--border-style);
  border-color: var(--border-color);
  */
  
  margin: 1em;
}

.demo.active {
  --border-width: 10px; 
}
<div class="demo">
  Should have thin border
</div>

<div class="demo active">
  Should have thick border
</div>
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 1
    @TemaniAfif thanks! I knew had to have been asked before, but all of my searching wasn't pulling any duplicates. – Shepmaster Aug 27 '19 at 12:18

1 Answers1

0

You are correct in that your .demo element has the border applied to it that you set in :root. However, in your .demo.active you merely redefine the CSS variable --border-width (as opposed to making use of the existing one). You need to explicitly use the property border-width.

In order to reuse the --border-width variable in .demo.active, you'd again be looking to make use of var() with border-width: var(--border-width):

:root {
  --border-width: 1px;
  --border: var(--border-width) solid #000;
}

.demo {
  border: var(--border);
  margin: 1em;
}

.demo.active {
  border-width: var(--border-width);
}
<div class="demo">
  Should have thin border
</div>

<div class="demo active">
  Should have thick border
</div>

Note that this will copy what was set in the :root --border-width. However, given that you also mention that you're expecting a thicker border, what I suspect you may actually be looking for is to either override this setting (with border-width: 10px), or extend it to also include an addition, with
border-width: var(--border-width) + 10px:

:root {
  --border-width: 1px;
  --border: var(--border-width) solid #000;
}

.demo {
  border: var(--border);
  margin: 1em;
}

.demo.active {
  border-width: var(--border-width) + 10px;
}
<div class="demo">
  Should have thin border
</div>

<div class="demo active">
  Should have thick border
</div>
Obsidian Age
  • 41,205
  • 10
  • 48
  • 71
  • *you merely redefine the CSS variable `--border-width`* — yes, my intention is that by doing so, the `--border` variable reflects the change, then `border: var(--border)` would as well. Effectively, I'm looking for a cascade of the variables. – Shepmaster Aug 27 '19 at 02:16
  • In the OP, I stated *if I add an explicit `border-width: var(--border-width)` property*, but followed that up with *I don't want each of my elements to have to specify all of the longhand properties*; are you stating that what I want is impossible? – Shepmaster Aug 27 '19 at 02:18
  • Essentially yes, I believe so -- something would still need to make *use* of that `-border-width` variable, with `var()`. If you're looking to apply a variable hierarchy in that regard, you're better off looking into a pre-processor like LESS, and nesting selectors (possibly making use of the parent selector `&`). I don't think that can be done in pure CSS, as the pre-processor simply compiles out each of the variables like above. – Obsidian Age Aug 27 '19 at 02:20
  • I don't follow your first example, as it doesn't have a think border in either case. Please also see my update where I show a way to make it work by only defining an updated variable. – Shepmaster Aug 27 '19 at 02:25
  • imho the first example is missing `--border-width: 10px;`, but essentially, yes, you would have to redefine `--border` for it to take the new `--border-width` into account. That makes sense tho. If `.active` was capable of changing the :root `--border`, then both the active and non active elements would have a thick border. It's more a question of scope than "cascade". – Capsule Aug 27 '19 at 02:31