Learning to build a better slider part two


by Jeremy Caudle
code

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!

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;
            }