If you’ve ever wanted to make your website feel more alive, a smooth, animated slider is a great place to start. In this post, I’ll walk you through how I created a colorful gradient slider using just HTML, CSS, and a small amount of JavaScript.
This slider looks elegant because it mixes soft gradients, simple shapes, and smooth transitions. It doesn’t rely on any heavy libraries or frameworks, just clean front-end code.
The Structure
The basic structure of the slider is very simple.
Each slide is a section that contains two parts — a text area on the left and a shape area on the right.
Here’s what the HTML looks like:
<div class="slider">
<div class="slide active">
<div class="text-box">
<h2>I'm the first Box</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer lacinia dui lectus.</p>
</div>
<div class="shape"></div>
</div>
<div class="slide">
<div class="text-box">
<h2>I'm the second Box</h2>
<p>Donec scelerisque ipsum diam, ac mattis orci pellentesque eget.</p>
</div>
<div class="shape"></div>
</div>
</div>
This structure repeats for each slide.
The .active class tells which slide is currently visible. JavaScript handles moving this class from one slide to the next as you click the navigation arrows.
The Styling Magic (CSS)
The beauty of this slider lies in the CSS.
The background gradients, transitions, and subtle depth all come from a few powerful CSS properties.
Let’s start with the background and layout:
.slider {
position: relative;
width: 100%;
height: 100vh;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #6a11cb, #2575fc);
color: #fff;
}
Here’s what’s happening:
linear-gradient(135deg, #6a11cb, #2575fc)creates that glowing two-tone background.display: flexkeeps the content centered both vertically and horizontally.- The full
100vhheight gives the slider a bold, full-screen look.
Now, for the shape on the right side:
.shape {
width: 200px;
height: 250px;
background: linear-gradient(145deg, #ff5f6d, #ffc371);
border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%;
transform: rotate(-10deg);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
transition: all 0.6s ease-in-out;
}
This part is what gives the design its unique look.
Let’s break it down:
- The gradient background makes the shape pop from the page.
- The border-radius with multiple values creates an organic blob-like shape instead of a normal rectangle.
- The rotate() transformation tilts it slightly, adding motion and depth.
- The transition ensures it moves smoothly when the slide changes.
You can experiment with different border-radius values or rotations to create shapes that feel more dynamic or playful.
Smooth Transitions Between Slides
The slider uses a small JavaScript snippet to switch between slides.
When you click the next or previous button, the script simply moves the .active class to the next slide.
Here’s a simplified version:
const slides = document.querySelectorAll('.slide');
let index = 0;
function showSlide(i) {
slides.forEach(slide => slide.classList.remove('active'));
slides[i].classList.add('active');
}
document.querySelector('.next').addEventListener('click', () => {
index = (index + 1) % slides.length;
showSlide(index);
});
document.querySelector('.prev').addEventListener('click', () => {
index = (index - 1 + slides.length) % slides.length;
showSlide(index);
});
This small block controls the whole slider interaction.
It cycles through slides smoothly without reloading the page or using any extra libraries.
Why This Design Works
There are a few simple reasons why this slider looks modern and engaging:
- Strong contrast between text and background for readability.
- Gradients give life and personality to each slide.
- Minimal motion — transitions are soft, not flashy.
- Balanced layout — text on one side, visuals on the other.
When all these elements come together, you get a slider that feels professional and smooth without being overdesigned.Final Thoughts
This gradient slider is a great example of what clean CSS and thoughtful design can do.
It doesn’t need a framework or animation library to feel interactive — just a few well-placed gradients, shapes, and transitions.
If you’d like to see the original inspiration or play with the live version, visit the CodePen link here:
https://codepen.io/Akimzzy/pen/JjGKMoX
At the end of the day, design is about balance. This slider finds that balance between simplicity and creativity — a mix of code that works well and looks even better.
Full Code
Here is the complete code with one index.html file
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
<title>Slider</title>
<style>
*,
*:before,
*:after {
margin: 0;
padding: 0;
box-sizing: inherit;
}
html {
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
font-size: 62.5%;
}
@media only screen and (max-width: 800px) {
html {
font-size: 57%;
}
}
body {
background-color: #0b0b0f;
color: #fff;
padding: 8rem;
}
@media only screen and (max-width: 1000px) {
body {
padding: 0;
}
}
.container {
position: relative;
overflow: hidden;
border-radius: 5rem;
}
@media only screen and (max-width: 1000px) {
.container {
border-radius: 0;
}
}
.slider {
display: flex;
width: 500%;
height: 55rem;
transition: all .25s ease-in;
transform: translateX(0);
}
@media only screen and (max-width: 1000px) {
.slider {
height: 100vh;
}
}
.slider .box {
height: 100%;
width: 100%;
display: grid;
grid-template-columns: repeat(2, 1fr);
align-items: center;
overflow: hidden;
position: relative;
}
@media only screen and (max-width: 650px) {
.slider .box {
grid-template-columns: 1fr;
grid-template-rows: repeat(2, 1fr);
}
}
.slider .box .bg {
background-color: rgba(0, 0, 0, 0.15);
width: 50%;
transform: skewX(7deg);
position: absolute;
height: 100%;
left: -10%;
transform-origin: 0 100%;
}
.slider .details {
padding: 5rem 10rem;
z-index: 10;
grid-column: 1 / span 1;
}
@media only screen and (max-width: 650px) {
.slider .details {
grid-row: 2 / span 1;
grid-column: 1 / -1;
text-align: center;
padding: 3rem;
transform: translateY(-8rem);
}
}
.slider .details h1 {
font-size: 4rem;
font-weight: 700;
margin-bottom: 1rem;
}
.slider .details p {
font-size: 1.4rem;
color: #d6d6d6;
line-height: 1.6;
margin-bottom: 2.5rem;
}
.slider .details button {
padding: 1rem 3rem;
color: #fff;
border-radius: 2rem;
outline: none;
border: none;
cursor: pointer;
background-color: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(5px);
transition: all .3s ease;
}
.slider .details button:hover {
background-color: rgba(255, 255, 255, 0.25);
}
.slider .box1 {
background: linear-gradient(135deg, #3d005a, #b5179e);
}
.slider .box1 .illustration .inner {
background: linear-gradient(160deg, #c77dff, #7b2cbf);
border-radius: 2rem;
transform: rotate(8deg);
}
.slider .box2 {
background: linear-gradient(135deg, #002a80, #0096c7);
}
.slider .box2 .illustration .inner {
background: radial-gradient(circle at 30% 30%, #00b4d8, #023e8a);
border-radius: 50%;
transform: none;
}
.slider .box3 {
background: linear-gradient(135deg, #004b23, #38b000);
}
.slider .box3 .illustration .inner {
background: linear-gradient(135deg, #70e000, #9ef01a);
clip-path: polygon(25% 5%, 75% 5%, 95% 50%, 75% 95%, 25% 95%, 5% 50%);
transform: none;
}
.slider .box4 {
background: linear-gradient(135deg, #ff6a00, #ffcc00);
}
.slider .box4 .illustration .inner {
background: linear-gradient(135deg, #ffd166, #ff7b00);
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
transform: none;
}
.slider .box5 {
background: linear-gradient(135deg, #52006a, #ff0080);
}
.slider .box5 .illustration .inner {
background: linear-gradient(135deg, #ff4ecd, #c9184a);
transform: skewX(-15deg);
border-radius: 1.5rem;
}
.slider .illustration {
grid-column: 2 / -1;
grid-row: 1 / -1;
justify-self: center;
}
@media only screen and (max-width: 650px) {
.slider .illustration {
grid-row: 1 / span 1;
grid-column: 1 / -1;
display: flex;
justify-content: center;
align-items: center;
}
}
.slider .illustration .inner {
height: 25rem;
width: 18rem;
position: relative;
transition: all 0.4s ease;
}
.slider .illustration .inner:hover {
transform: scale(1.05);
}
.prev,
.next,
.trail {
z-index: 10000;
position: absolute;
}
.prev,
.next {
width: 4rem;
cursor: pointer;
opacity: 0.3;
transition: all .3s ease;
}
.prev:hover,
.next:hover {
opacity: 1;
}
.prev {
top: 50%;
left: 2%;
transform: translateY(-50%);
}
.next {
top: 50%;
right: 2%;
transform: translateY(-50%);
}
.trail {
bottom: 5%;
left: 50%;
transform: translateX(-50%);
width: 60%;
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 1rem;
text-align: center;
font-size: 1.5rem;
}
.trail div {
padding: 2rem;
border-top: 3px solid #fff;
cursor: pointer;
opacity: .3;
transition: all .3s ease;
}
.trail div:hover {
opacity: .6;
}
.active {
opacity: 1 !important;
}
</style>
</head>
<body>
<div class="container">
<div class="slider">
<div class="box1 box">
<div class="bg"></div>
<div class="details">
<h1>I'm the first Box</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer lacinia dui lectus. Donec scelerisque ipsum diam, ac mattis orci pellentesque eget.</p>
<button>Check Now</button>
</div>
<div class="illustration"><div class="inner"></div></div>
</div>
<div class="box2 box">
<div class="bg"></div>
<div class="details">
<h1>I'm the second Box</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer lacinia dui lectus. Donec scelerisque ipsum diam, ac mattis orci pellentesque eget.</p>
<button>Check Now</button>
</div>
<div class="illustration"><div class="inner"></div></div>
</div>
<div class="box3 box">
<div class="bg"></div>
<div class="details">
<h1>I'm the third Box</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer lacinia dui lectus. Donec scelerisque ipsum diam, ac mattis orci pellentesque eget.</p>
<button>Check Now</button>
</div>
<div class="illustration"><div class="inner"></div></div>
</div>
<div class="box4 box">
<div class="bg"></div>
<div class="details">
<h1>I'm the fourth Box</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer lacinia dui lectus. Donec scelerisque ipsum diam, ac mattis orci pellentesque eget.</p>
<button>Check Now</button>
</div>
<div class="illustration"><div class="inner"></div></div>
</div>
<div class="box5 box">
<div class="bg"></div>
<div class="details">
<h1>I'm the fifth Box</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer lacinia dui lectus. Donec scelerisque ipsum diam, ac mattis orci pellentesque eget.</p>
<button>Check Now</button>
</div>
<div class="illustration"><div class="inner"></div></div>
</div>
</div>
<svg xmlns="http://www.w3.org/2000/svg" class="prev" width="56.898" height="91" viewBox="0 0 56.898 91"><path d="M45.5,0,91,56.9,48.452,24.068,0,56.9Z" transform="translate(0 91) rotate(-90)" fill="#fff"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" class="next" width="56.898" height="91" viewBox="0 0 56.898 91"><path d="M45.5,0,91,56.9,48.452,24.068,0,56.9Z" transform="translate(56.898) rotate(90)" fill="#fff"/></svg>
<div class="trail">
<div class="box1 active">1</div>
<div class="box2">2</div>
<div class="box3">3</div>
<div class="box4">4</div>
<div class="box5">5</div>
</div>
</div>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/gsap-latest-beta.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/CSSRulePlugin3.min.js"></script>
<script>
const slider = document.querySelector(".slider");
const trail = document.querySelector(".trail").querySelectorAll("div");
let value = 0;
let trailValue = 0;
let interval = 4000;
const slide = (condition) => {
clearInterval(start);
condition === "increase" ? initiateINC() : initiateDEC();
move(value, trailValue);
animate();
start = setInterval(() => slide("increase"), interval);
};
const initiateINC = () => {
trail.forEach(cur => cur.classList.remove("active"));
value === 80 ? value = 0 : value += 20;
trailUpdate();
};
const initiateDEC = () => {
trail.forEach(cur => cur.classList.remove("active"));
value === 0 ? value = 80 : value -= 20;
trailUpdate();
};
const move = (S, T) => {
slider.style.transform = `translateX(-${S}%)`;
trail[T].classList.add("active");
};
const tl = gsap.timeline({defaults: {duration: 0.6, ease: "power2.inOut"}});
tl.from(".bg", {x: "-100%", opacity: 0})
.from("p", {opacity: 0}, "-=0.3")
.from("h1", {opacity: 0, y: "30px"}, "-=0.3")
.from("button", {opacity: 0, y: "-40px"}, "-=0.8");
const animate = () => tl.restart();
const trailUpdate = () => {
if (value === 0) trailValue = 0;
else if (value === 20) trailValue = 1;
else if (value === 40) trailValue = 2;
else if (value === 60) trailValue = 3;
else trailValue = 4;
};
let start = setInterval(() => slide("increase"), interval);
document.querySelectorAll("svg").forEach(cur => {
cur.addEventListener("click", () => cur.classList.contains("next") ? slide("increase") : slide("decrease"));
});
const clickCheck = (e) => {
clearInterval(start);
trail.forEach(cur => cur.classList.remove("active"));
const check = e.target;
check.classList.add("active");
if(check.classList.contains("box1")) value = 0;
else if (check.classList.contains("box2")) value = 20;
else if (check.classList.contains("box3")) value = 40;
else if (check.classList.contains("box4")) value = 60;
else value = 80;
trailUpdate();
move(value, trailValue);
animate();
start = setInterval(() => slide("increase"), interval);
};
trail.forEach(cur => cur.addEventListener("click", (ev) => clickCheck(ev)));
const touchSlide = (() => {
let start, move, change, sliderWidth;
slider.addEventListener("touchstart", (e) => {
start = e.touches[0].clientX;
sliderWidth = slider.clientWidth/trail.length;
});
slider.addEventListener("touchmove", (e) => {
e.preventDefault();
move = e.touches[0].clientX;
change = start - move;
});
const mobile = (e) => {
change > (sliderWidth/4) ? slide("increase") : null;
(change * -1) > (sliderWidth/4) ? slide("decrease") : null;
[start, move, change, sliderWidth] = [0,0,0,0];
};
slider.addEventListener("touchend", mobile);
})();
</script>
</body>
</html>