Learning to build a better slider part two
Today I’ve gotten through the process of converting the slides into flex objects, implementing a form of lazy loading for images, provided a no JavaScript fallback, and I’ve started working on adding buttons and their functionality. While typing out the scripts that Heydon provides, I noticed that he does not make use of semi-colons. This really threw me off for a bit, but it works just fine. I need to learn more about how essential they are. At the moment, I like using them because it helps me be certain that a line of JS has a finishing point. There’s always more to learn!
scroll or use your arrow keys to see more kittens
scroll for more cute kittens
use your left and right arrow keys to see more kittens
swipe to see more kittens
View the code:
HTML and JS
<div class="code-block">
<div class="gallery">
<div role="region" aria-label="gallery" tabindex="0" aria-describedby="instructions">
<ul>
<li>
<figure>
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' /%3E" data-src="http://placekitten.com/200/304" alt="placeholder image of a cute kitteh">
<noscript>
<img src="http://placekitten.com/230/304" alt="placeholder image of a cute kitteh">
</noscript>
<figcaption>Gene Hackman</figcaption>
</figure>
</li>
<li>
<figure>
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' /%3E" data-src="http://placekitten.com/220/304" alt="placeholder image of a cute kitteh">
<noscript>
<img src="http://placekitten.com/230/304" alt="placeholder image of a cute kitteh">
</noscript>
<figcaption>Frederick Von Lickshimself</figcaption>
</figure>
</li>
<li>
<figure>
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' /%3E" data-src="http://placekitten.com/230/304" alt="placeholder image of a cute kitteh">
<noscript>
<img src="http://placekitten.com/230/304" alt="placeholder image of a cute kitteh">
</noscript>
<figcaption>Purrecious</figcaption>
</figure>
</li>
<li>
<figure>
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' /%3E" data-src="http://placekitten.com/200/310" alt="placeholder image of a cute kitteh">
<noscript>
<img src="http://placekitten.com/200/310" alt="placeholder image of a cute kitteh">
</noscript>
<figcaption>Fuzzball</figcaption>
</figure>
</li>
</ul>
<!-- list of gallery pictures -->
</div>
<div class="instructions">
<p id="hover-and-focus">scroll or use your arrow keys to see more kittens</p>
<p id="hover">scroll for more cute kittens</p>
<p id="focus">use your left and right arrow keys to see more kittens</p>
<p id="touch">swipe to see more kittens</p>
</div>
<ul aria-label="gallery controls">
<li>
<button id="previous" aria-label="previous"><</button>
</li>
<li>
<button id="next" aria-label="next">></button>
</li>
</ul>
</div>
</div>
<script>
// ---------
// Variables
// ---------
/* Variables for lazy loading of images - Another helpful bit of JS from Heydon Pickering's book, Inclusive Components - https://inclusive-components.design/a-content-slider/ */
const slides = document.querySelectorAll('[aria-label="gallery"] li')
const observerSettings = {
root: document.querySelector('[aria-label="gallery"]')
}
/* end of variables for lazy loading of images in slider */
// ---------
// Functions
// ---------
// ---------
// Events
// ---------
// Listen for a touch and add a touch class to the body element. Script and overall concepts by Heydon Pickering, https://inclusive-components.design/a-content-slider/. Gosh he's good at this stuff.
window.addEventListener('touchstart', function
touched() {
document.body.classList.add('touch');
window.removeEventListener('touchstart', touched, false)
}, false)
// IntersectionObserver script to help with lazy loading of slider images
if ('IntersectoinObserver' in window) {
const callback = (slides, observer) => {
entries.forEach(entry => {
if(!entry.isIntersecting) {
return
}
let img = entry.target.querySelector('img')
img.setAttribute('src', img.dataset.src)
observer.unobserve(entry.target)
})
}
const observer = new IntersectionObserver(callback, observerSettings)
slides.forEach(t => observer.observe(t))
slides.forEach(entry => {
entry.target.classList.remove('visible')
if (!entry.isInteresting) {
return
}
let img = entry.target.querySelector('img')
if (img.dataset.src) {
img.setAttribute('src', img.dataset.src)
img.removeAttribute('data-src')
}
entry.target.classList.add('visible')
})
} else {
Array.prototype.forEach.call(slides, function (s) {
let img = s.querySelector('img')
img.setAttribute('src', img.getAttribute('data-src'))
})
}
</script>
CSS
.code-block {
max-width: 60em;
margin: 1rem auto;
}
[aria-label="gallery"] {
border: 2px solid;
padding: 1rem;
overflow-x: scroll;
}
[aria-label="gallery"]:focus, [aria-label="galler controls"]:focus {
outline: 4px solid dodgerblue;
outline-offset: -6px;
}
[aria-label="gallery controls"] button:focus {
outline-offset: -4px;
}
[aria-label="gallery"] ul {
display: flex;
padding-left: 0;
margin: 0;
}
[aria-label="gallery"] li {
list-style-type: none;
flex: 0 0 100%;
padding: 2rem;
text-align: center;
}
[aria-label="gallery"] figure {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 50vh;
}
[aria-label="gallery"] figcaption {
padding: 0.5rem;
font-style: italic;
text-align: center;
}
[aria-label="gallery"] img {
max-width: 100%;
max-height: calc(100%-2rem);
margin-top: 2rem;
}
.instructions p {
background-color: #030303;
color: #fff;
text-align: center;
padding: 1rem;
margin-top: 0;
}
#focus, #hover, #hover-and-focus, #touch {
display: none;
}
[aria-label="gallery"]:focus + .instructions #focus,
[aria-label="gallery"]:hover + .instructions #hover {
display: block;
}
[aria-label="gallery"]:hover + .instructions #hover + #focus {
display: none;
}
[aria-label="gallery"]:hover:focus + .instructions #hover-and-focus {
display: block;
}
[aria-label="gallery"]:hover:focus + .instructions #hover-and-focus ~ * {
display: none;
}
.touch .instructions p {
display: none !important;
}
.touch .instructions #touch {
display: block !important;
}
.gallery {
position: relative;
}
[aria-label="gallery controls"] li {
list-style: none;
}
[aria-label="gallery controls"] button {
position: absolute;
top: 0;
background: #010101;
color: #fff;
border: 2px solid #010101;
border-radius: 0;
width: 3rem;
height: calc(60vh + 4px);
letter-spacing: 1px;
font-weight: bold;
cursor: pointer;
}
#previous {
left: 0;
}
#next {
right: 0;
}