Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <div class="fl">
    <button id="gradient-button">Native CSS Gradient Transition..</button>
</div>
<div class="fl">
    <button id="gradient-button-transition">Hover over me to Transition Smoothly..</button>
</div>
  
 <div class="fl"><button id="complex-gradient-transition">Automatic Gradient Transition</button></div>

              
            
!

CSS

              
                
body {
  background: rgb(15 19 22);
  padding: 2rem;
}
    #gradient-button, #gradient-button-transition, #complex-gradient-transition {
        background: linear-gradient(180deg, #ff7147, #e0417f);
        padding: 0.5rem 1.5rem;
        transition: all 0.1s ease-out;
        font-variation-settings: 'wght' 500;
        height: auto;
        border-radius: 100px;
        border: none;
        color: white;
        font-size: 1.25rem;
        box-shadow: none;
        transform: scale(1);
        margin: 0 0 2rem 1rem;
    }

    #gradient-button:hover {
        background: linear-gradient(45deg, #0037ff, #00adff);
        transform: scale(1.1);
    }
    #gradient-button-transition:hover {
        transform: scale(1.1);
    }
              
            
!

JS

              
                
    let complexTransitionTime = 3000    // <-- for complex animation
    let transitionTime = 1000           // <-- 100 ms - time our animation will last
    let previousTime, start = 0;        // <-- stores data on animation
    let angle = 180;                    // <-- angle of gradient
    let animationDirection = 'forwards' // <-- stores the animation direction
    let complexAnDirection = 'forwards' // <-- for continuous animation
    let element = 'gradient-button-transition'; // <-- id of our button
    let intervalFrame;                          // <-- stores the interval frame
    let complexIntervalFrame;                   // <-- for 'always on' gradient transition
    let currentPct = 0;                         // <-- current percentage through the animation
    let complexCurrentPct = 0;                  // <-- current pct for complex animation
    let elapsed = 0;                            // <-- number of frames which have ellapsed 
    let complexElapsed = 0;                     // <-- complex elapsed time
    
    // GRADIENT COLORS
    const gradientStopOne = [
        { pct: 0,  color: { r: 255, g: 113, b: 71 } }, // The first color in your gradient
        { pct: 100, color: { r: 0, g: 55, b: 255 } }   // The color you want your first color to transition to
    ];
    const gradientStopTwo = [
        { pct: 0,  color: { r: 224, g: 65, b: 127 } }, // The second color in your gradient
        { pct: 100, color: { r: 0, g: 173, b: 255 } }  // The color you want your second color to transition to
    ]
    const complexGradientOne = [
        { pct: 0,  color: { r: 224, g: 65, b: 127 } }, 
        { pct: 33, color: { r: 0, g: 173, b: 255 } },
        { pct: 66, color: { r: 203, g: 252, b: 5 } },
        { pct: 100, color: { r: 98, g: 5, b: 252 } }
    ]
    const complexGradientTwo = [
        { pct: 0,  color: { r: 255, g: 113, b: 71 } },
        { pct: 33,  color: { r: 0, g: 55, b: 255 } },
        { pct: 66, color: { r:30, g: 177, b: 7 } },
        { pct: 100, color: { r:228, g: 44, b: 200 } }
    ]
    // Apply our gradient programmatically so we can completely manipulate the gradient from JS rather than CSS
    let c1 = gradientStopOne[0].color;
    let c2 = gradientStopTwo[0].color;
    document.getElementById('gradient-button-transition').style.background = `linear-gradient(${angle}deg, rgb(${c1.r}, ${c1.g}, ${c1.b}), rgb(${c2.r}, ${c2.g}, ${c2.b}))`;
   
    // This function transitions between two rgb colors
    const getColor = function(pct, colorSet) {
        for (var i = 1; i < colorSet.length - 1; i++) {
            if (pct < colorSet[i].pct) {
                break;
            }
        }
        // This conversion figures out the transition between two rgb values
        var lower = colorSet[i - 1];
        var upper = colorSet[i];
        var range = upper.pct - lower.pct;
        var rangePct = (pct - lower.pct) / range;
        var pctLower = 1 - rangePct;
        var pctUpper = rangePct;
        var color = {
            r: Math.floor(lower.color.r * pctLower + upper.color.r * pctUpper),
            g: Math.floor(lower.color.g * pctLower + upper.color.g * pctUpper),
            b: Math.floor(lower.color.b * pctLower + upper.color.b * pctUpper)
        };
        // And returns the rgb code
        return `rgb(${color.r}, ${color.g}, ${color.b})`;
    }

    // This is our animation which we run on hover
    const animateGradient = function() {
        if(intervalFrame === undefined) {
            intervalFrame = setInterval(() => {
                let time = transitionTime / 1000; // time in seconds
                let numberOfFrames = time * 60; // 60 frames per second -> 1 second = 60 frames
                
                // If the animation is going forward
                if(animationDirection === 'forwards') {
                    // Add 1 to elapsed
                    elapsed += 1;
                    // The elapsed frames out of max frames
                    currentPct = Math.min(elapsed / numberOfFrames, 1) * 100;
                }
                else {
                    // Otherwise we're going back - subtract 1 from ellapsed
                    elapsed -= 1;
                    // The elapsed frames out of max frames
                    currentPct = Math.max(elapsed / numberOfFrames, 0) * 100;
                }
                
                // Calculate current color in this time for each gradient color
                let colorOne = getColor(currentPct, gradientStopOne);
                let colorTwo = getColor(currentPct, gradientStopTwo);

                // Generate CSS string
                let generateGradient = `linear-gradient(${angle}deg, ${colorOne}, ${colorTwo})`;

                // Add it to our background.
                document.getElementById(element).style.backgroundImage = generateGradient;

                // End the interval when we're done
                if(currentPct === 100 || currentPct === 0) {
                    clearInterval(intervalFrame);
                    intervalFrame = undefined;
                }
            }, 16.667); // 60 frames per second
        }
    };

    // This is our animation which we run on hover
    const complexGradientAnimation = function() {
        if(complexIntervalFrame === undefined) {
            complexIntervalFrame = setInterval(() => {
                let time = complexTransitionTime / 1000;
                let numberOfFrames = time * 60; // 60 frames per second -> 1 second = 60 frames
                
                if(complexCurrentPct === 100) {
                    complexAnDirection = 'backwards';
                }
                else if(complexCurrentPct === 0) {
                    complexAnDirection = 'forwards';
                }
                // If the animation is going forward
                if(complexAnDirection == 'forwards') {
                    // Add 1 to elapsed
                    complexElapsed += 1;
                    // The elapsed frames out of max frames
                    complexCurrentPct = Math.min(complexElapsed / numberOfFrames, 1) * 100;
                }
                else if(complexAnDirection === 'backwards') {
                    // Otherwise we're going back - subtract 1 from ellapsed
                    complexElapsed -= 1;
                    // The elapsed frames out of max frames
                    complexCurrentPct = Math.max(complexElapsed / numberOfFrames, 0) * 100;
                }

                // Calculate current color in this time for each gradient color
                let colorOne = getColor(complexCurrentPct, complexGradientOne);
                let colorTwo = getColor(complexCurrentPct, complexGradientTwo);

                // Generate CSS string
                let generateGradient = `linear-gradient(${angle}deg, ${colorOne}, ${colorTwo})`;

                // Add it to our background.
                document.getElementById('complex-gradient-transition').style.backgroundImage = generateGradient;

            }, 16.667); // 60 frames per second
        }
    };

    // On hover, run our animation
    document.getElementById('gradient-button-transition').addEventListener('mouseover', function() {
        animationDirection = 'forwards';
        animateGradient();
    });
    // On hover out, run our animation again, but backwards
    document.getElementById('gradient-button-transition').addEventListener('mouseleave', function() {
        animationDirection = 'backwards';
        animateGradient();
    });
    
    complexGradientAnimation();

              
            
!
999px

Console