Pure JavaScript effects

I often use slideUp, slideDown, slideToggle, fadeIn, fadeOut and fadeToggle as effects in my projects. I have been using JQuery a lot but want to reduce my dependency on that framework and do everything in VanillaJS.

I was first thinking that I should add effects to the HTMLElement interface (HTMLElement.prototype.FUNCTIONNAME) but read that it wasn’t a good idea.

This plugin has been tested and is working with Google Chrome (75.0.3770.100), Mozilla Firefox (67.0.4), Microsoft Edge (42.17134.1.0) and Internet Explorer (11.829.17134.0), without any polyfill. If you want to support older browsers (requestAnimationFrame), check out our post on transpilation and polyfilling of JavaScript.

JavaScript

I have created a JavaScript plugin with functions inside a namespace to make sure that function names not collide with names in other JavaScript libraries.

var annytab = annytab || {};
annytab.effects = (function () {

    'use_strict';

    // Public methods
    return {

        slideDown: function (el, duration, display) {

            // Return if the element is visible
            if (this.isVisible(el) === true) {
                return;
            }

            // Set default values for parameters
            duration = duration || 1000;
            display = display || 'block';

            // Display the element
            el.style.display = display;

            // Create variables
            var start = null;
            var height = el.offsetHeight;
            var overflow = el.style.overflow;

            // Set height and hide overflow
            el.style.height = '0';
            el.style.overflow = 'hidden';

            // Run animation
            function run(timestamp)
            {
                // Set start time
                if (!start) start = timestamp;

                // Calculate progress
                var progress = height * ((timestamp - start) / duration);

                // Set element height
                el.style.height = Math.min(progress, height) + 'px';

                // Check if the animation should end
                if (progress < height)
                {
                    window.requestAnimationFrame(run);
                }
                else
                {
                    // Reset element
                    el.style.height = '';
                    el.style.overflow = overflow;
                }
            }

            // Start animation
            window.requestAnimationFrame(run);

            // Return the element
            return el;
        },
        slideUp: function (el, duration) {

            // Return if the element not is visible
            if (this.isVisible(el) === false) {
                return;
            }

            // Set default values for parameters
            duration = duration || 1000;

            // Create variables
            var start = null;
            var height = el.offsetHeight;
            var overflow = el.style.overflow;

            // Hide overflow
            el.style.overflow = 'hidden';

            // Run animation
            function run(timestamp)
            {
                // Set start time
                if (!start) start = timestamp;

                // Calculate progress
                var progress = height - (height * ((timestamp - start) / duration));

                // Set element height
                el.style.height = Math.max(progress, 0) + 'px';

                // Check if the animation should end
                if (progress > 0)
                {
                    window.requestAnimationFrame(run);
                }
                else
                {
                    // Reset element
                    el.style.display = 'none';
                    el.style.height = '';
                    el.style.overflow = overflow;
                }
            }

            // Start animation
            window.requestAnimationFrame(run);

            // Return the element
            return el;
        },
        slideToggle: function (el, duration, display) {

            // Set default values for parameters
            duration = duration || 1000;
            display = display || 'block';

            // Check if we should slide up or slide down
            if (this.isVisible(el) === true) {
                this.slideUp(el, duration);
            }
            else {
                this.slideDown(el, duration, display);
            }

            // Return the element
            return el;
        },
        fadeIn: function (el, duration, display) {

            // Return if the element is visible
            if (this.isVisible(el) === true) {
                return;
            }

            // Set default values for parameters
            duration = duration || 1000;
            display = display || 'block';

            // Display the element
            el.style.display = display;

            // Create variables
            var start = null;

            // Set opacity
            el.style.opacity = 0.00;
            el.style.filter = 'alpha(opacity=0)'; /* For IE8 and earlier */

            // Run animation
            function run(timestamp)
            {
                // Set start time
                if (!start) start = timestamp;

                // Calculate progress
                var progress = 100 * (timestamp - start) / duration;

                // Set element opacity
                el.style.opacity = Math.min(progress, 100) / 100;
                el.style.filter = 'alpha(opacity=' + Math.min(progress, 100) + ')'; /* For IE8 and earlier */

                // Check if the animation should end
                if (progress < 100) {
                    window.requestAnimationFrame(run);
                }
                else {
                    // Reset element
                    el.style.opacity = '';
                    el.style.filter = ''; /* For IE8 and earlier */
                }
            }

            // Start animation
            window.requestAnimationFrame(run);

            // Return the element
            return el;
        },
        fadeOut: function (el, duration) {

            // Return if the element not is visible
            if (this.isVisible(el) === false) {
                return;
            }

            // Set default values for parameters
            duration = duration || 1000;

            // Create variables
            var start = null;

            // Set opacity
            el.style.opacity = 1.00;
            el.style.filter = 'alpha(opacity=100)'; /* For IE8 and earlier */

            // Run animation
            function run(timestamp)
            {
                // Set start time
                if (!start) start = timestamp;

                // Calculate progress
                var progress = 100 - (100 * ((timestamp - start) / duration));

                // Set element opacity
                el.style.opacity = Math.max(progress, 0) / 100;
                el.style.filter = 'alpha(opacity=' + Math.max(progress, 0) + ')'; /* For IE8 and earlier */

                // Check if the animation should end
                if (progress > 0)
                {
                    window.requestAnimationFrame(run);
                }
                else {
                    // Reset element
                    el.style.display = 'none';
                    el.style.opacity = '';
                    el.style.filter = ''; /* For IE8 and earlier */
                }
            }

            // Start animation
            window.requestAnimationFrame(run);

            // Return the element
            return el;
        },
        fadeToggle: function (el, duration, display) {

            // Set default values for parameters
            duration = duration || 1000;
            display = display || 'block';

            // Check if we should fade out or fade in
            if (this.isVisible(el) === true) {
                this.fadeOut(el, duration);
            }
            else {
                this.fadeIn(el, duration, display);
            }

            // Return the element
            return el;
        },
        isVisible: function (el) {
            if (typeof el === 'undefined' || el === null) { return false; }
            return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);
        }
    };

})();

How to use the plugin

To apply an effect to many elements, use a loop. You need to add the element as a parameter to a function, other parameters have default values.

function toggleForm()
{
    // Get the container
    var container = document.getElementById('inputForm');

    // Check if it is visible
    var visible = annytab.effects.isVisible(container);

    // Hide all containers
    var collection = document.getElementsByClassName('hideable');
    for (var i = 0; i < collection.length; i++) {
        annytab.effects.slideUp(collection[i], 500);
    }

    // Show the container if it wasn't visible
    if (visible === false) {
        annytab.effects.slideDown(container, 500);
    }

} // End of the toggleForm method

Leave a Reply

Your email address will not be published. Required fields are marked *