I'm working on a site for myself, and I'm using a custom horizontal scroller done with Mootools that I got from another site (and got their permission to use). While I've managed to get the scroller to function the way I want to, there are two issues I'm looking to fixed and don't have the know-how myself to figure out.
I've set up a simple demo page here.
You can scroll with your mousewheel/trackpad up and down or left and right, you can grab the scroller and drag it, and you can click anywhere along the line to jump directly. So all the functionality is okay. My issues are:
If you scroll to the middle (or anywhere except the start position), then resize your browser window, the scroller handle will jump back to the start/left even though the contents stays put. If you then start scrolling again the contents will jump back to align with the scroller handle's position. Ideally the handle would stay put when the window is resized, but I can't figure out how to do this on my own.
At the end/right of the page I'd like to have a back button that smoothly scrolls you back to the start/"top". The best I've managed is what you see there now, where the contents scrolls back smoothly, while the scroller simply jumps back to it's first position. While I could work around that by simply have it jump straight back to the start, it would certainly look much nicer if the scroller would smoothly scroll its way back like the contents does.
Any help with this would be greatly appreciated!
Your first issue is occurring because positionIt() is being called every time the window resizes. Looking into that function, you can see that the bottomSlider is being initialized every time. I would break positionIt() into a initializing function and positioning function, and ensure that only the positioning function is called when the window resizes.
The second issue could probably be fixed by creating a separate step() function for the bottomSlider and calling that within onChange, rather than using an inline anonymous function. You could then create a timer or tween that calls step() to move the scrollbar back to its original position (and subsequently move the viewport in accordance with it.)
Hopefully that makes some sense!
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?
I am attempting to recreate something similar to the pencil effect on:
http://www.fiftythree.com/pencil
Not exactly but similar. About halfway down the current page, the pencil sort of pulls apart with a description on each part as the user scrolls down the window.
I am attempting to use the jquery .animate function to pull multiple div's apart in the same fashion.
IE: (image1) behind that (image2) behind that (image3).
Sort of a vertical accordion effect.
I am basing everything off scrollTop variable. And at certain points it will move the div's in a different fashion. All the events are contained in this loop.
$(window).scroll(function (event) {
var scroll = $(window).scrollTop();
// doing stuff
}
My issue is that the scrolling function is not executing fast enough. If I scroll slowly it works, if I scroll quickly it sort of tries to play catch up and is either off location or too jerky.
Do you all think this is a decent way to achieve this effect, and if so - any suggestions on setting the refresh time to check for where the user has scrolled on the page?
I'm having a little trouble getting my head around a Javascript animated scroll issue.
I'm using the SuperScrollorama Jquery plugin which is built on-top of the Greensock JS tweening library.
The fundamental effect I'm after is to "pin" a section down, then use vertical scrolling to expand some content, then "unpin" the section once the content is fully expanded, so the user can scroll on - i.e. http://blueribbondesign.com.au/example/
But when I try to apply this same effect to multiple sections one after the other, everything gets all broken: the "unpinned" content below the pinned element is pushed off screen and it seems to miscalculate the height of the element when it performs the animation in reverse (i.e. scrolling back up the page). - i.e. http://blueribbondesign.com.au/example2/
I've been endlessly fiddling with the "position:fixed" and "pin-spacer" div, and tried attaching the Superscrollorama plugin to various containing elements, but still cannot work out how to get it to work.
Any help from the brilliant crowd-sourced minds of the web would be much appreciated,
Cheers,
TN.
I've been working with this issue myself. What happens is there's a blank div spacer put above the section being pinned with a height that you've defined in the pin() function. Secondly, the pinned element gets a position:fixed assigned to it. Both of these things allow the scroll bar to continue down the page while the element stays affixed. In turn, whatever you had below that section gets bumped down because of that spacer div's height.
If your pinned element is centered horizontally, first give it a left:50%, margin-left:-{width/2}px to fix it from pushing to the left edge.
Next, you'll have to detect the pin/unpin events (which are offered by the plugin as parameters additional to "anim"), and change the section underneath to also toggle a fixed/relative position. When you change that underlying section to be at a fixed position, be sure to set its "top" property to whatever the pinned element's height is. Once the pinned element becomes unpinned, change it back to relative positioning. Does that make any sense?
It seems that different techniques will call for different fixes, but those things are what I'd pay attention to... fixed positioning, and then using the pin/unpin events for adjustment.
How can I keep the browser from scrolling, or how can I make the browser continually scroll to a fixed posistion?
I am working on a library for the Nintendo 3DS browser. I made the page fit perfectly within the browser, but the up arrow makes it scroll because the bottom screen is the only window recognized as the visible area.
I want to make it so the div #bottomScreen is the only thing in the bottom screen, and disabling scrolling is the only thing I can think that would work.
I have figured out how to scroll it to a said position via
document.body.scrollTop = 220;
How can I make it continually go to this position?
Making a repeating timer with setTimeout and putting the above code in it won't work. I believe it is because this only works prior to the page loading.
Any advice on how to enforce it?
It should work even after page load. Here's the code, although i'm not sure what the intent of the code is, might be annoying to the user.
setInterval( function(){ document.body.scrollTop = 200 }, 500 ); // set your time
A more elegant solution would be to disable scrolling when that method is called (to scroll to the position of 220 from top or whatever), and re-enable it whenever the appropriate action has been taken by the user etc... jQuery example:
$('body').css('overflow', 'hidden'); // removes scrollbars entirely
$('body').css('overflow', 'auto'); // re-enable scrolling
Otherwise use setInterval() with a very short interval like 10ms to repeatedly fire your scroll function. If you are going to do this it would be wise to add some logic to see if the window is already scrolled to approximately the right position (allow for +/- 10px or something) so it isn't extremely jarring for the user.
The best way I've seen on some sites (like twitter I think or facebook when an image pops up) which is to set the overflow property to hidden on the body element. This prevents any scrolling so all you need to worry about is the position of content when you do that.
I guess you would need to wrap the content in some sort of container element and when you change the overflow of the body element you also set the y-coordinate of the container to reveal the specific area of the page being looked at.
This is by far the best thing I have seen to achieve that effect because it doesn't require timers etc.
You could add a event listener for the scroll event, and then set the position then.
I'm building a web app that has a grid of many small scrollable divs (actually, Ace editors), and this grid has enough elements that it is larger than the window. When a user begins scrolling over empty space, I want them to be scrolling the window itself; when a user begins scrolling inside a grid element, I want them to scroll the div contents there. The thing is, if a user begins scrolling over empty space, and then scrolls such that their mouse goes over a grid element, that scrollable div captures all the scrolling events, interrupting the user's flow over the grid and "trapping" them inside the grid element.
I can't manually capture onmousewheel events, since AFAIK there's no way to capture horizontal mouse wheel movement separately from vertical, and I want users on Mac OS X to be able to scroll in all directions. I've thought about using JS to add an invisible div with a very high z-index on the first onscroll event, and removing it as soon as onscroll events aren't triggered for a certain period of time. Haven't yet coded this up, but I'm wondering if there's a better solution, or if there are any potential pitfalls that I haven't thought of. Any help or advice would be great! Thanks!
I think a solution for this would be incredibly difficult due to browser support, and the actual solution, which would probably be something like calculating the scroll, backtracking the div, and applying the scroll to the page.
You could do something like this:
$('div').scroll(function(e){
// figure out how much it has scrolled
window.scrollBy(0,howmuch);
});
I don't recommend this solution in the slightest though, I think the better option would be to set the divs to overflow:hidden; and pick up a solid scroll plugin, and use that to customize the scroll behavior on the divs.