Lazy loading conflicting with ScrollTo anchor to ID scroll - Stops halfway through the page
Asked Answered
C

3

6

I have a scrollTo function on my page where when you click on a specific button you scroll to a section with a unique ID.

The problem is I am using lazy loading for the images on my website so, this will cause the ScrollTo to stop halfway through the page because of the images which are lazy-loaded.

After all, images are loaded and I click again on the button it works just fine.

My lazy load code:

(() => {
    const runLazy = () => {
        let images = [...document.querySelectorAll('[data-lazy]')];

        const settings = {
            rootMargin: '0px',
            threshold: 0.02
        };

        let observer = new IntersectionObserver((imageEntites) => {
            imageEntites.forEach((image) => {
                if (image.isIntersecting) {
                    observer.unobserve(image.target);
                    image.target.src = image.target.dataset.lazy;
                    image.target.onload = () =>
                        image.target.classList.add('loaded');
                }
            });
        }, settings);

        images.forEach((image) => observer.observe(image));
    };

    runLazy();

})();

My scroll to code:

(() => {
    document.querySelectorAll('a[href^="#"]').forEach((elem) => {
        elem.addEventListener('click', (e) => {
            e.preventDefault();
            let block = document.querySelector(elem.getAttribute('href')),
                offset = elem.dataset.offset
                    ? parseInt(elem.dataset.offset)
                    : 0,
                bodyOffset = document.body.getBoundingClientRect().top;
            window.scrollTo({
                top: block.getBoundingClientRect().top - bodyOffset + offset,
                behavior: 'smooth'
            });
        });
    });
})();

Is there a way to fix this?

Counterfeit answered 21/7, 2021 at 9:54 Comment(1)
Do the images loading in change the height of the page? If you can prefill the space that the images will take up with a placeholder of the same size, then the images loading should have no effect on the scroll.Riser
P
3

This seems to be caused by the image size change event during lazy loading.

So you could just set fixed height and width to the lazy load images, to skip this issue.

Edit:

Since fixed image size is not suitable, you can fix this with location.href = '#your-image-tag', plus window.scrollBy in image.onload event.

key code:

(() => {
  document.querySelectorAll('a[href^="#"]').forEach((elem) => {
      elem.addEventListener('click', (e) => {
          e.preventDefault();
          location.href = elem.getAttribute('href')
      });
  });
})()
image.target.onload = () => {
  image.target.classList.add("loaded");

  // TODO: check current image below or upper the target image
  window.scrollBy(0, image.target.clientHeight)
  // or window.scrollBy(0, 0 - image.target.clientHeight)
}

live demo: https://codesandbox.io/s/focused-field-2q3py?file=/src/index.js

Proviso answered 21/7, 2021 at 10:6 Comment(5)
I am setting images 100% H and W. Setting it to fixed is not the thing I want to. So, there is no other way to do right?Counterfeit
@Counterfeit I think 100% is not fixed size, 100px is. It's an interesting question, I will try in a codesandbox and update this answer later.Proviso
The reason why I am not setting it to fixed width and height is that I have images on different pages all over the place with the same code. When I set it to a fixed w x h layout would look funky. Never knew that It will conflictCounterfeit
also forgot to mention that if you face dynamic images like from WordPress clients can upload vertical, horizontal larger, smaller images.. and setting fixes height will kill the website layout.Counterfeit
@Counterfeit updated my answer with a new solutionProviso
P
0

I tried any solutions, but this is better for me:

element.scrollIntoView({
     block: 'start',
     behavior: "smooth"
});
Proser answered 16/3, 2022 at 4:6 Comment(1)
While this code may solve the question, including an explanation of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please edit your answer to add explanations and give an indication of what limitations and assumptions apply.Algin
M
0

check this out:

$("a").click(function(e) {
        e.preventDefault();
    var trigger = $(this).attr("href");
    $('html,body').animate({scrollTop: $(trigger).offset().top},300);
    setTimeout(function(){$('html,body').animate({scrollTop: $(trigger).offset().top},300);},300);
});
section{width:100%;height:600px}
#section1{background-color:red}
#section2{background-color:navy}
#section3{background-color:blue}
#section4{background-color:yellow}
#section5{background-color:green}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<a href="#section1">section1</a>
<a href="#section2">section2</a>
<a href="#section3">section3</a>
<a href="#section4">section4</a>
<a href="#section5">section5</a>
<section id="section1"></section>
<section id="section2"></section>
<section id="section3"></section>
<section id="section4"></section>
<section id="section5"></section>

After the first scroll, if the page fails to scroll properly due to lazy loading, the command with a delay of 300 milliseconds will solve this problem.

Misbecome answered 15/4 at 10:43 Comment(2)
OP is not using jQuery and your proposed solution appears to be. If not using the same method as the OP I would suggest speaking to any add-ons being used. Some developers, myself included, wish to stick to vanilla JS if possible. Something like "If you are willing to use jQuery, here is an option". Also, it may not help the OP but someone who does use jQuery will be able to scan, see you used it, and take the suggestion.Leishmaniasis
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Tolerable

© 2022 - 2024 — McMap. All rights reserved.