Create A Slider With Pure CSS
Create A Slider With Pure CSS
<div class="slider-container">
<div class="slider">
<div class="slides">
<div id="slides__1" class="slide">
<span class="slide__text">1</span>
</div>
<div id="slides__2" class="slide">
<span class="slide__text">2</span>
</div>
<div id="slides__3" class="slide">
<span class="slide__text">3</span>
</div>
<div id="slides__4" class="slide">
<span class="slide__text">4</span>
</div>
</div>
</div>
</div>
So here we have:
slider-container is just the element on your site that you want the slider to go in.
slider is like the 'screen', or the viewport that will display all your slides.
slides will hold your slides. This is the element that actually scrolls to give the slider effect.
slide is each individual slide. Note that you need the slide class, and a unique id for each one.
.slider-container {
background: linear-gradient(149deg, rgb(247, 0, 255) 0%, rgb(255, 145, 0) 100%);
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.slider {
width: 100%;
max-width: 600px;
height: 400px;
margin: 20px;
text-align: center;
border-radius: 20px;
position: relative;
}
slider-container can be anything - I've just used a flexbox to make it easy to centre the slider.
But if you prefer, you can use CSS Grid (it's a question of preferences, as we explained in
this CSS Grid Vs. Flexbox article)
slider just sets the size of your slider - you can adjust this to suit your needs.
.slides {
display: flex;
overflow-x: scroll;
position: relative;
scroll-behavior: smooth;
scroll-snap-type: x mandatory;
}
OK, this is where the magic happens. If we set overflow-x to scroll, anything that doesn't fit
in our slider viewport will be accessible only by scrolling.
.slide {
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
width: 100%;
height: 400px;
margin-right: 0px;
box-sizing: border-box;
background: white;
transform-origin: center center;
transform: scale(1);
scroll-snap-align: center;
}
.slide__text {
font-size: 40px;
font-weight: bold;
font-family: sans-serif;
}
Match the size of slide to be the same as slider. The final three properties, transform-
origin, transform, and scroll-snap-align, are key. These ensure that when we jump-link to any
particular slide, the slide will 'snap' into the middle of the slider viewport.
If you click inside the slider, then press the arrow keys, you'll see the smooth scrolling and
snapping behaviour in action.
But of course we don't want our users to have to do this! We want to put some navigation
buttons on the slider instead - and we should probably get rid of that scrollbar too!
<div class="slider-container">
<div class="slider">
<div class="slides">
<div id="slides__1" class="slide">
<span class="slide__text">1</span>
<a class="slide__prev" href="#slides__4" title="Next"></a>
<a class="slide__next" href="#slides__2" title="Next"></a>
</div>
<div id="slides__2" class="slide">
<span class="slide__text">2</span>
<a class="slide__prev" href="#slides__1" title="Prev"></a>
<a class="slide__next" href="#slides__3" title="Next"></a>
</div>
<div id="slides__3" class="slide">
<span class="slide__text">3</span>
<a class="slide__prev" href="#slides__2" title="Prev"></a>
<a class="slide__next" href="#slides__4" title="Next"></a>
</div>
<div id="slides__4" class="slide">
<span class="slide__text">4</span>
<a class="slide__prev" href="#slides__3" title="Prev"></a>
<a class="slide__next" href="#slides__1" title="Prev"></a>
</div>
</div>
</div>
</div>
Note that:
the href contains the jump link to the slide we want to move to. You have to set these
manually.
.slide a {
position: absolute;
top: 48%;
width: 35px;
height: 35px;
border: solid black;
border-width: 0 4px 4px 0;
padding: 3px;
box-sizing: border-box;
}
a.slide__prev {
transform: rotate(135deg);
-webkit-transform: rotate(135deg);
left: 5%;
}
a.slide__next{
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
right: 5%;
}
You can style and position these buttons however you want - I've chosen to have arrows
pointing in each direction. Sometimes the simple option is the best - but you can make your
own choice!
OK, pretty good - but ideally we don't want the buttons to be locked to each slide. Sliders
typically have buttons fixed in place.
Why, yes!
.slide a {
background: none;
border: none;
}
a.slide__prev,
.slider::before {
transform: rotate(135deg);
-webkit-transform: rotate(135deg);
left: 5%;
}
a.slide__next,
.slider::after {
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
right: 5%;
}
.slider::before,
.slider::after,
.slide__prev,
.slide__next {
position: absolute;
top: 48%;
width: 35px;
height: 35px;
border: solid black;
border-width: 0 4px 4px 0;
padding: 3px;
box-sizing: border-box;
}
.slider::before,
.slider::after {
content: '';
z-index: 1;
background: none;
pointer-events: none;
}
OK so what's going on here? Well first, we've taken the background and border off of
the a element. This makes our buttons effectively invisible.
Then, we've added before and after pseudo elements to slider. These have the same style that
we previously had on the a elements - the nice simple arrow. And we've positioned
them exactly on top of our now invisible buttons, and set pointer-events to none.
Because they are attached to the slider element and not slide, they will remain fixed in place
as the user scrolls through the slides. But... when the user clicks on one, they
are actually clicking on the invisible button attached to the actual slide.
Aha, I hear you say, but what about breadcrumbs, can we add those too?
Each breadcrumb will just be another jump link pointing to the relevant slide, and we'll
position it absolutely in the slider element.
<div class="slider__nav">
<a class="slider__navlink" href="#slides__1"></a>
<a class="slider__navlink" href="#slides__2"></a>
<a class="slider__navlink" href="#slides__3"></a>
<a class="slider__navlink" href="#slides__4"></a>
</div>
See? Same links as we used before. Now to style it:
.slider__nav {
box-sizing: border-box;
position: absolute;
bottom: 5%;
left: 50%;
width: 200px;
margin-left: -100px;
text-align: center;
}
.slider__navlink {
display: inline-block;
height: 15px;
width: 15px;
border-radius: 50%;
background-color: black;
margin: 0 10px 0 10px;
}