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.