Pure CSS slide show

A basic slide show using nothing but CSS:

Very lightweight and allows the page to be scrolled normally* while still easily jumping from slide to slide which is perfect for a landing page.

* Using CSS snap points it will change scrolling behaviour

The basic functionality

The basic functionality is using fragment identifiers to link to the slide elements:

<div class="slide-container">
  <div class="slide" id="side-1"> <!-- Slide with ID -->
    <h1>Slide 1</h1>

    <!-- Link to next slide -->
    <a href="#side-2" title="Next slide">
      <svg viewBox="4 4 16 16"><use href="#arrow-down" /></svg>

  <div class="slide" id="side-2"> <!-- Slide with ID -->

So far it’s just some links which jump to different parts of the page.

Enhancing with Scroll Behaviour

The scroll-behavior property can be used to give a smooth scrolling transition instead of just jumping between slides:

/* needs to be added to the scroll container */
html {
  scroll-behavior: smooth;

Currently, scroll-behavior only works in Chrome and FF but as it’s just an enhancement the low browser support isn’t an issue although a JS based fallback could be used.

Enhancing with CSS Snap Points

Another useful property is scroll-snap-type which can be used to limit scrolling to whole slides. Browser support is quite low at the moment (FF & Safari) but support is being added to Chrome soon.

Luckily detecting CSS snap point support is easy using @supports:

/* Support for FF using older spec which is limited to
   knowing the height of slides ahead of time and them
   all being the same */
@supports (scroll-snap-type: mandatory) and (scroll-snap-points-y: repeat(100%)) {
  .slide-container {
    overflow-y: auto;
    scroll-snap-type: mandatory;
    scroll-snap-points-y: repeat(100%);

/* Updated version based on latest spec */
@supports (scroll-snap-type: y mandatory) and (scroll-snap-align: start) {
  .slide-container {
    overflow-y: auto;
    scroll-snap-type: y mandatory;

  .slide {
    scroll-snap-align: start;

If scrolling isn’t important, using overflow: hidden works everywhere:


Another possibility is using CSS animations to transition between slides:

/* overflow hidden will need to be applied to the
   parent of .slide-container */
.slide-container {
  animation: slide 20s ease infinite;

/* Animate the translateY to transition between slides */
@keyframes slide {
   0%, 15% { transform: translateY(0%)    }
  20%, 35% { transform: translateY(-100%) }
  40%, 55% { transform: translateY(-200%) }
  60%, 75% { transform: translateY(-300%) }
  80%, 95% { transform: translateY(-400%) }

Unfortunately, the slide links won’t work when using CSS animations but it might make sense for some use cases.