JavaScript30 - Day 3 (CSS Variables)

This is day 3 in my #javascript30 journey. This is the free course from Wes Bos that lets you brush up on your JavaScript skills via 30 projects.

Yesterday we built an analog clock. You can keep track of all the projects we're building here.

Today we're exploring scoped CSS variables and JS.


Day 3 - Scoped CSS Variables and JS

Today we are exploring CSS Variables. These can be made even more powerful by coupling them with JavaScript to update the values after the initial rendering.

Our exploration will give the end user three inputs where they can edit the spacing, blur and colour of elements within the page. This is a simple example but it is easy to consider how this can be altered and extended for some real use cases.

Our starter file for today looks like this:

Starter file in the Javascript30 day 3

Defining the CSS Variables

To do this first define the default variables on the root element:

:root {
      --base: #FFC153;
      --spacing: 10px;
      --blur: 10px;
    }

Once these variables have been defined we can start using them:

img {  
      padding: var(--spacing);
      background-color: var(--base);
      filter: blur(var(--blur));
    }

Now our page has these styles applied and looks like this:

With the default styles applied

Gathering Data from Inputs via JS

To grab the data from the inputs we need to capture them into a variable. As we will be using the querySelectorAll syntax which will return a NodeList. This looks a lot like an Array but doesn't have the same methods available. This is why we will need to use forEach() to loop over all of the inputs:

<script>  
  const inputs = document.querySelectorAll('.controls input')

  function handleUpdate() {
    //TODO
  }

  inputs.forEach(input => input.addEventListener('change', handleUpdate))
</script>  

A range input outputs a numerical value. To insert this into our CSS we need to know the appropriate suffix for this number. For example, in our --spacing and --blur styles we need to know that this value is followed by px. To handle this Wes created a data attribute on each of the inputs:

<input id="blur" type="range" name="blur" min="0" max="25" value="10" data-sizing="px">  

Now in our handleUpdate() function we can check to see whether sizings is present in the dataset & if it is capture it:

const suffix = this.dataset.sizing || ``;  
Selecting a CSS variable

Wes also added a handy name on our inputs so we can use these when selecting the style to update:

function handleUpdate() {  
  const suffix = this.dataset.sizing || ''
  document.documentElement.style.setProperty(
    `--${this.name}`,
    this.value + suffix,
  )
}

This is all of the code that we need to do to make our CSS variables update & change the page:


Now that everything has been done I have pushed this project live to a Firebase project. You can view it live here.

You can keep track of all the projects in this JavaScript30 challenge here.