DEV Community 👩‍💻👨‍💻

Matt Kenefick
Matt Kenefick

Posted on

Fading an element using only Javascript

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

Top comments (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!

Create an Account!
Now it's your turn!
 
🗒 Share a tutorial
🤔 Reflect on your coding journey
❓ Ask a question

Create an account to join hundreds of thousands of DEV members on their journey.