How to Make a Pure HTML & CSS Image Slider – With Working Explanation

2025-08-28 — By Siddharth Jain · 7 min read

Share this article:

How to Make a Pure HTML & CSS Image Slider – With Working Explanation

Creating a stylish, interactive image slider doesn’t need complex JavaScript!
With just HTML and CSS, you can build a fully functional slider that’s smooth, responsive, and lets users click arrows or dots to change images.
Let’s break down the process and understand how this clever technique works.


🚀 The HTML Structure

The backbone of this slider uses:

  • Radio inputs: These act as slide “switches.”
  • Labels: Used as clickable arrows and dots, linked to the radio inputs.
  • A slides container: Holds all your images inside flex items.

Each slide has a corresponding radio input, so only one slide can be “checked” at a time.


🎨 How the CSS Slider Works (Step-by-Step)

1. Hiding and Showing Slides

  • The .slides container uses display: flex for a row layout.
  • By default, the container is shifted to always show the first image.
  • When a radio input like #slide2 is checked, CSS :checked selectors with ~ shift the .slides container using transform: translateX(...) to bring the right slide into view.

2. Navigation Arrows

  • Arrows are just labels for the previous/next radio input.
  • Their visibility is controlled with CSS—only the correct arrow for the active slide is visible.

3. Dots Navigation

  • Dots at the bottom are label elements.
  • Clicking a dot checks the corresponding radio input, and the relevant slide comes into view.

4. No JavaScript Required!

  • All interactivity—slide change, arrow navigation, dot highlighting—is handled by CSS selectors targeting the checked radio button state.

🧩 Full Example Code

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Image Slider with Font Awesome Arrows</title>
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
      integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA=="
      crossorigin="anonymous"
      referrerpolicy="no-referrer"
    />
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      .slider-container {
        width: 100%;
        max-width: 800px;
        margin: 50px auto;
        position: relative;
        overflow: hidden;
        border-radius: 10px;
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
      }

      .slides {
        display: flex;
        width: 300%;
        transition: transform 0.5s ease-in-out;
      }

      .slide {
        width: 33.333%;
        flex-shrink: 0;
      }

      .slide img {
        width: 100%;
        height: 400px;
        object-fit: cover;
      }

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

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

      .dot:hover {
        background-color: rgba(255, 255, 255, 0.8);
      }

      .arrow {
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
        font-size: 30px;
        color: #fff;
        background-color: rgba(0, 0, 0, 0.5);
        padding: 10px;
        cursor: pointer;
        user-select: none;
        border-radius: 5px;
        transition: background-color 0.3s;
        text-decoration: none;
      }

      .arrow:hover {
        background-color: rgba(0, 0, 0, 0.8);
      }

      .left-arrow {
        left: 10px;
      }

      .right-arrow {
        right: 10px;
      }

      input[type="radio"] {
        display: none;
      }

      #slide1:checked ~ .slides {
        transform: translateX(0);
      }

      #slide2:checked ~ .slides {
        transform: translateX(-33.333%);
      }

      #slide3:checked ~ .slides {
        transform: translateX(-66.666%);
      }

      #slide1:checked ~ .dots label[for="slide1"],
      #slide2:checked ~ .dots label[for="slide2"],
      #slide3:checked ~ .dots label[for="slide3"] {
        background-color: #fff;
      }

      #slide1:checked ~ .arrow.left-arrow[for="slide3"],
      #slide1:checked ~ .arrow.right-arrow[for="slide2"],
      #slide2:checked ~ .arrow.left-arrow[for="slide1"],
      #slide2:checked ~ .arrow.right-arrow[for="slide3"],
      #slide3:checked ~ .arrow.left-arrow[for="slide2"],
      #slide3:checked ~ .arrow.right-arrow[for="slide1"] {
        display: block;
      }

      .arrow {
        display: none;
      }
    </style>
  </head>
  <body>
    <div class="slider-container">
      <input type="radio" name="slider" id="slide1" checked />
      <input type="radio" name="slider" id="slide2" />
      <input type="radio" name="slider" id="slide3" />

      <div class="slides">
        <div class="slide">
          <img src="https://picsum.photos/800/400?random=1" alt="Slide 1" />
        </div>
        <div class="slide">
          <img src="https://picsum.photos/800/400?random=2" alt="Slide 2" />
        </div>
        <div class="slide">
          <img src="https://picsum.photos/800/400?random=3" alt="Slide 3" />
        </div>
      </div>

      <label for="slide3" class="arrow left-arrow"
        ><i class="fas fa-chevron-left"></i
      ></label>
      <label for="slide1" class="arrow left-arrow"
        ><i class="fas fa-chevron-left"></i
      ></label>
      <label for="slide2" class="arrow left-arrow"
        ><i class="fas fa-chevron-left"></i
      ></label>
      <label for="slide2" class="arrow right-arrow"
        ><i class="fas fa-chevron-right"></i
      ></label>
      <label for="slide3" class="arrow right-arrow"
        ><i class="fas fa-chevron-right"></i
      ></label>
      <label for="slide1" class="arrow right-arrow"
        ><i class="fas fa-chevron-right"></i
      ></label>

      <div class="dots">
        <label for="slide1" class="dot"></label>
        <label for="slide2" class="dot"></label>
        <label for="slide3" class="dot"></label>
      </div>
    </div>
  </body>
</html>

🔍 How the Slider Works

  • The radios are “hidden switches.” Only one is active at a time.
  • Clicking an arrow/dot checks a radio, changing the :checked state.
  • CSS uses the checked state and general sibling ~ to animate the .slides container (translateX) so the right slide is visible.
  • Arrows and dots are both navigation controls, but all logic is handled in pure CSS—no JavaScript!

💡 Where to Use This Slider

This pure CSS slider is perfect for landing pages, portfolios, and wherever you want a simple, dependency-free image carousel.

NMeta Blogger
MetaBlogger.in is your go-to platform for insightful blogs, digital tools, and resources that empower creators, learners, and developers. From web development to content marketing, we simplify complex topics and share practical knowledge for today’s digital world. Stay inspired, stay informed — only on MetaBlogger.in.
Follow us