Skip to content

Instantly share code, notes, and snippets.

@meduzen
Last active July 11, 2021 13:34
Show Gist options
  • Save meduzen/7ada5fc3d7296767c9e7f677229d60d4 to your computer and use it in GitHub Desktop.
Save meduzen/7ada5fc3d7296767c9e7f677229d60d4 to your computer and use it in GitHub Desktop.
CSS custom properties (CSS variables) stuff
<html>
<head>
<style>
:root {
/* Like me, you probably add a space between the semicolon and the value.
👇 */
--bg: hsl(0 0% 100%);
}
</style>
</head>
<body>
<p>This also exists in a <a href="https://twitter.com/meduzen/status/1117076932485615616">Tweet</a>.</p>
<script>
// BAD
let bgColor = getComputedStyle(document.documentElement).getPropertyValue('--bg')
console.log(bgColor)
/* Output:
- `hsl(0 0% 100%)` with styles minification (e.g. on production).
- ` hsl(0 0% 100%)` without minification (e.g. on dev environment).
👆 (Same space remains.) */
// GOOD
bgColor = getComputedStyle(document.documentElement).getPropertyValue('--bg').trim()
console.log(bgColor)
// bgColor = `hsl(0 0% 100%)` on every environment 👍
</script>
</body>

Update: a NPM package is born.


I find CSS variables syntax not very readable:

  • there’s this double hyphen thing in the name: --varName;
  • the var function is required on top of -- to access it: color: var(--myColor);.

Crazy. Let’s simplify this with…

The v() function!

@function v($var) {
  @return var(--#{$var});
}

Demo on Codepen

Usage

First, define your CSS variables normally:

:root {
  --primary: #000;
  --bg: #fff;
}

Then, use it with v(varName).

html {
  background: v(bg);
  color: v(primary);
}

It generates this:

html {
  background: var(--bg);
  color: var(--primary);
}

That’s only a 4 characters win, but it’s a cool one for readability and you’ll use it often.

That’s it!

We could have gone further, but…

From here til the end of the article, you’ll find other attempts to improve the thing.

Proposal #1: getter, setter

Let’s update the v() function to have both a getter and a setter, so that:

  • v(varName) returns var(--varName);
  • v(varName, value) declares --varName: value;;
@function v($name, $value: null) {
  @if $value == null {
    @return var(--#{$name}); // get
  }
  @return --#{$name} + ':' #{$value}; // set
}

This function is valid but unusable to shorten CSS prop: value because SASS functions can only be used on the value side (right side of the :). So there’s unfortunately no way to do this:

:root {
  v(primary, #000);
  v(bg, #fff);
}

Proposal #2: mixin to the rescue!

We could also use a mixin instead of a function:

@mixin v($name, $value) {
  --#{$name}: #{$value};
}

Mixins are perfect to write prop: value but are more characters to write due to the @include keyword ¯\_(ツ)_/¯

html {
  @include v(primary, #000);
  @include v(bg, #fff);
}

And no, there’s no way to alias @include in a shorter @i rule. This have been rejected.

Note: in case you wonder, you can declare a mixin and a function that have the same name (in our case, both are named v) without any conflict. Kinda cool!

Proposal #3: use SASS syntax instead of SCSS

Demo on Codepen

Wonderful thing: SASS syntax for mixins is way shorter: the @include is replaced by a single +, making the whole thing very short:

// function
@function v($name)
  @return var(--#{$name})

// mixin
@mixin v($name, $value: null)
  --#{$name}: #{$value}

// declare
:root
  +v(primary, #000)
  +v(bg, #fff)

// use
html
  background: v(bg)
  color: v(primary)

Problems I see with SASS:

  • (opinionated) I don’t like SASS syntax for various readability reasons;
  • +v(primary, #000) is still one character longer than --primary: #000;.

So at the end, let’s stick the the get v(varName) function.

@function v($name) {
@return var(--#{$name});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment