How to Make CSS Reactive!

Adam Crockett 🌀 - Aug 23 '20 - - Dev Community

So picture the scene, we are at a tech conference in your home city, and a strange developer comes up to you, (that's me) I say to you.

Hey, is your CSS Reactive?
...

🤨 You might think some of the following:
Was I supposed to answer that, there was a long pause, this is awkward.
What is reactive?
Why would you want to make CSS Reactive?
And finally...
Hey stop putting words in my mouth.

What is reactive programming?

This is a big topic but to sum it up without doing it much justice.. Some data changes and JavaScript responds to those changes, the data is bound to a function like a stick and a seperate pointy end is bound by lashings of glue. But we are not going to talk about survival on a desert island today, mores the pitty.

Why would I make my CSS Reactive?

I hear you, you might think it's some gimmick maybe or just adding complexity?
I have thought about this for a while, I have came to the conclusion that the standard model of styling individual elements and expecting the end result as whole to be consistent is complex, having styling update on user interaction whilst also handling business logic side effects are separate issues and therefore more complex than the single way to handle styling logic that I will present.

What if I said. Stop styling DOM elements! Too far? how would you make beautiful UI's?

Yeah that's a bit silly, but actually, is it? CSS custom properties have been around for a while now, they allow you to style what you might consider a pointer of sorts rather than an element to style. I feel that variables the best way to produce repeatable results in any language, that's what you need for a consistent design right? Now to be clear I'm still saying style classes etc, as normal but use more variables at runtime when the need arises, il get to that

Not only that, custom properties can have several useful behaviors.

  • scope reduction when applied to elements as roots
  • real-time changes
  • custom syntax
  • store data CSS does not understand
  • quick to compute

Tip:

If using Sass or any preprocessor, CSS properties have a use at runtime and should not be overlooked. Infact you can build custom properties from sass variables which I have covered in the past for insane results.


Okay back to the story; You have gone home now, pondering what on earth I was talking about, re.css, what's that?

Here's what I hope will show up one day when you Google re.css.

re.css is style guide (TODO) and accompanying library which branches off from css-in-js, it's goals are to provide enhanced performance, split responsibility and improved UX.

Split responsibility?

If you have ever styled a single thing in JavaScript, be it through vanilla, React, Vue or Angular, you are going to have something like this happen.

  • HTML loads and parsed
  • CSS loads parses and renders by looking up the DOM tree for selectors. Actually there is more to it via the CSSOM but il get to to that another time
  • JavaScript loads a few scripts, maybe your bundles or ESMs and then renders strings of HTML
  • If string HTML contains CSS then that gets applied as before

Phew that was actually a really simplified description of the loading a typical SPA without SSR and even that was a-lot.

It's almost like doing the same thing twice, this is what you might then see, a flash of horrible white un-styled content which nobody ever wants to see, your users want to see something, anything, just not that. It's the equivalent of a hotel staff member spitting at you, not very welcoming really 😱.

Well there's SSR, server side rendering generally helps because the first part of the render where your js's HTML and CSS is not loaded, suddenly it is, that unifies the process a bit. But there's a cost at your expense, you then have to go and use another framework specific to your chosen architecture to enable SSR.

What if we did things differently, we set a CSS variable in a stylesheet then style placeholder element where our component renders, once JS has loaded, we hand over responsibility of that variable or a set of variables to JavaScript, because this is the bit I neglected to mention, CSS custom properties can be interacted with using JavaScript! You would see something that could bare 🐻 some resemblance to your content before loading in that content. No more flash of un-styled content.

But it gets better, if all your CSS variables and styling mostly reside in stylesheets, all you need to do is set the property on the JavaScript side (I mentioned they are pointer like when used by scripting) and let the browser handle the rest, there is no further computation from JavaScript required.

But that's not true I hear you cry, "the reason I use CSS-in-JS is so I can compute styles based off of other styles or data." Example: if background is grey then border blue and width is 3px on a Tuesday. Well as it turns out CSS is kind of logical thanks to calc and we can still keep responsibility on the css side.

Calc

You can do ALOT with pure CSS that's for sure, when you first see the calc function your mind races, this is mathematical logic in real time, amazing! Then it hits you, JavaScript has access to way more stuff! CSS can't tell me where the mouse cursor is or the ambient light around me, so the logic is a bit limited to what is inside my stylesheet and viewport.

That's why we have these pure CSS vs JavaScript debates, re.css say something else, let them both be friends and allow each to play to thier strengths rather than one assuming the responsibility of the other.

There are a few things to know before we continue.

/* calc can be nested */
/* CSS custom properties are valid calc values */
calc( calc( var(--the-room-is-dark) * 200) - 20);
Enter fullscreen mode Exit fullscreen mode

You could certainly feed CSS variables from JavaScript and compute with calc, I think it's viable for smaller calculations. The above example had magic numbers though, ideally all the values would be variables.

Okay so it looks like we moved a good chunk of our styling logic into stylesheets but what about the other way around, I mentioned that you could store values in CSS that CSS doesn't understand, why would I want to do that?

Take this example:

:root {
    --current-theme: light;
    --theme-text-color: #000;
    --theme-bg-color: #fff;
}
Enter fullscreen mode Exit fullscreen mode

CSS cannot directly use the current theme value but it's best bud JavaScript can. Your JavaScript could then set dark-mode and then switch the colours accordingly through more CSS custom properties.

The trouble is, media queries and dev-tools, supports rules and other external factors can change the value of a CSS variables and JavaScript then become out of sync, there is no event listener for onPropertyChange, so I wrote a simple yet powerful library to add reactivity to those changes (caveat you must handle the media query or mousever from the JavaScript side), also it helps with getting and setting none reactively as well.

Imagine external changes just inexpensively cause JavaScript to fire functions which sets off a beautiful chain reaction of styling logic, that's essentially what I have published (but CSS cannot directly trigger the observable, JS has to handle that, see the comments) regardless, it does 90% of what I set out to do and there's always 2.0.0, anyways I want to share with you.

GitHub logo adam-cyclones / reactive-css-properties

Set css custom properties and react to changes in realtime from JavaScript

Reactive css logo

Reactive CSS Properties

A tiny library to supercharge your styling workflow. With Reactive CSS Properties (re.css) you can set css custom properties and react to changes in realtime from JavaScript

Website - Report a bug - Supported frameworks

Table of contents

The case for re.css

You can think of modern JavaScript having two main responsibilities, updating business logic and updating styling, The trouble with the latter is that this adds extra overhead and new problems to overcome, re.css sets out that it is css's responsibility to update styling and JavaScript should…




There is a lot more to cover but this post is getting long, next time let's build something, maybe style a TODO app with ideas from re.css

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .