DEV Community

Cover image for Inspired by Apple's web animations, I have written a JavaScript library.
Steven Lei
Steven Lei

Posted on

Inspired by Apple's web animations, I have written a JavaScript library.

Hello, I am Steven Lei.

I love Apple products, and so do their website. They did a lot of fantastic animations for presenting their products, primarily scrolled-based, when we scroll the webpage up and down, the animation plays forward and backward.

As a web developer, I tried to reproduce their animation work, learn from the process, and record it as screencasts.

To achieve the scroll-based animation, we have to do some calculation work with JavaScript, like whether the element has appeared on screen, the scrolled distance, the element offset, and so forth. And we will update the element style accordingly.

As they have the common requirements mentioned above, I wondered if this development process could be more straightforward. What if we can achieve the same goal without writing a single line of JavaScript?

Initial Design

Scroll-based animations are based on the scrolling distance and position of elements. I would like to have a number when the element starts to appear from the bottom of the page, and disappear from the top. Numbers between 0 to 1 would be simple enough, at least in this stage.

I have used the IntersectionObserver API to explore if the element is on-screen or not. And next, we have to think about how to use this number.

The Flexibility

As animation involves a variety of requirements, for instance, fading in an element, moving the element, changing the color of a text etc. We cannot limit the ability just on some of those. So I have decided to put the number as a CSS variable, this would be flexible enough for working out different animation scenarios.

The Name of the Library

I have started to develop the library and named it Trigger JS because every scroll triggers a new value, just a literal meaning.

Thoughts on the usage of JavaScript

I want to simplify the development process, so this library's purpose is to let developers create scroll-based animation without writing JavaScript. I have decided to use HTML attributes and CSS variables.

As the library name is Trigger JS, I have used tg- as the prefix of the related HTML attributes. I know tg- does not quite fulfil the standard of HTML5, that's okay, I will keep an option to set the prefix, for example, data-tg-*, to completely get rid of this concern. But for now, I will keep using tg- here first.

The First Attribute: tg-name

The tg-name HTML attribute is mainly for two purposes: elements to be monitored and the name of the CSS variable.

We will add the tg-name attribute to the element that we want to monitor, for example:

<h1 tg-name="opacity">
  Hello World
</h1>
Enter fullscreen mode Exit fullscreen mode

Trigger JS will fetch all HTML elements with tg-name attribute into an array called activeElements (via document.querySelector('[tg-name'])), and observe them with IntersectionObserver API.

A scroll event listener is attached to window, which will calculate the relative position of elements in activeElements within the browser window: 0 when the element appears from the bottom, and 1 when the element disappears from the top, and 0.5 when it is in the middle.

Finally, we will put this calculation result to the element with CSS variable, for instance, --opacity: 0.5. So that we can use the value in the appropriate CSS property, in this example, opacity: var(--opacity);.

The Range Setting

0 to 1 is excellent in some situations. But if we want to move an element with transform, it would be good to adjust the start and end value (We can do the calculation in CSS with calc() though, but let's make it simpler).

That's why I have added tg-from and tg-to. If we want to move an element by 400px from the right to the left when scrolling up the page, we can set tg-from="200" and tg-to="-200".

And yes, we have to define the frequency of movement. We can set tg-steps="400" so that the element is moving pixel-by-pixel. But what if we want to keep the increment to be 1 but change the range of tg-from and tg-to? We can do the calculation ourselves or use another attribute tg-step="1" to avoid doing the math.

Numbers are not Perfect

Sometimes, we need an exact value. Let's say we want to change the text color, what we need is a color code instead.

That's why tg-map is being added, this gave us the ability to convert a value from a number to a value. For example:

<h1
  tg-name="color"
  tg-from="0"
  tg-to="2"
  tg-step="1"
  tg-map="0: black; 1: blue; 2: purple"
>
  Hello World
<h1>
Enter fullscreen mode Exit fullscreen mode

The calculation value will be 0, 1 or 2 throughout the scroll, and convert to a final value with the setting in tg-map:

  • 0 -> black
  • 1 -> blue
  • 2 -> purple

So we can update the text color easily with:

<style>
h1 {
  color: var(--color);
}
</style>
Enter fullscreen mode Exit fullscreen mode

Noice Reduction

Sometimes we are only interested in certain values. For example, we only want to know when 25, 50, 75 happens from 0 to 100 (tg-from="0" and tg-to="100"). In this situation, tg-filter takes part.

<h1
  id="heading"
  tg-name="color"
  tg-from="0"
  tg-to="100"
  tg-step="1"
  tg-filter="25,50,75"
  tg-map="25: red; 50: yellow; 75: green"
>
  Red (25), Yellow (50), Green (75)
</h1>

<style>
  body {
    padding: 100vh 0; /* In order to make the page have enough rooms for scrolling */
  }

  #heading {
    color: var(--color);
  }
</style>
Enter fullscreen mode Exit fullscreen mode

Open Source

The above is the introduction of creating this library, and this project is available on GitHub - triggerjs/trigger. Please feel free to try out, submit pull requests and share your thoughts. Your opinion is precious.

Please star it if you like it, and that would be great to have your participation.

Cheers!

Discussion (0)