10

Lets assume to have the following CSS:

.box {
  width: var(--box-size);
  height: var(--box-size);
  border: 1px solid red;
}

.box--larger {
  --box-size: 66px;
}

.box--larger1 {
  --box-size: calc(var(--box-size) + var(--box--larger));
}

.box--larger2 {
  --box-size: calc(50px + var(--box--larger));
}

:root {
  --box-size: 50px; 
  --box--larger: 16px;
}
<div class="box">1</div>
<div class="box box--larger">2</div>
<div class="box box--larger1">3</div>
<div class="box box--larger2">4</div>

I wonder why boxes 1 and 2 work but box 3 doesn't. I would expect box 3 to look the same as box 2 but it doesn't. I tested box 3's approach in Chrome and I found that var(--box-size) doesn't show a value but var(--box-larger) does return the right value (16px).

Could someone explain why the approach of box 3 doesn't work. I mean to me it looks like valid CSS.

TylerH
  • 20,799
  • 66
  • 75
  • 101
SuperDJ
  • 7,488
  • 11
  • 40
  • 74
  • How do you import css file in you html? – Alesandro Giordano Aug 02 '18 at 18:37
  • @AlesandroGiordano I don't see how that is relevant but just with the normal approach: ``. Both variables are in the same file as is in the example above. – SuperDJ Aug 02 '18 at 18:40
  • Some time css is saved in cache of your project if you example are working with servlets... can you tell me in which contex are you using this html file? – Alesandro Giordano Aug 02 '18 at 18:43
  • I know HTML and CSS can be cached but I always refresh the cache on page reload using a clear cache plugin. The HTML is now in Laravel blade and the CSS part of a framework I'm making. However if it was due to cache than I guess it should have worked in the SO snippet but it didn't. – SuperDJ Aug 02 '18 at 18:49
  • If you are able to get date informations you can try to add them to the css url, i’ll write you an answer, let me know if it can be helpful – Alesandro Giordano Aug 02 '18 at 18:51
  • 2
    CSS is not a functional language. It doesn't calculate those values the way you would expect of a regular programming language. Basically you are trying to tell the system, "the value of this item is the same as its value plus 16", which is confusing. – Mr Lister Aug 02 '18 at 18:53
  • @AlesandroGiordano Why are you convinced that the outcome in the snippet here is the result of css caching? Snippets don't even use CSS files, they have – Mr Lister Aug 02 '18 at 18:55
  • @MrLister that is extactly what I'm trying to do yes. But how can it be that "confusing" I mean the value is already defined you just overwrite it in a specific class. For box 3 and 4 you basically do the same thing except one works the other doesn't – SuperDJ Aug 02 '18 at 18:58
  • You may want to just use a preprocessor in this case. – Chase Ingebritson Aug 02 '18 at 19:03
  • @SuperDJ Yes, but none of the other examples try to tell the system that the value of X is 16 greater than the value of X. I'm afraid you will have to use more variables. – Mr Lister Aug 02 '18 at 19:05
  • @ChaseIngebritson I'm already using a preprocessor but I still like to use CSS variables and calc. I only want to use the preprocessor as a last resort – SuperDJ Aug 02 '18 at 19:05
  • @SuperDJ I see. I've been looking all over and can't seem to find good examples on _why_ it doesn't work. [This](https://stackoverflow.com/questions/44562399/css-variable-with-fallback-value-of-itself#answer-44563243) answer may provide a bit of insight even though it's relating to variable fallbacks. – Chase Ingebritson Aug 02 '18 at 19:08
  • as @MrLister said : CSS is not C++, full stop ... you have cycle dependency – Temani Afif Aug 02 '18 at 19:18
  • As a reminder re: @ChaseIngebritson's comment, you can't do anything with a CSS preprocessor that you can't also do in CSS. It just lets you save some time when writing really long, repetitive CSS styles. – TylerH Aug 02 '18 at 19:29
  • @SuperDJ It is confusing to CSS because CSS sees a recursive declaration the way you've written it, and CSS cannot handle recursion. – TylerH Aug 02 '18 at 19:31

2 Answers2

11

As commented above, CSS is not C++ and you are having a cyclic dependency wanting to express a property with the same property which will not work.

Refering to the specification:

Custom properties are left almost entirely unevaluated, except that they allow and evaluate the var() function in their value. This can create cyclic dependencies where a custom property uses a var() referring to itself, or two or more custom properties each attempt to refer to each other.

A common fix to that situation is to add more variables to avoid any cyclic dependency.

:root {
  --bs:50px;
  --bl:16px;
  --box-size:var(--bs); 
  --box--larger:var(--bl);
}

.box {
  width: var(--box-size);
  height: var(--box-size);
  border: 1px solid red;
}

.box--larger {
  --box-size: 66px;
}

.box--larger1 {
  --box-size: calc(var(--bs) + var(--bl));
}

.box--larger2 {
  --box-size: calc(50px + var(--bl));
}
<div class="box">1</div>
<div class="box box--larger">2</div>
<div class="box box--larger1">3</div>
<div class="box box--larger2">4</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
1

Another, similar approach - assigning the new value to another variable, but when you read it to use it - you fallback to the original value.

:root {
 --box-size: 50px;
}
.box--large {
  --box-size-modified: calc(var(--box-size) * 2);
}

.box--huge {
  --box-size-modified: calc(var(--box-size) * 3);
}

.box {
  --box-size-to-use: var(--box-size-modified, var(--box-size))
  width: var(--box-size-to-use);
  height: var(--box-size-to-use);
  border: 1px solid red;
}

Here

--box-size-to-use: var(--box-size-modified, var(--box-size))

creates a new variable from --box-size-modified. If it is not defined, it will fallback to the next value - --box-size.

With this - .box would be 50px, .box.box--large would be 100px and .box.box--huge would be 150px. But still, this would only give you 1 degree of freedom. If you want to go further, you would have to use more fallback values.

Wish
  • 1,594
  • 1
  • 18
  • 36