Get Computed Value of CSS Variable That Uses an Expression Like Calc

Get computed value of CSS variable that uses an expression like calc

Technically you cannot because the computed value is not static and will depend on other properties. In this case it's trivial since we are dealing with pixel value but imagine the case where you will have percentage value. Percentage is relative to other properties so we cannot compute it until it's used with var(). Same logic if we use unit like em, ch, etc

Here is a simple example to illustrate:

let div = document.getElementById('example');console.log(window.getComputedStyle(div).getPropertyValue('--example-var'))console.log(window.getComputedStyle(div).getPropertyValue('font-size'))console.log(window.getComputedStyle(div).getPropertyValue('width'))console.log(window.getComputedStyle(div).getPropertyValue('background-size'));
:root {  --example-var: calc(100% + 5px - 10px);}#example {  font-size:var(--example-var);  width:var(--example-var);  background-size:var(--example-var);}
<div id='example'>some text</div>

Getting CSS Variables to Add Correctly using calc()

because when doing #century-*:checked~ #century_result you only assign the value to #century_result so #result will get nothing. You need to target both element so simply do #century-*:checked ~ * (same logic with #month_result)

:root {
--isLeapYear: 0;
/* Determinant to be worked out later, set as 0 for now */
/* Month registers */
--m7: 0;
--m6: 0;
--m5: 0;
--m4: 0;
--m3: 0;
--m2: 0;
--m1: 0;
--m0: 0;
/* Century keys */
--ck7: 0;
--ck6: 0;
--ck5: 0;
--ck4: 0;
--ck3: 0;
--ck2: 1;
--ck1: 1;
--ck0: 0;
--century: 0;
--month: 0;
--result: 0;
--borderBlack: 1px solid black;
--selectedColor: #007ec2;
}

[type="radio"],
[type="checkbox"] {
display: none;
}

.century+label,
.month+label {
padding-left: 4px;
padding-right: 4px;
height: 16px;
border-left: var(--borderBlack);
border-right: var(--borderBlack);
font: 400 13.3333px Arial;
display: inline-block;
background-color: white;
color: black;
}

.century+label {
width: 20px;
left: 5px;
top: 5px;
}

.month+label {
width: 80px;
position: relative;
left: 73px;
top: -224px;
}

label[for="month-01"],
label[for="century-18"] {
border-top: var(--borderBlack);
}

label[for="month-12"],
label[for="century-29"] {
border-bottom: var(--borderBlack);
}

input:checked+label {
background-color: var(--selectedColor);
color: white;
}

/* Century Keys */

#century-18:checked~ * {
--ck7: 0;
--ck6: 0;
--ck5: 0;
--ck4: 0;
--ck3: 0;
--ck2: 0;
--ck1: 1;
--ck0: 0;
/* 2 */
}

#century-19:checked~* {
--ck7: 0;
--ck6: 0;
--ck5: 0;
--ck4: 0;
--ck3: 0;
--ck2: 0;
--ck1: 0;
--ck0: 0;
/* 0 */
}

#century-20:checked~* {
--ck7: 0;
--ck6: 0;
--ck5: 0;
--ck4: 0;
--ck3: 0;
--ck2: 1;
--ck1: 1;
--ck0: 0;
/* 6*/
}

#century-21:checked~* {
--ck7: 0;
--ck6: 0;
--ck5: 0;
--ck4: 0;
--ck3: 0;
--ck2: 1;
--ck1: 0;
--ck0: 0;
/* 4 */
}

#century-22:checked~* {
--ck7: 0;
--ck6: 0;
--ck5: 0;
--ck4: 0;
--ck3: 0;
--ck2: 0;
--ck1: 1;
--ck0: 0;
/* 2 */
}

#century-23:checked~* {
--ck7: 0;
--ck6: 0;
--ck5: 0;
--ck4: 0;
--ck3: 0;
--ck2: 0;
--ck1: 0;
--ck0: 0;
/* 0 */
}

#century-24:checked~* {
--ck7: 0;
--ck6: 0;
--ck5: 0;
--ck4: 0;
--ck3: 0;
--ck2: 1;
--ck1: 1;
--ck0: 0;
/* 6 */
}

#century-25:checked~* {
--ck7: 0;
--ck6: 0;
--ck5: 0;
--ck4: 0;
--ck3: 0;
--ck2: 1;
--ck1: 0;
--ck0: 0;
/* 4 */
}

#century-26:checked~* {
--ck7: 0;
--ck6: 0;
--ck5: 0;
--ck4: 0;
--ck3: 0;
--ck2: 0;
--ck1: 1;
--ck0: 0;
/* 2 */
}

#century-27:checked~* {
--ck7: 0;
--ck6: 0;
--ck5: 0;
--ck4: 0;
--ck3: 0;
--ck2: 0;
--ck1: 0;
--ck0: 0;
/* 0 */
}

#century-28:checked~* {
--ck7: 0;
--ck6: 0;
--ck5: 0;
--ck4: 0;
--ck3: 0;
--ck2: 1;
--ck1: 1;
--ck0: 0;
/* 6 */
}

#century-29:checked~* {
--ck7: 0;
--ck6: 0;
--ck5: 0;
--ck4: 0;
--ck3: 0;
--ck2: 1;
--ck1: 0;
--ck0: 0;
/* 4 */
}

/* Month Keys */

.month[value="1"]:checked~* {
--m7: 0;
--m6: 0;
--m5: 0;
--m4: 0;
--m3: 0;
--m2: 0;
--m1: 0;
--m0: calc(1 - var(--isLeapYear));
}

.month[value="2"]:checked~* {
--m7: 0;
--m6: 0;
--m5: 0;
--m4: 0;
--m3: 0;
--m2: calc(1 - var(--isLeapYear));
--m1: var(--isLeapYear);
--m0: var(--isLeapYear);
}

.month[value="3"]:checked~* {
--m7: 0;
--m6: 0;
--m5: 0;
--m4: 0;
--m3: 0;
--m2: 1;
--m1: 0;
--m0: 0;
}

.month[value="4"]:checked~* {
--m7: 0;
--m6: 0;
--m5: 0;
--m4: 0;
--m3: 0;
--m2: 0;
--m1: 0;
--m0: 0;
}

.month[value="5"]:checked~* {
--m7: 0;
--m6: 0;
--m5: 0;
--m4: 0;
--m3: 0;
--m2: 0;
--m1: 1;
--m0: 0;
}

.month[value="6"]:checked~* {
--m7: 0;
--m6: 0;
--m5: 0;
--m4: 0;
--m3: 0;
--m2: 1;
--m1: 0;
--m0: 1;
}

.month[value="7"]:checked~* {
--m7: 0;
--m6: 0;
--m5: 0;
--m4: 0;
--m3: 0;
--m2: 0;
--m1: 0;
--m0: 0;
}

.month[value="8"]:checked~* {
--m7: 0;
--m6: 0;
--m5: 0;
--m4: 0;
--m3: 0;
--m2: 0;
--m1: 1;
--m0: 1;
}

.month[value="9"]:checked~* {
--m7: 0;
--m6: 0;
--m5: 0;
--m4: 0;
--m3: 0;
--m2: 1;
--m1: 1;
--m0: 0;
}

.month[value="10"]:checked~* {
--m7: 0;
--m6: 0;
--m5: 0;
--m4: 0;
--m3: 0;
--m2: 0;
--m1: 0;
--m0: 1;
}

.month[value="11"]:checked~* {
--m7: 0;
--m6: 0;
--m5: 0;
--m4: 0;
--m3: 0;
--m2: 1;
--m1: 0;
--m0: 0;
}

.month[value="12"]:checked~* {
--m7: 0;
--m6: 0;
--m5: 0;
--m4: 0;
--m3: 0;
--m2: 1;
--m1: 1;
--m0: 0;
}

.century:checked~* {
font-family: Courier;
font-weight: 700;
--century: calc(var(--ck7) * 128 + var(--ck6) * 64 + var(--ck5) * 32 + var(--ck4) * 16 + var(--ck3) * 8 + var(--ck2) * 4 + var(--ck1) * 2 + var(--ck0));
}

#century_result:after {
counter-reset: C7 var(--ck7) C6 var(--ck6) C5 var(--ck5) C4 var(--ck4) C3 var(--ck3) C2 var(--ck2) C1 var(--ck1) C0 var(--ck0) CENTURY 0;
counter-increment: CENTURY var(--century);
content: "C" counter(C7) counter(C6) counter(C5) counter(C4) counter(C3) counter(C2) counter(C1) counter(C0) " = " counter(CENTURY)
}

.month:checked~#month_result {
font-family: Courier;
font-weight: 700;
--month: calc(var(--m7) * 128 + var(--m6) * 64 + var(--m5) * 32 + var(--m4) * 16 + var(--m3) * 8 + var(--m2) * 4 + var(--m1) * 2 + var(--m0));
}

#month_result:after {
counter-reset: M7 var(--m7) M6 var(--m6) M5 var(--m5) M4 var(--m4) M3 var(--m3) M2 var(--m2) M1 var(--m1) M0 var(--m0) MONTH 0;
counter-increment: MONTH var(--month);
content: "M" counter(M7) counter(M6) counter(M5) counter(M4) counter(M3) counter(M2) counter(M1) counter(M0) " = " counter(MONTH)
}

#result {
font-family: Courier;
font-weight: 700;
--century: calc(var(--ck7) * 128 + var(--ck6) * 64 + var(--ck5) * 32 + var(--ck4) * 16 + var(--ck3) * 8 + var(--ck2) * 4 + var(--ck1) * 2 + var(--ck0));
--month: calc(var(--m7) * 128 + var(--m6) * 64 + var(--m5) * 32 + var(--m4) * 16 + var(--m3) * 8 + var(--m2) * 4 + var(--m1) * 2 + var(--m0));
--result: calc(var(--century) + var(--month));
}

#result:after {
counter-reset: RESULT 0;
counter-increment: RESULT var(--result);
content: "R = " counter(RESULT);
}

#century_result {
position: absolute;
top: 240px;
}

#month_result {
position: absolute;
top: 265px;
}

#result {
position: absolute;
top: 290px;
}
<input id="century-18" name="century" class="century" type="radio" value="18" /><label for="century-18">18</label><br />
<input id="century-19" name="century" class="century" type="radio" value="19" /><label for="century-19">19</label><br />
<input id="century-20" name="century" class="century" type="radio" value="20" checked="checked" /><label for="century-20">20</label><br />
<input id="century-21" name="century" class="century" type="radio" value="21" /><label for="century-21">21</label><br />
<input id="century-22" name="century" class="century" type="radio" value="22" /><label for="century-22">22</label><br />
<input id="century-23" name="century" class="century" type="radio" value="23" /><label for="century-23">23</label><br />
<input id="century-24" name="century" class="century" type="radio" value="24" /><label for="century-24">24</label><br />
<input id="century-25" name="century" class="century" type="radio" value="25" /><label for="century-25">25</label><br />
<input id="century-26" name="century" class="century" type="radio" value="26" /><label for="century-26">26</label><br />
<input id="century-27" name="century" class="century" type="radio" value="27" /><label for="century-27">27</label><br />
<input id="century-28" name="century" class="century" type="radio" value="28" /><label for="century-28">28</label><br />
<input id="century-29" name="century" class="century" type="radio" value="29" /><label for="century-29">29</label><br />

<input id="month-01" name="month" class="month" type="radio" value="1" checked="checked" /><label for="month-01">January</label><br />
<input id="month-02" name="month" class="month" type="radio" value="2" /><label for="month-02">February</label><br />
<input id="month-03" name="month" class="month" type="radio" value="3" /><label for="month-03">March</label><br />
<input id="month-04" name="month" class="month" type="radio" value="4" /><label for="month-04">April</label><br />
<input id="month-05" name="month" class="month" type="radio" value="5" /><label for="month-05">May</label><br />
<input id="month-06" name="month" class="month" type="radio" value="6" /><label for="month-06">June</label><br />
<input id="month-07" name="month" class="month" type="radio" value="7" /><label for="month-07">July</label><br />
<input id="month-08" name="month" class="month" type="radio" value="8" /><label for="month-08">August</label><br />
<input id="month-09" name="month" class="month" type="radio" value="9" /><label for="month-09">September</label><br />
<input id="month-10" name="month" class="month" type="radio" value="10" /><label for="month-10">October</label><br />
<input id="month-11" name="month" class="month" type="radio" value="11" /><label for="month-11">November</label><br />
<input id="month-12" name="month" class="month" type="radio" value="12" /><label for="month-12">December</label><br />

<div id="century_result"></div>
<div id="month_result"></div>
<div id="result"></div>

Getting a calc() CSS variable into JavaScript

  • Problem was, you are access root values which returns string.
  • and calc() function cannot calculate multiplication of 100ms * 44 so, I have changed --loaderSpeed:100 removed ms. and also created new valiable called loaderSecondsMultiplier.
  • After that, I have getPropertyValue get css variables values and converted them into a number and then just mutiply them and in last store it in finalTimeout.

//GETTING DOCUMENT STYLES
let docStyle = getComputedStyle(document.documentElement);
// GEETING CSS VARIABLE VALUES
let loaderSpeed = parseInt(docStyle.getPropertyValue('--loaderSpeed'));
let loaderSecondsMultiplier = parseInt(docStyle.getPropertyValue('--loaderSecondsMultiplier'));
// MUTIPLYING AND STORING IT'S VALUE TO finalTimeout
let finalTimeout = loaderSpeed * loaderSecondsMultiplier;
setTimeout(() => {
const box = document.getElementById('loaderWrapper');
box.style.display = 'none';
}, finalTimeout);
:root {
--loaderSpeed: 100;
--loaderSecondsMultiplier: 44;
}
<div id="loaderWrapper">
<h1>hey</h1>
</div>

css vars which use calc don't update

Yes, this is expected behavior and in fact completely respectful of the cascading nature of custom properties. From section 2.2 of the spec:

It is important to note that custom properties resolve any var() functions in their values at computed-value time, which occurs before the value is inherited.

This means that the value of the custom property --font-size as it appears on the root element is really calc(1 * 16px), not calc(var(--font-size-mult) * 16px), because the var(--font-size-mult) expression is evaluated when --font-size is computed for the root element.

This computed value, calc(1 * 16px), is then inherited by descendants. Any new value you set for --font-size-mult on any descendants is ignored (unless other references to it exist).

Should this be the expected behavior? Well, I can only tell you that the spec claims this is required to prevent cyclic references between ancestors and descendants. In the same paragraph as the sentence quoted above:

In general, cyclic dependencies occur only when multiple custom properties on the same element refer to each other; custom properties defined on elements higher in the element tree can never cause a cyclic reference with properties defined on elements lower in the element tree.

Finally, while Kriszta's answer demonstrates the right way to use calc() with custom properties taking inheritance into account, you should be using the rem unit instead of custom properties entirely, as that unit was made specifically for this use case.

Sass Variable in CSS calc() function

Interpolate:

body
height: calc(100% - #{$body_padding})

For this case, border-box would also suffice:

body
box-sizing: border-box
height: 100%
padding-top: $body_padding

How can I get a negative value of a CSS variables in a calc() expression?

Yes you can do it. Simply multiply by -1:

:root {  --margin: 50px;}
body { margin: 0 100px; border:1px solid;}
.box-1 { background: red; height: 100px; width: 200px; margin-left: calc(-1 * var(--margin));}
.box-2 { background: green; height: 100px; width: 200px; margin-left: calc(-1 * (-1 * var(--margin))); /* You can also nest calculation */}
<div class="box-1"></div><div class="box-2"></div>


Related Topics



Leave a reply



Submit