Add/remove elements to either side of DOM without affecting scroll position?
Asked Answered
T

1

9

Is there any way to position elements or some clever hack in such a way to allow for adding or removing elements from either the top or bottom of the DOM without affecting the scroll?

I've tried using Jquery to measure the length of the added/removed elements and then as soon as I add/remove them, I scroll the current container the offset amount. This successfully gets me to stay at the current position, however, I've noticed that more often than not there is a visible "jump" that occurs in the space of time it takes to first affect the content and then run the follow up scroll fix.

I imagine the best way to handle something like this would be to remove the concept of "scrolling" and somehow implement it manually, but I'm not sure how to go about doing so. Any ideas are greatly appreciated!

Trustless answered 22/1, 2018 at 17:37 Comment(9)
Well, the scroll gets effected because the height of the parent is changed due to the removal or the addition of it's child elements. Did you try manually adding/removing to the parent height the same height which is effected by the removed child ?Bismuthous
@AlonAdler - yes, as I stated in the post. I did try adding back the changed height, but the problem is there is still a moment where the screen flickers to the changed position before the height is added. It's almost immediate, but that flicker is extremely annoying and breaks the flow.Trustless
I have a couple of WAGs... one is to change the opacity of the removed elements to zero, but not remove them. The other is to use .appendTo() to move the elements into a div that is somehow not visible. Neither one seems a magic bullet to me (I see the obvious downsides to both), but throwing them out there FWIW in case something triggers a workable idea.Sapsucker
Thanks @gibberish - I'll play around with those and try, but the ultimate goal is to actually remove them to prevent so much content on the screen causing performance drops. (The content can sometimes be pretty large.)Trustless
From UX point of view, if those changes don't occur too often, I would make a "loading" floating div in front of everything - to show the user something is happening but without the "jumps". Even if the change actual time is in milliseconds - Preventing the jumps on the screen by making a longer 2-3 seconds "loading" or "processing" div can be a quick and simple win - and even produce a more correct and standard UX.Bismuthous
@Trustless Did you get a working solution? Could you write an answer please? Thanks!Tidal
@Tidal - I have not yet. 🙁I needed the solution again just the other day and still get the jump issue.Trustless
Have you tried it in reverse order, so first scroll to correct for the element about to be added/removed, and only then actually add/remove it? Because the DOM needs to be updated after you add/remove something, it needs more time, which could explain the 'visible jump' during that lag time. Maybe if you switch your actions around it's not noticeable... Then again, may not make a single bit of difference, since you still have to wait for the DOM to update. I didn't have a change to test it since you didn't post any code, but I'd say it's worth a try.Neoplasticism
I'm dealing with this same problem and considering replacing the content I'm removing with an equally sized placeholder.Niobous
G
1

This should already work out-of-the-box based on the scroll anchoring spec currently implemented by Chrome and Firefox (link).

Directly from the spec introduction:

Today, users of the web are often distracted by content moving around due to changes that occur outside the viewport. Examples include script inserting an iframe containing an ad, or non-sized images loading on a slow network.

[...]

Scroll anchoring attempts to keep the user’s view of the document stable across layout changes. It works by selecting a DOM node (the anchor node) whose movement is used to determine adjustments to the scroll position.

It may not be working for you because the anchor node selected is not correct or you are using an unsupported browser (caniuse data). The exact process for the anchor node is described here. You can tweak the anchor selection algorithm by setting the CSS property overflow-anchor: none on the nodes you want not to be the scroll anchor.

Working example for scroll anchoring: Just scroll within 5s and scroll up when the text turns red. You will see a new <p> node added at the top.

const root = document.querySelector('#root');
const ol = document.querySelector('#list');

ol.las

setTimeout(() => {
  const para = document.createElement('p');
  para.innerText = 'A\nB\nC';
  root.insertBefore(para, ol);  
  root.classList.add("red");
}, 3000);
.red {
  color: red;
}
<div id="root">
<ol id="list">
    <li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li><li>Hello</li><li>World!</li><li>Bye</li><li>World!</li>
</ol>
</div>

Can you share your code to see why it is not working?

Gerek answered 17/5, 2022 at 22:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.