Check out a free preview of the full Dynamic CSS with Custom Properties (aka CSS Variables) course

The "Javascript" Lesson is part of the full, Dynamic CSS with Custom Properties (aka CSS Variables) course featured in this preview video. Here's what you'd learn in this lesson:

Lea discusses how to set and read custom properties with JavaScript and walks through examples setting properties to communicate mouse location. How to get local pointer coordinates is also covered in this segment.


Transcript from the "Javascript" Lesson

>> And now let's get to the last section for today which has to do with JavaScript. And I feel that this is possibly the most exciting section because that is the biggest revolution that custom properties bring. The fact that we can use just a tiny bit of JavaScript to set them and have the rest of the CSS just adapt.

Whereas previously, we had to include like copious amounts of CSS code mixed with our JavaScript, it was such a mess. So how can we set and read some properties with JavaScript? The exact same methods that we use for regular properties. This API has existed for possibly decades. We just do, and that gives us the value of foo on the inline style of the element.

Or if we want to get the value of foo from wherever, even if it comes from a style sheet, we get the computed style of the element and then we use the same method name. And most importantly, this is what we're gonna be doing a lot when we want to set a custom property on the inline style.

We just do and we set the custom property to whatever we want. And that sets it on the inline style, but that's usually what we want, we don't usually want to be actually modifying style sheets. So what can we do with this? Let's look at a few examples.

So here we have a radial gradient whose center is hard coded to the center of the page. We wanted to, instead, do a spotlight effect that follows the mouse, we want its center to change to follow our mouse pointer. So how can we do that? In the past, we would need to use an event listener for mouse move and recreate the gradient every time.

However, today we can just set two custom properties So we're going to set --mouse-x and --mouse-y to evt.clientX and evt.clientY. And then, We can go here and use, well, we can't get just to use mouse x directly, we need to transform it first, cuz right now we just have a number.

So we multiply it by 1 pixel. Right, and we also need to provide a fallback. Let's say zero. And now, as I move my mouse pointer, the gradient does adapt horizontally. We can do the same vertically. Oops, calc. And now it adapts in both directions. However, this is not ideal.

Even though this already gives us a big advantage over what we would have to do before custom properties, it's not sufficiently usable. And let's see why. So let's go back to this SVG example. Let's say we wanted to set this look variable, remember it goes from 0 to 1, in terms of the mouse pointer so that we could move our mouse pointer and have the eyes appear to follow it, wouldn't that be cool?

But how do you convert this number of pixels to a 0 to 1 range? Even though what we said is a pure number, it's actually a fake pure number because it essentially corresponds to pixels and we can't really do much with it. So what can we do instead?

Instead of having a number of pixels, we could actually divide the number of pixels with the maximum number of pixels we could have. Which is given by innerwidth or window.innerwidth as we might have seen it, it's the same thing. So what does this give us? This gives us the percentage of the screen of the viewport that the mouse pointer has moved horizontally and dividing by inner height.

Gives us the percentage that the mouse pointer has moved across the viewport vertically. And that means we can use it just the same in everything that needs to use the mouse pointer, so here we can just set look based on that. Let's default it as well, in fact, let's give it a fullback of 0.5, and look at that.

It already worked. And the biggest advantage of this is that it works regardless of the CSS code that we intend to use it in. We can take exactly the same JavaScript code, copied into our previous example, Let's press Cmd+Enter to run. And if we multiply it by 100%, and here as well, it works for this as well.

In fact it works better because instead of having pixels here we have percentages. So the exact same JavaScript code can serve two entirely different use cases. This is very important when designing how you're gonna use custom properties to communicate between JavaScript and CSS. And it becomes even more important if there are different people writing the CSS code and different people writing the JavaScript.

You don't want to have to go back to the JavaScript developer every time you wanna tweak the design of your gradient, or every time you want to make a minor tweak on some kind of effect. You want to offload as much of the styling as possible to CSS.

You want to JavaScript to just send the very purest form of data so you can just iterate as much as you want in your CSS without having to go back to the JavaScript and change JavaScript code. That is the ideal separation of concerns. Now there are some things that we can do by having mouse-x and mouse-y that apply to the whole page, but sometimes we want local coordinates.

So how could we do that? And this is a summary of how we can do reusable pointer coordinates. So you should prefer abstract 0 to 1 percentages rather than absolute pixel lengths. 0 to 1 can be converted to a length, if you want, you can always multiply it by viewport units, for example.

But the reverse isn't possible if you have pixels even if you have pixels as a pure number, you can't do anything with them. So what about local coordinates? While having coordinates that apply to the percentage of the viewport that the mouse coordinate design is useful. Often we wanna do things that depend on the percentage of an element itself that the pointer is over.

It's relatively easy to get local pointer coordinates, all we need to do is get the bounding rectangle of the element. And then subtracted from client y and client x, and then we get local coordinates for the element itself. And in the same spirit has previously, instead of having pixels cuz that's what top and left would give us, we wanna divide by the width and height of the actual elements.

So we could get a 0 to 1 percentage that we could actually use for calculations in our CSS.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now