Home > Designing, Others > Custom Properties as State

Custom Properties as State

Here’s a fun idea from James Stanley: a CSS file (that presumably updates daily) containing CSS custom properties for “seasonal” colors (e.g. spring is greens, fall is oranges). You’d then use the values to theme your site, knowing that those colors change slightly from day to day.

This is what I got while writing this:

:root {
  --seasonal-bg: hsl(-68.70967741935485,9.419354838709678%,96%);
  --seasonal-bgdark: hsl(-68.70967741935485,9.419354838709678%,90%);
  --seasonal-fg: hsl(-68.70967741935485,9.419354838709678%,30%);
  --seasonal-hl: hsl(-83.70967741935485,30.000000000000004%,50%);
  --seasonal-hldark: hsl(-83.70967741935485,30.000000000000004%,35%);
}

I think it would be more fun if the CSS file provided was just the custom properties and not the opinionated other styles (like what sets the body background and such). That way you could implement the colors any way you choose without any side effects.

This makes me think that a CDN-hosted CSS file like this could have other useful stuff, like today’s date for usage in pseudo content, or other special time-sensitive stuff. Maybe the phase of the moon? Sports scores?! Soup of the day?!

/* <div class="soup">The soup of the day is: </div> */
.soup::after {
  content: var(--soupOfTheDay); /* lol kinda */
}

It’s almost like a data API that is tremendously easy to use. Pseudo content is even accessible content these days — but you can’t select the text of pseudo-elements, so don’t read this as an actual endorsement of using CSS as a content API.

Will Boyd just blogged about what is possible to put in a custom property. They are tremendously flexible. Just about anything is a valid custom property value and then the usage tends to behave just how you think it will.

body {
  /* totally fine */
  --rgba: rgba(255, 0, 0, 0.1);
  background: var(--rgba);

  /* totally fine */
  --rgba: 255, 0, 0, 0.1;
  background: rgba(var(--rgba));

  /* totally fine */
  --rgb: 255 0 0;
  --a: 0.1;
  background: rgb(var(--rgb) / var(--a));
}

body::after {
  /* totally fine */
  --song: "I need quotes to be pseudo content A and can't have line breaks without this weird hack A but still fairly permissive (💧💧💧) ";
  content: var(--song);
  white-space: pre;
}

Bram Van Damme latched onto that flexiblity while covering Will’s article:

That’s why you can use CSS Custom Properties to:

perform conditional calculations

pass data from within your CSS to your JavaScript

inject skin tone / hair color modifiers onto Emoji

toggle multiple values with one custom property (--foo: ; hack)

Bram points out this “basic” state-flipping quality that a custom property can pull off:

:root {
  --is-big: 0;
}

.is-big {
  --is-big: 1;
}

.block {
  padding: calc(
    25px * var(--is-big) +
    10px * (1 - var(--is-big))
  );
  border-width: calc(
    3px * var(--is-big) +
    1px * (1 - var(--is-big))
  );
}

Add a couple of scoops of complexity and you get The Raven (media queries with custom properties).

Will calls them “CSS variables” which is super common and understandable. You’ll read (and I have written) sentences often that are like “CSS variables (a.k.a CSS Custom Properties)” or “CSS Custom Properties (a.k.a CSS Variables.” Šime Vidas recently noted there is a rather correct way to refer to these things: --this-part is the custom property and var(--this-part) is the variable, which comes right from usage in the spec.

And that reminds me of this Vue proposal. I’m not sure if it went anywhere, but the state of a component would automatically be exposed as CSS custom properties.

<template>
  <div class="text">Hello</div>
</template>

<script>
export default {
  data() {
    return {
      color: 'red'
    }
  }
}
</script>

<style vars="{ color }">
.text {
  color: var(--color);
}
</style>

By virtue of having color as part of the state of this component, then --color is available as state to the CSS of this component. I think that’s a great idea.

What if every time you used useState in React, CSS custom properties were put on the :root and were updated automatically. For example, if you did this:

import React, { useState } from 'https://cdn.skypack.dev/react@^16.13.1';
import ReactDOM from 'https://cdn.skypack.dev/react-dom@^16.13.1';

const App = () => {
  const [ activeColor, setActiveColor ] = useState("red");
  return(
    <div className="box">
      <h1>Active Color: {activeColor}</h1>
      <button onClick={() => {setActiveColor("red")}}>red</button>
      <button onClick={() => {setActiveColor("blue")}}>blue</button>
    </div>
  );
}

ReactDOM.render(<App />,
document.getElementById("root"))

And you knew you could do like:

.box {
  border-color: 2px solid var(--activeColor);
}

Because the state automatically mapped itself to a custom property. Someone should make a useStateWithCustomProperties hook or something to do that. #freeidea

Libraries like React and Vue are for building UI. I think it makes a lot of sense that the state that they manage is automatically exposed to CSS.

And speaking of state that CSS should know about, I’ve seen quite a few demos that do fun stuff by mapping over things, like the current mouse position or scroll position, over to CSS. I don’t think it’s entirely unreasonable to ask for that data to be natively exposed to CSS. We already have the concept of environment variables, like env(safe-area-inset-top), and I could see that being used to expose page state, like env(page-scroll-percentage) or env(mouseY).


The post Custom Properties as State appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Categories: Designing, Others Tags:
  1. No comments yet.
  1. No trackbacks yet.
You must be logged in to post a comment.