JavaScript 30 – Day 3: CSS Variables and JS

Welcome to my recap of Day 3 of the free JavaScript 30 online video course by Wes Bos. In case you really have not yet heard of the course, quickly head over to it and get started right away! ๐Ÿ™‚

Please refer to the JavaScript 30 archive for all recap posts.

Objective

Day 3 is a quicky! ๐Ÿ˜€ The task is to use JavaScript in order to manipulate CSS variables referenced by some elements on the page, and thus customize their styling on the fly.

The provided starter files include not more than a single HTML file that again contains the markup for UI as well as some inline CSS that takes care of the styling. Like before, I moved the latter into a separate CSS file for my fork of the JavaScript 30 repository.

To tackle the JavaScript part on my own, I stopped the video right after the CSS variables have been defined and used.

Conception

Since Wes completely prepared the markup already, the only thing left is to add an event handler to the three inputs, and update the value of a CSS variable when the according element is changed. Since Wes also defined name attributes that match the CSS variable name, this can be done by using a single callback only.

Implementation

Implementing the above concept is pretty straightforward. Since I never worked with CSS variables before, however, I had to look up how to manipulate them by JavaScript first; I found this tutorial by Zack Bloom.

I ended up with the following code:

const body = document.body;

function updateVariable( el ) {
    body.style.setProperty( `--${el.getAttribute( 'name' )}`, el.value + ( el.dataset.sizing || '' ) );
}

document.querySelectorAll( '.controls input' ).forEach( ( el ) => {
    updateVariable( el );
    el.addEventListener( 'input', ( e ) => updateVariable( e.target ) );
} );

To speed things up (yes, a little, I know), I cached the body element, which I used to manipulate the CSS variables on. I also executed the updating function for each element once to take care of mismatches with the CSS variable defaults and the input values, or to counter old values cached by the browser.

Refinement

As usual, I then continued the video and compared what Wes did with my code.

First difference is that I decided for the input event (instead of, for example, a combination of change and mousemoveโ€”which in my opinion donโ€™t make so much sense, to be honest ๐Ÿ˜‰ ). At least I am not aware of any downside of using this event.

Besides the two things mentioned before already (i.e., caching the body element, and updating the CSS variables once the page loads), there was only one bigger difference: the definition and usage of the update function. Wes took advantage of passing a function reference (instead of a function itself) to addEventListener. By doing this, the individual element is defined as the this context.

I really liked this, so I adapted my code as well. This means I could get rid of the arrow function inside theย addEventListener call as well as the argument in the update function. However, since I want to execute the latter myself, I have to call it on the element.

My updated code now looks like so:

const body = document.body;

function updateVariable() {
    body.style.setProperty( `--${this.getAttribute( 'name' )}`, this.value + ( this.dataset.sizing || '' ) );
}

document.querySelectorAll( '.controls input' ).forEach( ( el ) => {
    updateVariable.call( el );
    el.addEventListener( 'input', updateVariable );
} );

Live Demo

Want to see this in action? Well, here is a live demo. ๐Ÿ™‚

Retrospection

As I said, I never did anything with CSS variables before. Now I did. Cool. ๐Ÿ™‚

I learned how to define and use (and override) CSS variables, and how to manipulate them with JavaScript.

And I also will (try to) internalize how and when to make use of implicit binding, or the default this context, in general.

And You?

JavaScript 30 is free! So, unless you already did this on your own, whatโ€™s your reason not to? ๐Ÿ™‚

Leave a Reply

Your email address will not be published. Required fields are marked *