Scroll content of fixed element along with parent - javascript

Question title might be bit confusing, but please have a look at this fiddle for more info.
I have a container with scrollbar and one element fixed left to it. When I am scrolling I would like to make fixed element content also scrolling. Here is the code
$('.parent').on('scroll', function(){
var top = $(this).scrollTop(), _top = $('.right').offset().top;
$('.left').animate({
scrollTop : top - _top
},0)
});
Please refer to fiddle for demo.
This is working but there is some non uniform scrolling and I am unable to fix it.

I think the extra subtraction of _top is causing the uniformity issue, since it is recalculating the offset top each time, and continually subtracting it.
$('.parent').on('scroll', function(){
var top = $(this).scrollTop(), _top = $('.right').offset().top;
$('.left').animate({
scrollTop : top
},0)
});
Appears to let the scrolling be more uniform, minus some padding issues.

Related

Page noscroll keeping scrollTop position in sticky footer layout

I can't handle such a mind-breaker:
It's common approach to hide page scroll when a tall popup shows. But when you set overflow: hidden to html and body elements, the content automatically returns to it's top (scrollTop: 0). It's no problem to keep scrollTop position, and reset it on popup's disappearing. But if you use transparent mask, user will see unnecessary jump from current scroll position to the top. How to escape this?
In the current Chrome and Firefox, I can set overflow: hidden only to html element to reach what I want, but it's not working on mobile devices.
Maybe someone can propose a good cross-browser solution.
I don't think this should be happening. I would look at the popup code to see if it's the culprit sending the page to the top and using subpar css to position the popup element.
In any case, here's code that ought to counter the behavior you're encountering. Since I cannot reproduce the problem, I cannot test my proposed fix. I think you'll find though that your pop up will be scrolled away out of view.
function keepScroll(){
var x = $('body').scrollLeft() + $(document.documentElement).scrollLeft();
var y = $('body').scrollTop() + $(document.documentElement).scrollTop();
$('html').css({
'overflow':'hidden'
});
$('body').css({
'overflow':'hidden'
});
$(window).scrollTop(y).scrollLeft(x);
}
The sicky footer layout has html and body height equal to '100%'. And when you set overflow:hidden it crops all the content and returns it to the top position.
To avoid this, you should set html and body height to 'auto' if scroll exists (you should check it to keep sticky footer behavior)
function keepScroll(){
var scrollHeight = $('body')[0].scrollHeight > $('html')[0].scrollHeight ? $('body')[0].scrollHeight : $('html')[0].scrollHeight,
keepCSS = scrollHeight > $(window).height() ? {'overflow':'hidden','height':'auto'} : {'overflow':'hidden'};
$('html, body').css(keepCSS);
}
See the fiddle, for live demo
Edit 1
This solution is still not working on mobile (overflow: hidden doesn't disable scrolling on iPad, the position 'fixed' fix for body throw the content to the top), so the issue is open
Edit 2
Find a fix, for mobiles. Maybe it isn't so clean, but works.
var scrollKeeper = (function() {
var scrollHeight = $('body')[0].scrollHeight > $('html')[0].scrollHeight ? $('body')[0].scrollHeight : $('html')[0].scrollHeight,
keepCSS = scrollHeight > $(window).height() ? {'overflow':'hidden','height':'auto'} : {'overflow':'hidden'},
scrollTop = 0;
return {
keep : function() {
scrollTop = $(window).scrollTop();
$('body').css({'position': 'fixed', 'width':'100%', 'top': -scrollTop + 'px'});
$('html, body').css(keepCSS);
},
release : function() {
$('html, body').removeAttr('style').scrollTop(scrollTop);
}
}
})();
Tip: Of course in the real development you should use css classes to avoid removeAttr(style) etc.
Tested on iPhone and Ipad (iOS 8+).
The fiddle http://jsfiddle.net/m1eav032/5/

Calculating Height of Sidebar Dynamically

I'm trying to work out the algorithm for a fixed div that grows in height (while scrolling) until it's equal to the height of the viewport or div with fixed position relative to another div and the bottom of the viewport
I am using Twitter Bootstrap affix to lock my secondary navigation bar (yellow) and my sidebar (black) to the top of the screen when the user scrolls that far. 
This works fine. The sidebar is the piece that's giving me trouble.  When it is in its in its starting position (as shown in the diagram belorw), I want the top of the bar to sit 30px
down from the secondary navigation bar (yellow) and 30px up from the bottom of the page. 
As the user scrolls, the bar should grow in height so that it remains 30px beneath the secondary navigation bar and 30px above the bottom of the screen (As shown in the diagram below)
After the bar is fixed position, I am able to do what I need to do.  
.sidebar { 
position:fixed;
top:100px;  
bottom:30px;
left:30px;
}
What I can't figure out is how to position the TOP of the sidebar relative to my
secondary navigation bar and the BOTTOM of my sidebar relative to the bottom
of the screen. I've tried calculating the height of the sidebar at the beginning and the end of the
scroll but this causes issues.
I've also tried calculating the final height of the sidebar and letting the bottom of
the sidebar just run off the edge of the screen (when it's in its initial position), but
if there's not enough content on the right side to warrant scrolling, I have no way
of getting to the bottom items in the scroll bar.  Plus my screen starts bouncing
in a really un­attractive way.
below is the current code in use:
ShelvesSideBar.prototype._resize_sidebar = function(_this) {
var PADDING = 50;
var window_height = $(window).height(),
nav_bar_height = $('.nav_bar').height() + $('.secondary_tabs').height(),
sidebar_height = window_height - nav_bar_height - PADDING,
sidebar_scrollable_height = sidebar_height - $('.bar_top').height();
_this.$container.height(sidebar_height);
_this.$container.find('.bar_bottom').height(sidebar_scrollable_height);
/* reset the nanoscroller */
_this.$container.nanoScroller();
};
   
this code is called on page load and again on window resize. Any help would be greatly appreciated!
I've been trying to do something similar (minus the fixed elements and navbars). What I found was in order to do any sort of relative height scaling every element above the element I wished to scale all the way up to the opening html tags had to have a relative height set, even if it was just height:100%;. (here's my original question Variable height, scrollable div, contents floating)
My goal was to have the body height fixed to window size like a native full screen application would be with my content subareas scrolling, so this is a bit off topic for what you're wanting to accomplish. But I tried using JS/JQ to start off with as you're trying to do currently and found that I simply couldn't get the window height because the default behaviour for height management is to expand the page height until everything on the page fits. And all the getHeight methods I tried we're getting the page height not window/viewport height as promised. So you may wish to try fixing your body's height to the window and going from there using overflow:scroll; to scroll the page.
A quick note on overflow:scroll; if you have users who use WP8 IE (and probably other versions of IE) it may be advantageous to implement FTscroller to handle all your scroll elements as the overflow property defaults to hidden and is a fixed browser property. The only problem with FTscroller is because it uses CSS offsets to move the content container it may wreak havoc on elements that are designed to switched to fix when they reach x height from top of page because technically the top of page (or rather the top of the container they're in) isn't at the top of the page anymore it's beyond it. Just something to be aware of if you do need to cater for this browser.
And apologies for the complexity of my sentence structure. :/
so I was able to figure this out, for anyone still looking. What I ended up doing was binding to the window scroll event and - whenever the scroll occurred - I check if the class "affix" has been added to the sidebar. If it has, then I perform one set of calculations to determine sidebar height. Otherwise, I perform the other set of calculations. Code below:
/* called on window scroll */
var PADDING = 70;
var window_height = $(window).height(),
nav_bar_height = $('.nav_bar').height() + $('.secondary_tabs').height(),
header_height = $('.prof_block').height() - nav_bar_height,
sidebar_height = _this.$container.hasClass("affix") ? window_height - nav_bar_height - PADDING : window_height - (header_height + nav_bar_height) - PADDING,
sidebar_scrollable_height = sidebar_height - $('.bar_top').height();
_this.$container.height(sidebar_height);
_this.$container.find('.bar_bottom').height(sidebar_scrollable_height);

Javascript scroll and stop when in view

I have this code:
function Scroll(aid){
var aTag = $(\"a[name='\"+ aid +\"']\");
$('html,body').animate({scrollTop: aTag.offset().top},'slow');
}
But the problem is, that it scrolls down to the tag, so it is in the top of the window. I did like to have it, so it only scrolls to the element so it is in the bottom of the window.
So you can see what is on top of the element (like all the other content above it).
Any ideas?
Find out how high the viewport is, and substract that:
var pos = Math.max(aTag.offset().top - $(window).height(), 0);
$('html,body').animate({scrollTop: pos },'slow');
You might need to add a small offset.

How do a add to scrollTop based on the intended scroll distance of another element

fiddle: http://jsfiddle.net/DerNalia/88N4d/9/
The behavior I'm trying to accomplish:
The Sidebar(s) should be fixed on the page if there is enough room
for them
The Sidebar(s) should scroll if there is ever not enough room for them
When scrolling down, and the bottom of the sidebar(s) is reached, it should stop scrolling
When scrolling down, the sidebar(s) should also scroll down, until
the bottom of the sidebar(s) is/are reached
When scrolling up, and the top of the sidebar(s) is reached, it should stop scrolling
If at any point during the scrolling of the content, the user switches directions of scrolling, the sidebar(s) shall also move in the same direction as the rest of the page / content
When scrolling up, the sidebar(s) should also scroll up, until the
top of the sidebar(s) is/are reached
If the content is shorter than the sidebar(s), the sidebar(s) should
still be able to scroll This is the one that I'm having trouble
with
How do I make it so that I can detect the intended scroll distance desired by the user, rather than use the actual scrolled distance of the content body? There may be another solution, but this is all I can think of for right now.
I'm currently using Chrome on Mac.
UPDATE:
something I've noticed: using the track pad on macs does the stretching / bouncy scrolling shenanigans on the edges.. which messes up this javascript hard core. It's possible to scroll the sidebar completely off the screen if you bounce up enough times. Mouse Wheel scrolling does not have this issue.
I think you’d be much better off positioning the columns absolute and then check positions onscroll and toggle the positions.
It gets quite complicated, since the scroll will jump if both columns are fixed and the content has regular flow.
I created a solution for you using a simpler logic that goes:
var $win = $(window);
var $containers = $(".container").css('position','absolute');
// we need to force a height to the body for fixed positioning
$('body').css('minHeight', Math.max.apply( Math, $containers.map(function() {
return $(this).height();
})));
$win.bind("resize scroll", function() {
var scrolled = $win.scrollTop(),
winheight = $win.height(),
elheight = 0;
$containers.each(function() {
elheight = $(this).height();
$(this).css('position', function() {
if ( elheight > (winheight+scrolled) ) {
$(this).css('top',0);
return 'absolute';
}
$(this).css('top', Math.min(0, winheight-elheight));
return 'fixed';
});
});
});
It should fill your requirements. The fixed positioning kicks in if the columns are shorter than the window height, or if the scrollTop is enough.
A demo in all it’s glory: http://jsfiddle.net/mb9qC/

issue with $(document).scrollLeft() as a variable

I'm trying to use the left variable to replace '1493' in this code. It works fine when it's a number but when I changed it over to use 'left' the if statement stops working.
$(document).scroll(function () {
var width = $(document).width();
var left = $(document).scrollLeft();
var postCount = $(".post").length;
var columnLength = ( width - ((postCount*743) - 1493)) - (width-(postCount*743));
if(left >= columnLength) {
$(".num").text(left);
}
});
Does anyone have any ideas where I'm going wrong with this? Any pointers would be great.
You may need to force it to be an integer:
var left = parseInt($(document).scrollLeft());
Lets take a look at the math you have really quick.
var columnLength = ( width - ((postCount*743) - 1493)) - (width-(postCount*743));
You are basically cancelling out width, and (postCount*743). It leaves you with --1493 which is positive 1493. The following would have the same effect:
var columnLength = 1493;
So, the reason the if statement fires when you put in the static value 1493, is because columnLength ALWAYS equals 1493 which, of course satisfies this condition:
if (1493 >= columnLength)
You could as easily write:
if (1493 >= 1493)
That said, it should still, theoretically fire when left becomes greater than or equal to 1493. But left is the current horizontal scroll position in pixels. It would be a HUGELY wide page to hit a scroll position of 1493.
Edit: Here's a fiddle to give an idea of how fast the scroll position increases: http://jsfiddle.net/vdQ7B/16/
EDIT 2:
Here is an update in response to your comment.
As I understand it, you were trying to get a horizontal scrollbar that would, essentially, scroll forever.
Please see the following fiddle for a demo: http://jsfiddle.net/vdQ7B/40/
The code is below:
$(document).scroll(function () {
var width = $(document).width();
var left = $(document).scrollLeft();
var viewportwidth = window.innerWidth;
// If our scrollbar gets to the end,
// add 50 more pixels. This could be set
// to anything.
if((left + viewportwidth) === width) {
$("body").css("width", width + 50);
}
});
Per the comments in the code, we simply increase the width of the body if we determine we've reached the end. scrollLeft() will only tell us the number of pixels that are currently not visible to the left of the viewable area. So, we need to know how much viewable area we have, and how much is hidden to the left to know if we've scrolled all the way to the end.
If you have a scroll bar on an inner element, like a div, you'd need to update with width of the div, not the body.
Note: You may also need to use $(window) instead of $(document) to get scrollLeft() to work across all browsers.
Note: See here about using "innerWidth". There are some compatibility issues, and you may need to expand it a bit to handle other cases (IE6).

Categories

Resources