htmlcsscss-variablescss-calc

Use of calc() and var into CSS: elements rendered differently


Given the <style> I wrote, I expected the 1st <h1> and 2nd <h1> to have same font-size, but it is not true:

:root {
  --default-size: calc(1rem + 0.5vw);
  font-size: var(--default-size);
}

.font-size\:default {
  font-size: var(--default-size) !important;
}
<h1>DIMENSION</h1>
<h1 class="font-size:default">DIMENSION</h1>

Digging around, I found this comment on stackoverflow https://stackoverflow.com/a/48415933/7253377 , and the problem seems related to how var() are evaluated, or better, when they are evaluated by the browser.

So, I wrote this simple snippet and it seems to work correctly:

:root {
  --default-size: calc(1rem + 0.5vw);
}

* {
  font-size: var(--default-size);
}

.font-size\:default {
  font-size: var(--default-size) !important;
}
<h1>DIMENSION</h1>
<h1 class="font-size:default">DIMENSION</h1>

The only problem is that I don't think to get at 100% what is going on. The 1st approach didn't work because:

And the :root var() value happens to be different from the .font-size:default var() value? If yes, why?


Solution

  • The first issue is related to the default font-size applied to h1 by the browser so to do your testing you need to use a "neutral" tag to avoid dealing with default styles.

    Try with divs

    :root {
      --default-size: calc(1rem + 0.5vw);
      font-size: var(--default-size);
    }
    
    .font-size\:default {
      font-size: var(--default-size) !important;
    }
    <div>DIMENSION</div>
    <div class="font-size:default">DIMENSION</div>

    Now you will see a slight difference because of how 1rem works. It can be confusing but 1rem is relative to the font-size you set on the :root element and you set this one to be equal to calc(1rem + 0.5vw) and we have

    If used in the font-size property of the root element, or in a document with no root element, 1rem is equal to the initial value of the font-size property. ref

    So inside root the value is equal to calc(16px + .5vw) and this value is inherited by the first div.

    Now the second div is also using 1rem and this time 1rem will equal to calc(16px + .5vw) (the root font-size) so the value for the second div is equal to calc(16px + .5vw) + .5vw = 16px + 1vw. It's .5vw bigger than the first one

    If you move the styles to the body for example, both will be equal because in both cases the reference will be the root font-size that is not defined so the initial value 16px will be used

    body {
      --default-size: calc(1rem + 0.5vw);
      font-size: var(--default-size);
    }
    
    .font-size\:default {
      font-size: var(--default-size) !important;
    }
    <div>DIMENSION</div>
    <div class="font-size:default">DIMENSION</div>