0

I'm developing a website using gatsby.js and it involves a slide-in animation as you scroll down. I wrote code that worked perfectly until I opened dev tools and tried it using the device toolbar. here's a reproduction demo as well as a webpage to make it easier https://getboundingclientrect-is-broken.netlify.app


        <div class="0 space"></div>

        <p class="1 slideFR"></p>
        <div id="boy" class="2 slideFL"></div>

        <p class="3 slideFR"></p>
        <div class="4 slideFL"></div>

        <div class="flx space"></div>

            .slideFR {
                width: 100px;
                height: 100px;
                background-color: #957b26;
                position: relative;
                left: 450px;

                transform: translateX(1000px);
            }
            .slideFL {
                width: 100px;
                height: 100px;
                background-color: #26958f;
                position: relative;
                left: 300px;

                transform: translateX(-1000px);
            }
            .inSight {
                transition: all 0.5s;
                transform: translateX(0);
            }
            .space {
                width: 100px;
                height: 1500px;
                background-color: aquamarine;
            }
let elemsFL = document.getElementsByClassName("slideFL");
        var leftiesLoaded = Array.from( { length: elemsFL.length }, (_, i) => false ); // creates array length of elemsFL full of <false>

        let elemsFR = document.getElementsByClassName("slideFR");
        var rightersLoaded = Array.from( { length: elemsFR.length }, (_, i) => false ); // creates array length of elemsFR full of <false>

        document.addEventListener("scroll", function (event) {
            let windowHeight = window.outerHeight;
            console.log( "%c/* ----------- scroll ---------- */", "color: purple; font-weight: bold" );

            checkIfInSight(elemsFL, leftiesLoaded, windowHeight);
            checkIfInSight(elemsFR, rightersLoaded, windowHeight);
        });
        /* -------------------------------- touchmove ------------------------------- */
        document.addEventListener("touchmove", function (event) {
            let windowHeight = window.outerHeight;
            console.log( "%c/* ---------- touchmove --------- */", "color: red; font-weight: bold" );
            checkIfInSight(elemsFL, leftiesLoaded, windowHeight);
            checkIfInSight(elemsFR, rightersLoaded, windowHeight);
        });

        function checkIfInSight(elemArray, boolArray, windowHeight) {
            for (let counter = 0; counter < elemArray.length; counter++) {
                const elem = elemArray[counter];
                let elemRect = elem.getBoundingClientRect();
                let elemPosTop = elemRect.top;
                let elemPosBottom = elemPosTop + elem.scrollHeight;

                if (elemPosTop <= windowHeight && elemPosBottom >= 0) {
                    if (!boolArray[counter]) {
                        console.log( "%c In Sight", "color: green", elem.classList[0] );
                        boolArray[counter] = true;
                        elem.classList.add("inSight");
                    } else {
                        console.log( "%c In Sight And Loaded", "color: yellow", elem.classList[0] );
                    }
                } else {
                    console.log( elem.classList[0], "\tOut Of Sight", elemPosTop, "<=", windowHeight, "&&", elemPosBottom, ">=0\t\t\t", elem.offsetTop );
                    boolArray[counter] = false;
                    elem.classList.remove("inSight");
                }
            }
        }

Edit: As I'm troubleshooting this I replaced elem.offsetTop with window.scrollY which indeed made me realize that for some reason the it is not interpreting the scroll action as actually scrolling for quite a while. I still don't know what I'm doing wrong or what the issue is

Arfizato
  • 1
  • 2
  • 2
    The code is really anti react pattern if you use gaysby, for react you can use intersection-observer or react-measure. But you never use document.appendEventlistner the way you did that, instead you use useState useEffect combination and for scroll you should throttle denounce also – antokhio Sep 10 '22 at 19:35
  • Look into the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). This API is specifically developed to check if elements are within the viewport. – Emiel Zuurbier Sep 10 '22 at 19:42
  • @antokhio the code here is for the demo not for the react app I replicated the error onto vanilla js and HTML. is this what you mean by "throttle denounce"? https://stackoverflow.com/a/25991510/18027442 – Arfizato Sep 10 '22 at 19:45
  • @Arfizato, hi, so event can fire multiple times per second (like 60 or 120 or even more), and you don’t really want to have something that updates your DOM 120 times per second, and if you subscribe to scroll event without throttle it would giving you a lot of lags… https://www.google.com/amp/s/www.geeksforgeeks.org/lodash-_-throttle-method/amp/ that what throttle does for you – antokhio Sep 10 '22 at 21:36
  • thank you @antokhio i will for sure start using throttle with event listeners – Arfizato Sep 11 '22 at 13:50

1 Answers1

0

thanks to EmielZuurbier's comment I found the solution IntersectionObserver API was the way to go. I even produced cleaner more optimized code.

HTML


        <div class="0 space"></div>

        <p class="1 slideFR toSlide"></p>
        <div id="boy" class="2 slideFL toSlide"></div>

        <p class="3 slideFR toSlide"></p>
        <div class="4 slideFL toSlide"></div>

        <div class=" space"></div>

JS

const slideDivs = document.querySelectorAll(".toSlide");
        const options={
            root: null,
            rootMargin: "0px 2000px",
        };

        const observer= new IntersectionObserver(function(entries, observer){
            entries.forEach(entry =>{
                console.log(entry.target.classList[0],entry.isIntersecting, entry.intersectionRect);
                if (entry.isIntersecting ){
                    entry.target.classList.add("inSight");
                }else {
                    entry.target.classList.remove("inSight");
                }
            });
        },options);
        slideDivs.forEach(slideDiv => {
            observer.observe(slideDiv);
        });

CSS


            .slideFR {
                width: 100px;
                height: 100px;
                background-color: #957b26;
                position: relative;
                left: 200px;

                transform: translateX(1000px);
            }
            .slideFL {
                width: 100px;
                height: 100px;
                background-color: #26958f;
                position: relative;
                left: 150px;

                /* visibility: hidden; */
                transform: translateX(-1000px);
            }
            .inSight {
                transition: all 0.5s;
                transform: translateX(0);
            }
            .space {
                width: 100px;
                height: 1500px;
                background-color: aquamarine;
            }
Arfizato
  • 1
  • 2