Estelle Weyl | @estellevw | Github | Press key to advance.

CSS Math & Variables

CSS Custom Properties and Math in property values

CSS Math & Variables

  • CSS Custom Properities
    • Creating custom properties --*
    • Using custom properties var(--*) function
  • Evironmental Variables
    • env() function
  • Math
    • calc()
    • min(), max(), clamp()
    • Other "math" functions

CSS Custom Properties

Custom properties with --*

Custom properties (--*): CSS variables

Property names that are prefixed with -- are custom properties

They contain a value that can be used in other declarations using the var() function.

  • The above are the the custom properties for this part of the slide deck.
  • Update the colors above to change the slide deck.

Global property values

Custom properties are scoped to the element(s) they are declared on, and participate in the cascade. The main.css file has global colors.

The five custom properties on the previous slide, --font, --dark_bg, --colorpop, and --lightsplash have been overwritten for this deck, thanks to "the cascade"

Scoped property values

Custom properties are scoped to the elements they are declared on. What happen if we scope more locally and change the values of some properties?

Change the figure to header and change some values

Remove a line. If no value is set for a custom property on a given element, the value of its parent is used.

The var(--*) function

Using Custom Properties

Custom properties containing values are used in declarations using the var() function. Note property names are case sensitive

Using Custom Properties

The var() function can be used as a value in other functions

Using Custom Properties


:root:lang(en-us) {--wedding: #FFFFFF;}
:root:lang(hi-in) {--wedding: #CC0000;}

So you don't get bored staring at the same deck all day:

:root { --splashcolor: #880088;
        --dark_bg: #666666; }

Fallbacks for Custom properties

OOoops, you thought you declared a custom property, but you didn't. No worries. Include fall backs.

  1. color will be red because colorpop was misspelled.
    color: var(--colorpoop, red);
  2. background-color will be green because custom property names are case sensitive
    background-color: var(--colorpoop, var(--splashColor, green));
  3. text-decoration-color will be blue because '--colorpop, --splashcolor' is not a valid custom property name.
    text-decoration-color: var(--colorpop, --splashcolor, blue);

Invalid values

Paragraph will be blue

body { color: red; } 
p { color: blue; } 
p { color: 16px; }

Syntax errors are ignored.

Invalid values

Paragraph will be red

:root {--size: 16px;}
body { color: red; } 
p { color: blue; } 
p { color: var(--size); }

Invalid: custom property values that are invalid are not ignored. Value, if inheritable, is inherited

Invalid values

Paragraph will be red

:root {--size: 16px;}
body { color: red; } 
p { color: blue; } 
p { color: var(--pooperscooper); }

If the value doesn't exist, it is invalid, and fails too. Not just invalid values, but non-existant properties.

SpecSpeak: Value computation (where variable references are resolved) happens after applying the cascade, which means that the `color: blue` declaration was already eliminated in favor of the variable reference.

Invalid custom properties


Invalid variables

When the browser encounters an invalid var() substitution, the initial or inherited value of the property is used.

If a variable substitution doesn’t make any sense, the browser:

  1. Checks if the property color is inheritable.
  2. If not, it sets the value to its default initial value.

While a syntax error in a CSS property / value pair will lead to the line being ignored, using a cascaded value, invalid substitution -- using a custom property value that is invalid -- is not ignored.

Variable references are resolved after applying the cascade, so a valid declaration may have been eliminated in favor of a variable reference without checking validity of that reference.

Custom Properties and JavaScript

you can get the value just like you would any property value

// get a variable
let heading = document.querySelector('.current header h1');

let headingColor = 
   getComputedStyle( heading ).getPropertyValue( "--colorpop" );

Can be used to pass information to JavaScript

--forJS: if(count > 15) this.width = 100;

You can also use .style to read or write on an inline style, but since inline styles are not what I recommend, 😝

env() function

env() function

three iphone layouts demonstrating use of env() function

For inserting browser environment variable values

body {
    env(safe-area-inset-top, 20px)
    env(safe-area-inset-right, 20px)
    env(safe-area-inset-bottom, 20px)
    env(safe-area-inset-left, 20px);



calc() syntax

To perform calculations anywhere a <length>, <frequency>, <angle>, <time>, <percentage>, <number>, or <integer> value is allowed.

property: calc(expression)


height: calc(90vh - 100px);

calc() computations

Use standard math:

 calc( 6 * 2 / 3 - 4 + 5);

Use parenthese to make it less confusing

 calc( 6 * (2 / 3 ) - (4 + 5));

calc() rules

  • Operands can be any <length> syntax value, with or without units.
  • Mixing different units is AOK
  • Nesting a calc() in a calc() is also AOK
  • calc() inside a custom property is, you guessed it, AOK.
  • Use parentheses to establish computation order & for code legibility.
  • Surround operands with whitespace. Is "-" a minus or a negative number?
  • Don't divide by zero or a non-number
  • % for width and heights on some elements may be auto, so may lead to odd results

calc() examples

:root {
  --widthA: calc(100% - 80px);
  --widthB: calc(var(--widthA) / 2);
  --widthC: calc(var(--widthB) / 2);

min(), max() and clamp()

Can be used anywhere a <length>, <frequency>, <angle>, <time>, <percentage>, <number>, or <integer> is allowed.

min() - only works in Safari

Sets the smallest (most negative) value from a list of comma-separated expressions.

max() - only works in Safari

Sets the largest (most positive) value from a list of comma-separated expressions.

clamp() - doesn't work anywhere

Clamps a value between an upper and lower bound: a middle value within a range of values between a defined minimum and maximum

When supported

font-size: max(4vw, 2em, 2rem);
max-height: min(40vh, 300px);

clamp() - for the future

clamp( <minimum value>, <preferred value>, <maximum value>)

Those three values can be calculations, min() functions and max() functions as well

clamp(MIN, VAL, MAX)
is resolved as
max(MIN, min(VAL, MAX))


font-size: clamp(1rem, 4vw, 3rem);
  clamp(var(--smallFont), var(--userPref), var(--largeFont));

Other Math!

Trigonometric and exponential values


Useful Math!

Responsive font equation

  calc( var(--min_font) + 
  (var(--max_font) - var(--min_font)) * ( (100vw - var(--min_width)) / 
  ( var(--max_width) - var(--min_width)) ));


Next ➹