CSS Only Slider
You can check the demo here:
And access the source code here:
- No dependencies
- Works on all browsers
- Very performative
- Not the greatest solution to use with CMS
- Not very DRY
This is a step-by-step tutorial for anyone with a reasonable amount of knowledge in HTML & SCSS. If you don’t want to do it step by step, scroll faster! Plus, I’ll be using BEM– if you’re not familiar with how BEM should be written, take a look at this: http://getbem.com/introduction/
Ok, ready to go! First of all, let’s take a look at the design:
Conceptual aside: Radio buttons
Before starting with the actual tutorial, let me tell you a bit about radio buttons’ features and how to use them properly. If you already know how to handle them, feel free to skip this part.
First of all, this is how an input type radio basic markup looks like:
A very important feature about radio buttons that we’ll be leveraging during this tutorial is the fact that only one can be checked at the time.
However, in order to make that happen, all of them require the same name:
<input type=“radio” name=“slider”>
Another relevant feature about radio button is that you can define which one is checked directly on the HTML. This will be very useful later on.
<input type=“radio” name=“slider” checked>
A cool fact is that you don’t actually need to click on the radio button itself to make it checked, you might as well click on it’s label.
And in order to get that working, you need this:
<label for=“”>This is a clickable label</label>
In order for the label to check a specific radio, you need to identify each radio button, this way the label knows which one it is referring to.
For this tutorial, we’ll use ID’s but you may use classes as well — classes work with radio buttons but not with checkboxes.
<input type=“radio” name=“slider” id=“slider-1”>
And then we’ll make the label refer for it:
<label for=“slider-1”>This is clickable</label>
That’s all we’ll need to know regarding radio buttons for now!
1. The Markup
Step 1 — Wrappers
Lets start by having a parent section which we’ll call slider. And then lets set up a div inside slider which we can call slider__holder.
The inner one will wrap the slider itself and the outer one will hold the inner, plus the titling content.
Step 2 — Radio buttons
Done that, let’s markup the radio buttons. We got to put them as a slider__holder sibling so we can easily refer to it later on.
We’ll need 5 of them, so:
Don’t forget to change the ID’s number on each radio button.
Plus, I want the middle one to be the visible one on page load, that’s why I defined it as checked.
Step 3 — Card as labels
We want all cards to be clickable, so each one of them will be a label for each one the 5 radios.
Mind that each label for=”slide-X” has to refer to each radio button, so don’t forget to change the number when you copy and paste.
You might have noticed that each slide has a modifier slider__item — n. We’ll be using it as soon as we need to refer to each slider__item.
Step 4 — Cards content
For the content of each card, I’ll leave it up to you. I’ll do mine but it doesn’t influence the slider’s functionality in any way, so this is up to your creative designer skills.
Step 5 — Navigation bullets
Besides giving an important visual clue of the current card selected, the bullets below the cards should be clickable to help the navigation between the slides.
Which is the same as saying that each bullet has to be a label for the radios as well.
Also, lets make bullets as a new element rather than have it as a slider element:
Once again we’re using bullets__item — n modifier since we’ll be referring to each one of them separately in the future.
Just place them under <div class=“slider__holder”></div> as a sibling.
Done that, we’re done with the markup.
You might have noticed that slider also has a section class.
That’s because I wanted to add a section title and description to it and make it as a separate element. It doesn’t have any influence in the functionality whatsoever and you’re free to ignore it. All the styles will be available in the source code.
Here’s the whole snippet:
2. The Functionality
Before anything else, I think we should make sure the labels are in fact checking the radio buttons.
The best option would be for us write some text inside the Cards, inside the bullet’s label tag and click on them. If the checked input changes, then it’s ok. If not, something might be wrong.
I did the following for debugging:
As I told you before, I won’t make any reference to each slide content and design, I rather focus on the functionality. However, for this tutorial sake, I’ll use my design and it’s styles as an example.
Step 1 — Active Slide
First of all, we need to set each card default style. Feel free to write your own styles as long as you include a transform: scale(0.85) among them.
Then we need to define how it will look when a certain slide is active. And that’s when the fun part starts.
So, when #slide-1 is checked we want .slider__item — 1 to be 100% scaled, so we do the following:
Explaining what just happended:
First: we referred to .slider__item — 1 (line 7);
Second: we told it to scale(1) when #slide-1 is checked (line 11 and 12);
In current language it means that when #slide-1 is checked, it’s sibling’s (~) .slider__holder son .slider__item — 1 will be 100% scaled.
Basically when you click on Card 1 it will get 100% scaled.
Then we must replicate it for the remainder cards. So when we click on Card 2 it will get 100% scaled and the sames for cards 3, 4 and 5.
At this point, when you click on a card it will get 100% scaled and all the other ones will get smaller — 85% scaled.
The same will happen if you could click on the bullets since they are labels as well.
Step 2— Non Active Slides
Now, we’ll have to define each slide position for when a certain slide is active. In the following case, for example, when #slide-1 is checked/active, .slider__item — 2 is 0.85 scaled and translated 100px.
And in the following one, #slide-1 is checked/active, .slider__item — 3 is 0.65 scaled, translated 210px and with z-index: 0.
And in the following one, #slide-1 is checked/active, .slider__item — 4 and .slider__item — 5 are 0.65 scaled, translated 210px, with 0 opacity and with z-index: -1.
And in the following one… there is no following one! Imagine doing this for all the active slides — defining each card position when a certain slide is active. It would be plain crazy!
Specially because there’s a pattern as you can see in the image below:
At certain active cards, some of the remainder ones behave the same way. For example, when card 1 is active, cards 4 and 5 assume the same position — behind card 3.
Step 3 — Loop it!
To tackled this kind of madness, lets use SCSS loops.
The following code does exactly the same but saves 90% of trouble!
Take a look:
Let me explain:
- We loop through each slide
- Inside each loop iteration, we loop again all slides, validating if:
- The current slide is 3 or more positions to the right
- is 2 positions to the right
- is 1 position to the right
- is the current slide
- is 1 position to the left
- is 2 positions to the left
- is 3 or more positions to the left
This way, we can tackle all the possibilities and give them style accordingly.
Take a second look at the following image for further understanding:
Step 4— Bullets
Now, we have to have a loop for the bullets as well:
This is a much simpler loop since you just have to define the active one.
Don’t forget to style it.
The same logic can be applied to build image sliders, tabbed content, and many more.
We hope everything was easy to follow and if you have any questions or comments, drop us a line in the commenting section!
If you liked it, please press 💚. It will let us know you want us to keep on writing more stuff like this.