DEV Community

loading...

Fading an element using only Javascript

Matt Kenefick
Senior Engineer -- Learn to code first. Use libraries second.
・2 min read

I saw a post on S/O looking for a pure Javascript solution to animation; then the body started talking about CSS. 🤷🏻‍♂️ I decided to write a pure Javascript solution anyway that serves as a miniature example of tweening values linearly using time.

Example: https://jsfiddle.net/nqfud4j0/

It's intentionally using setInterval rather than requestAnimationFrame to demonstrate the example's use of time + controlled framerate rather than a delta or 'fast as possible.' A good solution would abstract this logic into a tweening library that combines both RAF + intervals to manage latency between frames.

Here's the commented code:

/**
 * Fade an HTMLElement to a specific value using style attributes
 * 
 * @param HTMLElement element
 * @param number toValue
 * @param number duration
 * @return void
 */
function fadeTo(element, toValue = 0, duration = 200) {
    // Store our element's current opacity 
    // (or default to 1 if null)
    const fromValue = parseFloat(element.style.opacity) || 1;

    // Mark the start time (in ms). We use this to calculate
    // a ratio over time that applied to our supplied duration 
    // argument
    const startTime = Date.now();

    // Determines time (ms) between each frame. Sometimes you 
    // may not want a full 60 fps for performance reasons or 
    // aesthetic 
    const framerate = 1000 / 60; // 60fps

    // Store reference to interval (number) so we can clear 
    // it later
    let interval = setInterval(() => {
        const currentTime = Date.now();

        // This creates a normalized number between now vs when we
        // started and how far into our desired duration it goes
        const timeDiff = (currentTime - startTime) / duration;

        // Interpolate our values using the ratio from above
        const value = fromValue - (fromValue - toValue) * timeDiff;

        // If our ratio is >= 1, then we're done.. 
        // so stop processing
        if (timeDiff >= 1) {
            clearInterval(interval);
            interval = 0;
        }

        // Apply visual. Style attributes are strings.
        element.style.opacity = value.toString();
    }, framerate);
}


// Element reference
const element = document.querySelector('div');

// Fade in and out on click
element.addEventListener('click', e => {
    // Animates our element from current opacity (1.0) to 0.25 for 1000ms
    fadeTo(element, 0.25, 1000);

    // Waits 1s, then animates our element's opacity to 1.0 for 500ms
    setTimeout(() => {
        fadeTo(element, 1.0, 500);
    }, 1000);
});
Enter fullscreen mode Exit fullscreen mode

Discussion (1)

Collapse
commdao profile image
commdao

Thanks a bunch for the comments included. I'm still early on with my study, but being able to read through it like this is super helpful. Rock on!