In this new tutorial, we’ll learn how to create a fully functional, responsive image slideshow with thumbnails, from scratch. To accomplish it, we won’t need to write a single line of JavaScript. In actual fact, once more, we’ll only use HTML and CSS as we take advantage of the “CSS checkbox hack technique”.
Note: This tutorial assumes that you’re familiar with that CSS technique along with advanced CSS selectors (e.g. general sibling combinator). If you haven’t heard of these before, or need a refresher, check out the following tutorials:
-
CSS SelectorsHow to Build an Accordion Component With the CSS Checkbox Hack
-
CSSQuick Tip: How to Create an Off-Canvas Feedback Form With Pure CSS
-
CSS SelectorsHow to Build a Filtering Component in Pure CSS
Our Responsive CSS Slideshow
Here’s the slideshow that we’re going to create during this tutorial:
1. Begin With the HTML Markup
For the purposes of this exercise, we’ll grab three images from Unsplash.
Then, we’ll create the corresponding radio buttons which we’ll group under the image
keyword:
<input type="radio" id="image1" name="image" checked> <input type="radio" id="image2" name="image"> <input type="radio" id="image3" name="image">
Next, we’ll put inside a container the .featured-wrapper
and .thumb-list
elements.
The .featured-wrapper
element will contain three lists:
- The first list will hold the slideshow images. Only one single image will appear at a time.
- The other two lists which are identical will be used for navigating between images/slides. Both lists will contain labels whose
for
values match theid
values of the aforementioned radio buttons.
Tip: In our example, we’ll associate a radio button with more than one label. It’s perfectly valid.
The .thumb-list
element will also include the slideshow images along with their descriptions. However, unlike the images of the .featured-list
element, these images will always be visible and used for the thumbnail navigation.
In short, our slideshow will provide users the ability to switch between slides via dots, arrows, and thumbnails. Niiice!
Final HTML Structure
By default, the first image should be visible/active. With that in mind, we’ll add the checked
attribute to the first radio button.
Putting it all together, here’s the structure of our container:
<div class="container"> <div class="featured-wrapper"> <ul class="featured-list"> <li> <figure> <img src="IMG_SRC" alt=""> </figure> </li> <!-- other two list items here --> </ul> <ul class="arrows"> <li> <label for="image1"></label> </li> <li> <label for="image2"></label> </li> <li> <label for="image3"></label> </li> </ul> <ul class="dots"> <li> <label for="image1"></label> </li> <li> <label for="image2"></label> </li> <li> <label for="image3"></label> </li> </ul> </div> <ul class="thumb-list"> <li> <label for="image1"> <img src="IMG_SRC" alt=""> <span class="outer"> <span class="inner">...</span> </span> </label> </li> <!-- other two list items here --> </ul> </div>
Note: Within each label inside the .thumb-list
, I don’t use the block-level figure
and figcaption
elements because the W3C Validator will throw an error. We’ll just stick to inline elements.
2. Define the Styles
In terms of styles we’ll first visually hide the radio buttons by moving them off-screen:
input[type="radio"] { position: absolute; bottom: 0; left: -9999px; }
Note: I added the bottom: 0
property value to prevent the browser from jumping to the top of the page, each time a label is clicked. Not the ideal approach, yet it seems to do the job. Alternatively, as a more stable solution, I could have set display: none
, yet this isn’t recommended due to keyboard accessibility restrictions. Specifically, that style will prevent arrow keys from changing the selected radio button.
As usual, our container will have a maximum width with horizontally centered content
.container { max-width: 700px; padding: 0 20px; margin: 0 auto; }
Large Images
By default, all featured images will be stacked on top of another. They will all be hidden, apart from the image associated with the checked radio button.
To stack the images, surprisingly enough we won’t use the common position
property. Normally, what you might expect is that we turn the images into absolutely positioned elements. But that method comes with one big disadvantage: absolute elements are removed from the normal document flow, so we would have to find a way to preserve images’ aspect ratio. For example, a rough, non-elegant solution might be to add a fixed height to the images’ container.
This is where new CSS additions like CSS Grid comes to the rescue, especially if you’re only interested in modern browsers. So first, we’ll make the list behave as a grid container, then we’ll position its items in the same cell by giving them grid-row: 1
and grid-column: 1
.
Here’s the corresponding CSS:
.featured-wrapper .featured-list { display: grid; } .featured-wrapper .featured-list li { grid-column: 1; grid-row: 1; opacity: 0; transition: opacity 0.25s; }
Dots
The dots navigation will be absolutely positioned and located at the bottom of the .featured-wrapper
element. Each of its labels will have the appearance of a circle, like this:
Here are the related styles:
/*CUSTOM VARIABLES HERE*/ .featured-wrapper { position: relative; } .featured-wrapper .dots { position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%); display: flex; } .featured-wrapper .dots li:not(:last-child) { margin-right: 8px; } .featured-wrapper .dots label { display: inline-block; width: 12px; height: 12px; border-radius: 50%; border: 1px solid var(--white); transition: background 0.25s; } .featured-wrapper .dots label:hover { background: currentColor; }
Arrows
The navigation arrows will be absolutely positioned inside the .featured-wrapper
element:
Keep in mind that only the arrows for the label associated with the checked radio button will appear. To create them, we’ll use the ::before
and ::after
pseudo-elements of the target label.
Here are the required styles:
/*CUSTOM VARIABLES HERE*/ .featured-wrapper .arrows label::before, .featured-wrapper .arrows label::after { position: absolute; top: 50%; transform: translateY(-50%); width: 40px; height: 40px; border-radius: 50%; color: var(--black); background-position: center; background-repeat: no-repeat; background-size: 24px 24px; background-color: var(--white); opacity: 0.5; transition: opacity 0.25s; } .featured-wrapper .arrows label::before { left: 10px; } .featured-wrapper .arrows label::after { right: 10px; }
Thumbnails
Each thumbnail will cover one-third of the parent width, like so:
To position the caption on top of its image, instead of using the traditional CSS positioning, we’ll take advantage of the CSS Grid trick which we learned previously.
We’ll turn the label into a grid element and force the children to cover its full dimensions. By default, only the caption associated with the checked radio button will appear. Also, its content will be horizontally and vertically centered thanks to CSS Grid again.
Here are the target styles:
/*CUSTOM VARIABLES HERE*/ .thumb-list { display: grid; grid-template-columns: repeat(3, 1fr); grid-column-gap: 20px; margin-top: 20px; } .thumb-list label { display: grid; } .thumb-list img, .thumb-list .outer { grid-column: 1; grid-row: 1; } .thumb-list .outer { display: grid; place-items: center; transition: background 0.25s; } .thumb-list .inner { font-size: 18px; opacity: 0; transform: translateY(20px); transition: all 0.25s; }
3. Checkbox Hack: Switch Between Slides
Let’s now have some fun! We’ll push the boundaries of CSS thanks to the checkbox hack and mimic JavaScript’s click
event.
So, each time a thumbnail image, a dot, or an arrow is clicked (i.e. becomes active), the following things will happen:
- The active slide will become visible.
- The active dot will receive a white background color.
- The caption of the active thumbnail image will appear.
- The previous and next arrows of the active slide will appear. These will link to its previous slide and its next slide, respectively.
Here are the styles that handle this functionality:
/*CUSTOM VARIABLES HERE*/ [id="image1"]:checked ~ .container .featured-list li:nth-child(1), [id="image2"]:checked ~ .container .featured-list li:nth-child(2), [id="image3"]:checked ~ .container .featured-list li:nth-child(3), [id^="image"]:checked ~ .container .arrows [for^="image"]:hover::before, [id^="image"]:checked ~ .container .arrows [for^="image"]:hover::after { opacity: 1; } [id="image1"]:checked ~ .container .arrows [for="image3"]::before, [id="image2"]:checked ~ .container .arrows [for="image1"]::before, [id="image3"]:checked ~ .container .arrows [for="image2"]::before { content: ’’; background-image: url(arrow-prev-slideshow.svg); } [id="image1"]:checked ~ .container .arrows [for="image2"]::after, [id="image2"]:checked ~ .container .arrows [for="image3"]::after, [id="image3"]:checked ~ .container .arrows [for="image1"]::after { content: ’’; background-image: url(arrow-next-slideshow.svg); } [id="image1"]:checked ~ .container .dots [for="image1"], [id="image2"]:checked ~ .container .dots [for="image2"], [id="image3"]:checked ~ .container .dots [for="image3"] { background: currentColor; } [id="image1"]:checked ~ .container [for="image1"] .outer, [id="image2"]:checked ~ .container [for="image2"] .outer, [id="image3"]:checked ~ .container [for="image3"] .outer { background: var(--overlay); } [id="image1"]:checked ~ .container [for="image1"] .inner, [id="image2"]:checked ~ .container [for="image2"] .inner, [id="image3"]:checked ~ .container [for="image3"] .inner { opacity: 1; transform: none; }
It might take you some time to understand how the aforementioned styles work. If this is the case, the browser inspector is your best friend!
Conclusion
That’s it, folks! In this tutorial, we managed to build a responsive CSS-only slideshow with thumbnails by taking advantage of the “CSS checkbox hack technique”. Hopefully, you enjoyed this exercise and you’ll incorporate it in an upcoming project.
Here’s a reminder of what we built:
As a last thought, I’d say that without a doubt, the CSS checkbox hack technique is a great way to enhance your CSS knowledge. On the other hand, in a real project, we should be aware of its limitations (accessibility, markup) and when it’s worth using ιt instead of JavaScript alternatives.
Have you ever built something interesting with the checkbox hack? Let us know!
Further Reading
Check out these tutorials to get some inspiration about powerful slideshows you can create by customizing popular jQuery plugins:
-
jQueryHow to Build an Attractive Responsive Image Gallery With slick.js
-
jQueryHow to Build a Full-Screen Responsive Carousel Slider With Owl.js
No comments:
Post a Comment