CSS variables with fallback for older browsers

Ced picture Ced · May 30, 2017 · Viewed 17.1k times · Source

TL;DR: How can you use SCSS to have CSS variables with a fallback for older browsers.

I'm trying to make sense of this article. In my opinion, you have to already be an advanced SASS user to understand it, which I'm not. To make matters worse, it's the only article I found on the subject.

Here is what I'm trying to achieve:

My scss should be along the lines of :

body {
  @include v(background-color, primary)
}

then the processed CSS should be

body{
   background: yellow; /* Yellow being defined above as the primary color */
   background: var(--color-primary);
}

By playing around a bit, I can already get the value of the CSS variable like so:

$colors: (
  primary: yellow,
);

:root {
  @each $name, $color in $colors {
    --color-#{$name}: $color;
  }
}

@mixin background-color($color_) {
  background: var(--color-#{$color_});
}

To use it:

body{
  @include background-color(primary);
}

Which will result in this:

body {
    background: var(--color-primary);
    /* But the fallback is missing :(, I tried  things with the map-get but it's really eluding me... */
}

Answer

rdhainaut picture rdhainaut · Feb 10, 2018

If you're using Sass, you can automate fallbacks through a Sass mixin. Create a map of your CSS variable names and their values, and then you can look up those values in a mixin that outputs the fallback style and the preferred one

$vars: (
  primary: yellow,
);

:root {
  --primary: map-get($vars, primary);
}

@mixin var($property, $varName) {
  #{$property}: map-get($vars, $varName);
  #{$property}: var(--#{$varName});
}

The above mixin is used like so:

body {
  @include var(background-color, primary);
}

and outputs the following CSS:

:root {
  --primary: yellow;
}

body {
  background-color: yellow;
  background-color: var(--primary);
}

Et voilà :)