I have a bunch of divs that i am removing from the document using javascript. When this is done, the length of the page is often shortened significantly, and if the user had scrolled down the page, it gets abruptly recentered because the entire page now fits on the window.
This causes the user to no longer have their mouse over the same buttons on the page. I'd like to prevent this auto scrolling, but it seems like it may be difficult. I admit that it doesn't make much sense to allow a page to be scrolled off of its contents. Seems like the best I could do is to leave dummy divs as placeholders. Once the user scrolls back up, then clean them up to shrink the page.
Are there other, cleaner solutions?
You could just set the divs to be removed to visibility: hidden (add a class or similar) so they still take up room in the document. At a suitable time you actually remove them and allow the document to reflow.
Related
This will be a long post, sorry for that, I'd just like to explain what I'm trying to do and why, and what I've tried so far.
I was asked to put a banner (legal disclaimer) on top of a page that stays on top no matter how the page is scrolled. After going down the rabbit hole of trying to make a <div> with position: sticky work, I gave up and went with position: fixed.
(Long story short, there's too much going on the page in terms of css styles that I don't have control over/don't have the resources to investigate and fix, that's causing the sticky to not work and the <div> to scroll with the rest of the page.)
position: fixed made the <div> stick to the top of the page, but it caused another problem: The div now overlaps the top of the scrollable page content. In other words, even when scrolled all the way to the top, a bit of the content is covered by the div. Important content. The top menu bar.
To get around this I put another empty div on the top of the page just to take up space. I effectively made the scrollable content of the page a bit taller. This works fine, as long as the user doesn't resize the window. If they do that, the disclaimer div changes height, but the padding div doesn't. So I turned to JavaScript:
$(window).on('resize', function () {
$("#disclaimer-padding").height($("#disclaimer-container").height());
});
I realize I'm well into the workaround/clumsy hack territory, but what was I supposed to do? The damn sticky thing wouldn't work. Anyway, this works, except for one last usecase:
If the user loads the page while not in fullscreen, or they have a smaller screen, or a device in portrait mode, the padding div height won't match the height of the disclaimer when the page loads.
I naturally tried putting the same code in $(window).on('load') or $(document).on('ready'). But the problem is that the content of the disclaimer, like many other elements on the page, is loaded by AngularJS (which grabs it from backend, which grabs it from the database or server-side cache) and both window.load and document.ready fire long before Angular is done loading and the final height of the div is known.
My next thought was "I'll listen for the context of the div to change, and trigger the resize then". So I used a MutationObserver.
const targetNode = document.getElementById('some-id');
const config = { attributes: true, childList: true, subtree: true };
let observer = new MutationObserver(callback);
function callback() {
$("#disclaimer-padding").height($("#disclaimer-container").height());
}
observer.observe(targetNode , config);
I tried hooking this up in window.load and in document.ready. It didn't work, which really surprised me, because when I tried it in a minimal working test page, it worked like a charm. But alas, in my project, the callback function just never got called. I have no idea why.
In the end I implemented a truly ugly solution (which I found somewhere here on StackOverflow). In window.load I call a function that periodically checks the contents of my diclaimer div. If the content has changed (until it's loaded it says something like #Application.DislaimerContent) then it will set the height, otherwise it will schedule itself to run again in 200 miliseconds using setTimeout().
I don't like this solution, but I was running out of time and this is the only thing that worked. But I feel like if my supervisor ever sees this, he'll give me an earful and make me fix it.
So the question is, how do I fix it? How do I make the code register when the div has loaded, and resize the other div accordingly?
Here is what I am trying to do: When the user is clicking a button, a transparent overlay is opening. The background shouldn't be scrollable but stay at the scroll position. So what I am doing at the moment is that once the button is clicked, I safe the current scroll position via window.scrollY, then add overflow: hidden to both the html and body tag (which unfortunately scrolls the page to the very top), then proceed to scroll to the saved position inside the main div of the website. In most browsers these steps aren't noticeable so it seems like everything just stays at the same position. In Safari however, you can see that for a few ms the background scrolls to the very top and then back again.
So what I would like to know is how to execute multiple methods at once before the DOM updates. Or maybe you can think of another way of doing this?
Thank you!
I am trying to link to a page at an anchor point, i.e.:
About
<div id="content">…</div>
The normal browser behavior is to render the page, then jump to the anchor/ID. Is there a way to position the page at the anchor position before the page renders?
I've tried using
$(document).scrollTop( $('#content').offset().top );
thinking it might move to position quick enough to prevent a flash of the full page load but it doesn't work until DOM ready, so it's not quick enough.
I can cobble together a work-around by selectively hiding elements, moving to position, then showing them, but I'm wondering if there's an approach I'm not aware of.
I don't think there is any other direct way of doing it. You can only guarantee faster link to a particular div making the div available as soon as possible in the DOM.
You can do this by loading the required div to be linked statically while loading the contents of other div dynamically. Again while doing this you have to make sure that the page is always scrolled to this div, by executing the code
$(document).scrollTop( $('#content').offset().top );
periodically, as when the other contents of the page are getting loaded dynamically page size may tend to increase and we would want to keep the scroll position always on the content div.
Ok, I've seen a trend where a fixed/absolute element will automatically hide itself from the view if the browser is less than a certain size, recently I've come across a client who wishes to have such a thing on a couple elements on there page. But I'm not sure how to approach that. Whats the best way to handle this type of action like what would I need to bind to, or what event do I have to be mindful of to say if the window is less than x wide or z tall hide this element and that element. The hiding part I can handle through a nice animation of sorts but just don't know which event to be mindful of.
how about http://api.jquery.com/resize/
Here is my current situation:
I have a web page containing a couple scrollable divs. Each of those divs contains a number of objects. I am using YUI to display popup menus of actions that can be performed on each object. Each object has its own menu associated with it that is constructed and displayed dynamically. The popup menus can be large and can overlap the bounds of the scrollable div.
From what I believe are issues with focus (the menus must be accessible), when I hover the mouse over an action that lies on top of an edge of the scrollable div, the div automatically scrolls, moving the content but leaving the menu stationary. Trying to move the menu dynamically when this happens is not something I want to do as I believe it would provide a poor user experience.
So I need to prevent this focused menu from scrolling the div. My idea for providing the best user interface is to prevent these inner divs from scrolling when a menu is open. This leaves the menu positioned in the optimal location to show the user which item is being acted upon. If the user wants to scroll the box, they can click to close the menu and then scroll normally.
How can I do this? I need a solution that works across the major browsers.
My first thought was to listen to the onscroll event for that particular element. Unfortunately, there does not seem to be an easy way from there to just prevent the scrolling from happening. For one, my JavaScript event code appears to execute after the actual scrolling has occurred.
Then, I thought that since my code is being run after the object has scrolled, I could just reset obj.scrollTop and obj.scrollLeft. Sure enough, this appears to work, though I am worried that on slow browsers the user will see the content inside the div "jump around". Also, it would be really nice if the amount the element scrolls is part of the event object. Is it stuck in there somewhere? I'm looking for an alternative to having to store the scrollTop and scrollLeft variables for this element and then using them while the scrolling is temporarily disabled.
What is the best way to solve this entire problem?
I agree with Anthony regarding the presentation of the functionality you're trying to disallow. If you're going to disable scrolling, then you should make that part of the page visually disabled or removed.
To that end, you can position a semi-transparent div on top of the scrollable div in question, which would capture the mouse events and visually show that the scrollable div is inactive for now. It would be hard to make cross-browser compatible and wouldn't be perfect, but then again very few client-side tricks like this are.
The simple answer is no you can't do this. Its doubly no if you want a cross-browser solution.
Providing the user with the clear affordance that something can be scrolled then denying them that is just plain poor UI design.
Ok so after your edit it turns out you are not actually trying to prevent the user from scrolling.
The main answer remains true though. It sounds as though the focus is going to rectangle (probably an anchor?) that is not fully in view and causes a scroll. Is there a reason this rectangle must get the focus? For accessibility?
What if you didn't have overflow: scroll and instead you used overflow: hidden and provided scroll up/down buttons that allowed the user to scroll when necessary? These buttons could of course be disabled easily.
Though it may not be the answer you are looking for, if you are to set the display value of the div to 'none' while the page loads (from the server) and then have an event wired to the page load (either pageLoad in ajax.net or attach it to the onload event via javascript) that will make the div display set to 'block' .. that would ensure that slower browsers wouldn't see the div 'jumping around' (could even put a 'loading' image in the div to show users it's doing something and not just invisible)
sorry i couldn't provide a more complex/fluent solution.
I found a way to work around this issue. By removing the menu element from the scrollable div and then appending it directly to document.body, the browsers all stop trying to scroll the div to reveal the focused element (even though the element is already completely visible).
Thanks to all for your time and your answers!