Fixing JS sticky header glitch - javascript

There are a few posts on this already, and one answer that addresses the glitch I'm experiencing but the fix doesn't work with my setup.
(Existing Post 1)
(Existing Post 2)
-
I've used some JS to create a div that sticks to the top of the browser window when a user scrolls past it. The setup works by applying the class .sticky to the existing parent container #stickywrapperaa when a user scrolls past the parent element. Here is the JS:
<script>
jQuery(document).ready(function( $ ) {
// Cache selectors outside callback for performance.
var $window = $(window),
$stickyEl = $('#stickywrapperaa'),
elTop = $stickyEl.offset().top;
$window.scroll(function() {
$stickyEl.toggleClass('sticky', $window.scrollTop() > elTop);
});
});
</script>
This creates the element ID/class attribute of #stickywrapperaa.sticky which I have then positioned and styled using CSS. All of this so far is working.
The problem:
The problem I have is that when the sticky header is activated this removes a section of the page height and causes the static page content to jump up by the same height as the parent container (#stickywrapperaa).
Logically this makes perfect sense as the container has been moved ontop of the static page content so it's now missing from the page content; however this leaves a gaping hole in my page that I now need to fill.
I thought about creating an empty space of equal height to the parent container (#stickywrapperaa) and triggering that to appear with the sticky class, effectively replacing where the header used to be with an empty space.
Can anyone help me achieve this or provide a better solution?

Add a padding-top to body when you toggle the sticky class. The padding should be the same height as your header.
<script>
jQuery(document).ready(function( $ ) {
// Cache selectors outside callback for performance.
var $window = $(window),
$stickyEl = $('#stickywrapperaa'),
elTop = $stickyEl.offset().top;
$window.scroll(function() {
$stickyEl.toggleClass('sticky', $window.scrollTop() > elTop);
if ($window.scrollTop() > elTop){
$("body").css("padding-top", $stickyEl.height());
} else {
$("body").css("padding-top", 0);
}
});
});
</script>

Set the position of the div that gets removed to absolute, while creating another, invisible div that is set to relative, and has the same height as the absolute div.
Although adding in the div with the height later might work, it would overly complicate things when you could just put it there in the first place, and remove the visible div from the normal flow.

Related

Translate div on scroll

I have a div in a div.
The first div has a unknown height. The second one has the height of 125px.
I want to make the second one a sticky div which is only sticky in this div.
The grey box is the container and the social media div next to it should be sticky.
After the container more content will come, so I cant use position: fixed. I tried to use position: absolute and change the top value or the transform: translate, but when I Do that Chrome is jittering around.
Code that I tried to use:
$offset = $(".social-media").offset().top;
$containerHeight = $(".sticky-container").height();
$bottom = $containerHeight + $(".sticky-container").offset().top;
$maxPoint = $containerHeight - $(".social-media").height();
$(window).scroll(function(){
if($(window).scrollTop() >= $offset){
if($(window).scrollTop() >= $bottom){
$(".social-media").css({transform: "translate(0px,"+$maxPoint+"px)"});
}else{
$scroll = $(window).scrollTop() - $offset;
$(".social-media").css({transform: "translate(0px,"+$scroll+"px)"});
}
}else{
$(".social-media").css({transform: "translate(0px,0px)"});
}
});
Since the jsbin you provided shows the solution works without jittering, the problem might lie in the repaints triggered by other elements of your site, not the code you pasted. Have a look at the Google's repaint optimization guidelines, it might help you identify the issues that cause the jittering.

Position fixed acting like position relative ( scrolling with page )

I'm styling an element with position fixed and other css in a certain condition ( basically if the user scrolls up ), but the element is behaving like a relative positioned element. In other words, it is scrolling with the page and not remaining fixed.
I tried isolating this issue, but this issue only exists in this site as a whole and I need it to work in this site.
var lastScrollTop = 0;
$(window).scroll(function(){
var st = $(this).scrollTop();
if(st<=lastScrollTop){
//scroll up
if($(this).scrollTop()>235) $('#searchInput').removeClass('slideIn').addClass('stickySearch');
else $('#searchInput').removeClass('stickySearch').addClass('slideIn');
}
else $('#searchInput').removeClass('stickySearch').removeClass('slideIn');
lastScrollTop = st;
});
Right now the class .slideIn has no styling associated with it, but .stickySearch does.
Here is the CSS:
.stickySearch{
width:56% !important;
position:fixed !important;
left:0;
right:0;
}
I checked in developer tools and the class is being applied and the styles are being applied, but the position fixed is just not working.
Here is a live URL: http://goo.gl/ns6UEQ
Note, it helps to have a small window in height so you can scroll. Scroll down so that the header is hidden up top and then scroll up and the search bar should appear, but the moment the header comes back into view the search bar will go back into place in the header.
This is a bug that exists in CSS and in Chrome and Firefox's implementation of CSS.
When you have a parent element that has backface-visibility or is transformed, its children can not be fixed.
More here: http://www.sitepoint.com/forums/showthread.php?1129352-CSS3-tip-of-the-week-No-1&highlight=chrome+bug+fixed
Solution: remove the transform and backface visibility styling from #container
Change the if statement to something like below
var lastScrollTop=0;
$(window).scroll(function(){
if($(this).scrollTop()>150 && lastScrollTop>$(this).scrollTop()){
$('#fixedinput').addClass('fixed');
} else {
$('#fixedinput').removeClass('fixed');
}
lastScrollTop=$(this).scrollTop();
});
JSFiddle demo
As you scroll down past the grey part the will not be fixed, but once you start scrolling up it will.

How to jump to certain position of scrolled element without scrolling the main screen?

I have a container (div) on the page. This container has a scrolling (provided by overflow:auto; height:400px).
I need no provide a URL, that will open a page so that the main page will not be scrolled, but the text in the container will be scrolled.
I tried www.mysite.com#position, but by this way the main page is scrolled too (and I need, that users will see the header on the top of the screen, and the "#position" position on the top of the container)
This is possible with javascript. And I will show a jQuery example here.
if (window.location.hash == '#position') {
$('#containerDiv').animate({
scrollTop: $("#actual_position").offset().top
}, 2000);
}
The actual_position should be the place where to scroll to. position should just be in the url and not on the page, to prevent the whole page from scrolling.
May you use the css-properties: position:fixed, top:..., left:... for your element that should stay at a certain place on your side, when an user scrolls.
Furthermore you can put all content that you do not want to be scrolled into a div and define the css-properties.
I hope this helps you a little bit.
Really it's an upgrading of Arjan answer (and now this really works).
As Arjan's suggestion the script will not work every time, but only by providing #scroll in the end of url (www.mysite.com#scroll). This script will scroll the container scroll bar to the #position element, and the all document will stay.
jQuery(window).load(function(){
container_top = jQuery('#container').offset().top;
element_top = jQuery('#position').offset().top;
element_relative_top = element_top -container_top;
if (window.location.hash == '#scroll') {
jQuery('#container').animate({
scrollTop: element_relative_top
}, 2000);
}
})

JavaScript to trigger events based on which div takes up most of the screen?

Basically I have a list of divs like this:
<div id="1">First div</div>
<div id="2">Second div</div>
and I want the most visible div to affect what is displayed in a different constant div, like this:
<div id="link">First div's link</div> (If the first div took up most of the page)
And then
<div id="link">Second div's link</div> (If the second div is scrolled to)
How would I get the Javascript to figure out which div is being viewed (calculated by which is taking up the greatest % of pixel space on the screen) and then trigger an event for the 'link' div based on that?
EDITING MY PREVIOUS ANSWER.
You have to find out how far each div is from the top of the document (it's a fixed number, regardless of how far the window is scrolled down):
divTop = $('#1').offset().top
Then, find out how far the window is scrolled:
scrollTop = $(document).scrollTop()
You also need the window's height (which is the height of visible portion of the document):
windowHeight = $(window).height()
And, you need the height of each div:
divHeight = $('#1').height().
Then you calculate where each div starts relative to the top of the window, which could be a negative number -- if the window is scrolled down past the top of the div -- in which case you make it zero, using Math.max:
divTopInWindow = Math.max(0, divTop - scrollTop)
Similarly, you calculate the div's bottom, relative to the top of the window. If the div extends past the bottom of the window, you make it the window's height:
divBottomInWindow = Math.min(windowHeight, divTop + divHeight - scrollTop)
Finally, you figure out the percent visible of each div like so (actually it's the fraction, not the percent, but whatever):
percentVisible = (divBottomInWindow - divTopInWindow) / windowHeight
I haven't tried it, so there may be a mistake in there, but it's definitely the right approach.
-------------------------- OLD ANSWER BELOW JUST FOR REFERENCE ------------------
I don't think you're using the expression "trigger an event" properly. Sounds like you just want to set the content of a div based on some condition (i.e. whether div 1 is taller than div 2).
Assuming you have jQuery or Zepto loaded on the page:
if( $('#1').height() > $('#2').height() ) {
$('#link').html('First div link');
}
else {
$('#link').html('Second div link');
}

Dynamically change relatively positioned content to fixed content - bug

I have a sidebar that contains content larger than the screen. As the user scrolls down I want that content to come into view until the last bit. Then I want it to be fixed so that as much content stays on screen as possible. I actually want it to work exactly like the "Similar Questions" sidebar when you are posting a question in SO. In each of these example links scroll down. In the broken case notice how everything gets all jumpy.
Should work like this = http://jsfiddle.net/mrtsherman/G4Uqm/2/
But broken in this case = http://jsfiddle.net/mrtsherman/G4Uqm/1/
In the broken case it looks like the scroll event is being retriggered when you reach the end of the page. This then causes subsequent scroll events to trigger which then screw everything up. How can I properly handle this case? I just can't figure it out.
$(document).ready(function() {
var dynamic = false;
var topOfSidebar = $("#sidebar").offset().top;
var leftOfSidebar = $("#sidebar").offset().left;
var botOfSidebar = topOfSidebar + $("#sidebar").height();
var botOfScreen = $(window).height() + $(window).scrollTop();
//if sidebar fits on screen then use fixed version of it
if (botOfSidebar < $(window).height()) {
$("#sidebar").addClass("fixed");
$("#sidebar").css("top", topOfSidebar);
$("#sidebar").css("left", leftOfSidebar);
}
else {
dynamic = true;
}
//toggle sidebar class when user scrolls
$(window).scroll(function() {
console.log($("#sidebar").css("position"));
botOfScreen = $(window).height() + $(window).scrollTop();
//return;
if (botOfSidebar < botOfScreen && dynamic) {
$("#sidebar").addClass("fixed");
//$("#sidebar").css("bottom", 0);
//$("#sidebar").css("left", leftOfSidebar);
}
else if (dynamic) {
$("#sidebar").removeClass("fixed");
}
});
});
So I figured this one out on my own. The trick is to wrap the content in a div with a min-height attribute. If we switch the sidebar to fixed then the div holds the place of the sidebar. Therefore no more screen resizing.
.wrap creates the div
.parent gets the sidebar's parent (the new div)
add css properties where min-height is the height of the sidebar. Remove padding and margin
$("#sidebar")
.wrap('')
.parent()
.css("min-height", this.height())
.css("padding", "0px")
.css("margin", "0px");

Categories

Resources