Bloop Cheee Demo

On scroll variable font effect with Chee

Chee by James Edmondson is Paid/Commercial.
Code by Mandy Michael available on Codepen

I previously used Chee in the Ooze Demo using the temp axis. In this example we'll be using the yest and gvty axes, but rather than animating with CSS, we'll use a CSS Custom Property and connect it up with the browser scroll event.

What I'm aiming for with this effect is the feeling that as we scroll down to the bottom of the page the text feels as though it's falling and then "plops" onto the floor.

To get started I've set up our base html and css including a few css custom properties. The custom properties are a really important part of this process as they are what we will update over in our JS to change the values of the variable font axis.


It took me a really long time to figure out what text I wanted in this example. Words matter! Never underestimate the difference a word can make.

In the CSS below I have two custom properties, --axis and --pos. The --axis variable will change the value of both axes in the variable font (yest and gvty) - more on this later - and the --pos custom property will update the top offset of the text in relation to the page. This what will make the text to look like it's "falling" as we scroll.

h1 {
--axis: 0;
--pos: 0;
font-variation-settings: "yest" var(--axis), "gvty" var(--axis);
top: var(--pos);

Over in our JavaScript we'll set up the code needed to hook into the scroll event.

Accessing the Scroll position

Like our Ambient Light Sensor example we need to set up a few bits of information about the axis we want to affect and the event we want to use.

In our case we need the min and max values for both axes in Chee (yest and gvty), because they have the same range and we are using the same range for the effect, we can just use one value instead of defining two, which keeps things simple.

We also need to specify the min and max scroll position, which is 0% from the top, to 100% from the top. I've specifed these as numbers in our code to make it easier to do some math, we convert it back to a percentage later on in the code.

const maxAxis = 1000;
const minAxis= 0;

const posTop = 0;
const posBottom = 100;

Next we'll add an Event Listener to check when the user is scrolling and determine what the current scroll position is.

The code I am using is essentially the function that I wrote for generic access to variable font axes via JavaScript, you can read about it on the Getting Started page or find the source on Github.

The code below will convert the scroll position into a decimal which we can use to calculate two new values to pass into our css. As I mentioned earlier this will be one for the two font axis and one to calculate the top offset of the text.

var text = document.querySelector("h1");

window.addEventListener("scroll", function(e) {

var scrollPosition = (document.documentElement.scrollTop + document.body.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight);

const percent = scrollPosition / 0.99;
const axisScale = percent * (maxGravity + minGravity) - minGravity;
const positionScale = percent * (posBottom - posTop) + posTop;


We access the scroll position by using the scrollTop property for the element and the body. This will get the number of pixels that the element or body has scrolled vertically. For this example we'll add the element's scrollTop value to the body's scrollTop value and then we'll divde that by the elements scrollHeight value minus it's clientHeight value.

	var scrollPosition = (document.documentElement.scrollTop + document.body.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight);

The scrollHeight is essentially the height of all the elements content, including padding (whether it's visible or not) and the clientHeight which is the inner height of an element including padding but not borders, margins etc.

This will give us an accurate position for the top of the text element to shift it down the page.

The next step is to convert the position value to a decimal, so we can use it to normalise the axis values and link them together. This then allows us to multiple the new position value by the the max axis value and minus the min axis value, providing us with a number along our axis scale linked to the viewport scroll position.

The same applies to the position, but instead of minusing the top position value we'll add it instead so it looks like it's moving down the page.

	const position = scrollPosition / 0.99;
const axisScale = position * maxGravity - minGravity;
const positionScale = position * posBottom + posTop;

The last step is updating the CSS Custom Properties so that our CSS has access to the new values. We do this by using the setProperty method, which will set a new value for a property in our CSS."--axis", axisScale);"--pos", positionScale +'%');

Jumping back to the CSS (below) we can access the values of our custom properties by using the var() function.

For example:

h1 {
--axis: 0;
--pos: 0;
font-variation-settings: "yest" var(--axis), "gvty" var(--axis);

After this the last step is to update the rest of the styles however you need to so you can make a beautiful, interesting Bloop yourself!

You can see the full implementation in the Codepen example.

Have fun and make cool things.