Slider with Text Animation in HTML CSS

Slider with Text Animation in HTML CSS
Code Snippet:Slider Animations
Author: NIDAL
Published: 5 days ago
Last Updated: September 16, 2025
Downloads: 26
License: MIT
Edit Code online: View on CodePen
Read More

This tutorial will guide you through creating a visually appealing slider with text animation using HTML, CSS, and JavaScript. This is a great way to showcase products or information on your website, enhancing user engagement and improving the overall user experience.

Step 1: Setting up the HTML Structure

Creating the Slider Container

First, we’ll create the main container for our slider. This will hold all the elements, including the image, text, and navigation dots.

<div class="slider-container">

  <div class="content">
    <div class="color-overlay"></div>
    <div class="product-name">
      <span class="word-part first-word">Chai</span>
      <span class="word-part second-word">Vanilla</span>
    </div>
    <img class="milkshake-image" src="https://raw.githubusercontent.com/nidal1111/storage/master/assets/milkshake_banana.png" alt="Milkshake">
    <div class="nutrition-panel">
      <div class="nutrition-item">
        <div class="nutrition-value">20g</div>
        <div class="nutrition-label">Plant Protein</div>
      </div>
      <div class="nutrition-item">
        <div class="nutrition-value">13g</div>
        <div class="nutrition-label">Of Fiber</div>
      </div>
      <div class="nutrition-item">
        <div class="nutrition-value">15</div>
        <div class="nutrition-label">Vitamins</div>
      </div>
      <div class="nutrition-item">
        <div class="nutrition-value">1.8g</div>
        <div class="nutrition-label">Omega-3</div>
      </div>
      <div class="nutrition-item">
        <div class="nutrition-value">1B</div>
        <div class="nutrition-label">CFU Probiotics</div>
      </div>
    </div>
  </div>

  <div class="controls">
    <div class="control-dot active" data-index="0"></div>
    <div class="control-dot" data-index="1"></div>
    <div class="control-dot" data-index="2"></div>
    <div class="control-dot" data-index="3"></div>
  </div>
</div>

Step 2: Styling with CSS

Now, let’s add some style to make our slider look attractive. We’ll use CSS to control the layout, colors, animations, and responsiveness.

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: #2c3e50;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  padding: 20px;
}

.slider-container {
  position: relative;
  width: 600px;
  height: 400px;
  border-radius: 20px;
  overflow: hidden;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
  background: #4a90e2;
}

.color-overlay {
  position: absolute;
  top: -100%;
  left: 0;
  width: 100%;
  height: 100%;
  background: #e94b4b;
  transition: transform 1.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
  z-index: 10;
}

.color-overlay.slide-down {
  transform: translateY(100%);
}

.content {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  align-items: center;
  z-index: 5;
}

.product-name {
  font-size: 48px;
  font-weight: bold;
  color: white;
  text-align: center;
  margin: 20px 0;
  min-height: 60px;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 15;
  position: relative;
  margin-top: -2px;
  gap: 70px;
}

.word-part {
  transition: transform 0.8s ease-out;
  display: inline-block;
}

.milkshake-image {
  width: 400px;
  height: 300px;
  margin: 5px 0;
  object-fit: contain;
  transition: opacity 1.5s ease;
  position: relative;
  z-index: 5;
  position: absolute;
}

.nutrition-panel {
  background: white;
  border-radius: 15px;
  padding: 20px 30px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 19px;
  margin-top: 15px;
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
  position: relative;
  z-index: 15;
  min-width: 95%;
}

.nutrition-item {
  text-align: center;
  flex: 1;
}

.nutrition-value {
  font-size: 16px;
  font-weight: bold;
  color: #2c3e50;
  margin-bottom: 5px;
  transition: all 0.4s ease;
}

.nutrition-label {
  font-size: 12px;
  color: #7f8c8d;
  line-height: 1.2;
}

.controls {
  position: absolute;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 10px;
  z-index: 15;
}

.control-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.4);
  cursor: pointer;
  transition: all 0.3s ease;
}

.control-dot.active {
  background: white;
  transform: scale(1.2);
}

Step 3: Adding JavaScript for Interactivity

To make the slider dynamic and interactive, we’ll use JavaScript. This will handle the animation, transitions, and navigation between slides.

const flavors = [
  {
    name: ["Chai", "Vanilla"],
    color: "#4A90E2",
    image:
      "https://raw.githubusercontent.com/nidal1111/storage/master/assets/milkshake_banana.png",
    nutrition: ["20g", "13g", "15", "1.8g", "1B"]
  },
  {
    name: ["Maple", "Peanut"],
    color: "#E94B4B",
    image:
      "https://raw.githubusercontent.com/nidal1111/storage/master/assets/milkShake_caffe%CC%80.png",
    nutrition: ["35g", "10g", "10", "1.5g", "2B"]
  },
  {
    name: ["Cacao", "Coconut"],
    color: "#F4D03F",
    image:
      "https://raw.githubusercontent.com/nidal1111/storage/master/assets/milkShake_fragole.png",
    nutrition: ["40g", "25g", "22", "2.2g", "1B"]
  },
  {
    name: ["Berry", "Blend"],
    color: "#8E44AD",
    image:
      "https://raw.githubusercontent.com/nidal1111/storage/master/assets/milkshake_banana.png",
    nutrition: ["28g", "18g", "25", "2.0g", "3B"]
  }
];

let currentIndex = 0;
let isAnimating = false;

const container = document.querySelector(".slider-container");
const overlay = document.querySelector(".color-overlay");
const firstWord = document.querySelector(".first-word");
const secondWord = document.querySelector(".second-word");
const imageElement = document.querySelector(".milkshake-image");
const nutritionValues = document.querySelectorAll(".nutrition-value");
const dots = document.querySelectorAll(".control-dot");

function initSlider() {
  const currentFlavor = flavors[currentIndex];
  container.style.background = currentFlavor.color;
  firstWord.textContent = currentFlavor.name[0];
  secondWord.textContent = currentFlavor.name[1];
  imageElement.src = currentFlavor.image;
}

function morphWords(fromWords, toWords, onComplete) {
  const [fromFirst, fromSecond] = fromWords;
  const [toFirst, toSecond] = toWords;

  firstWord.style.transform = "translateX(0)";
  secondWord.style.transform = "translateX(0)";

  const maxMoveDistance = 20;

  let step = 0;
  const totalSteps = 40;

  function nextFrame() {
    if (step < totalSteps) {
      const progress = step / (totalSteps - 1);
      const easeProgress = progress * progress * progress;

      const moveDistance = maxMoveDistance * easeProgress;
      firstWord.style.transform = `translateX(${moveDistance}px)`;
      secondWord.style.transform = `translateX(-${moveDistance}px)`;

      const firstCharsToShow = Math.max(
        0,
        Math.ceil(fromFirst.length * (1 - easeProgress))
      );
      const secondCharsToShow = Math.max(
        0,
        Math.ceil(fromSecond.length * (1 - easeProgress))
      );

      const currentFirst = fromFirst.substring(0, firstCharsToShow);
      const currentSecond = fromSecond.substring(
        fromSecond.length - secondCharsToShow
      );

      if (currentFirst !== firstWord.textContent) {
        firstWord.textContent = currentFirst;
      }
      if (currentSecond !== secondWord.textContent) {
        secondWord.textContent = currentSecond;
      }

      step++;
      requestAnimationFrame(nextFrame);
    } else {
      setTimeout(() => {
        let expandStep = 0;
        const expandSteps = 40;

        function expandFrame() {
          const expandProgress = expandStep / (expandSteps - 1);
          const easeExpandProgress =
            expandProgress * expandProgress * (3 - 2 * expandProgress);

          const returnDistance = maxMoveDistance * (1 - easeExpandProgress);
          firstWord.style.transform = `translateX(${returnDistance}px)`;
          secondWord.style.transform = `translateX(-${returnDistance}px)`;

          const firstCharsToShow = Math.ceil(
            toFirst.length * easeExpandProgress
          );
          const secondCharsToShow = Math.ceil(
            toSecond.length * easeExpandProgress
          );

          const currentFirst = toFirst.substring(0, firstCharsToShow);
          const currentSecond = toSecond.substring(
            toSecond.length - secondCharsToShow
          );

          if (currentFirst !== firstWord.textContent) {
            firstWord.textContent = currentFirst;
          }
          if (currentSecond !== secondWord.textContent) {
            secondWord.textContent = currentSecond;
          }

          if (expandStep < expandSteps) {
            expandStep++;
            requestAnimationFrame(expandFrame);
          } else {
            firstWord.style.transform = "translateX(0)";
            secondWord.style.transform = "translateX(0)";
            firstWord.textContent = toFirst;
            secondWord.textContent = toSecond;
            if (onComplete) onComplete();
          }
        }

        expandFrame();
      }, 100);
    }
  }

  nextFrame();
}

function animateNutritionValues(newValues) {
  nutritionValues.forEach((value, index) => {
    setTimeout(() => {
      value.style.opacity = "0";
      setTimeout(() => {
        value.textContent = newValues[index];
        value.style.opacity = "1";
      }, 150);
    }, index * 80);
  });
}

function changeSlide(newIndex) {
  if (newIndex === currentIndex || isAnimating) return;

  isAnimating = true;
  const currentFlavor = flavors[currentIndex];
  const newFlavor = flavors[newIndex];

  overlay.style.background = newFlavor.color;
  overlay.classList.add("slide-down");

  setTimeout(() => {
    morphWords(currentFlavor.name, newFlavor.name);
    animateNutritionValues(newFlavor.nutrition);

    setTimeout(() => {
      imageElement.src = newFlavor.image;
      imageElement.style.opacity = "0";

      setTimeout(() => {
        container.style.background = newFlavor.color;
        overlay.classList.remove("slide-down");
        overlay.style.transform = "translateY(-100%)";

        setTimeout(() => {
          imageElement.style.opacity = "1";
          overlay.style.transform = "";
          isAnimating = false;
        }, 300);
      }, 100);
    }, 400);
  }, 0);

  dots[currentIndex].classList.remove("active");
  dots[newIndex].classList.add("active");
  currentIndex = newIndex;
}

function autoSlide() {
  if (!isAnimating) {
    const nextIndex = (currentIndex + 1) % flavors.length;
    changeSlide(nextIndex);
  }
}

dots.forEach((dot, index) => {
  dot.addEventListener("click", () => changeSlide(index));
});

initSlider();
setInterval(autoSlide, 4000);

Congratulations! You’ve successfully created a slider with text animation using HTML, CSS, and JavaScript.

Related posts:

Loading... ...

Loading preview...

Device: Desktop
Dimensions: 1200x800
Lines: 0 Characters: 0 Ln 1, Ch 1

Leave a Comment

About W3Frontend

W3Frontend provides free, open-source web design code and scripts to help developers and designers build faster. Every snippet is reviewed before publishing for quality. Learn more.