<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>
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);
}
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();
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.