I have a fixed div set at the top of the browser window, with z-index:2, and with text in this div.
My website page is a single page at z-index:1, and with multiple "<section id=...>" sections in it for each website "page".
I'm using javascript and jquery to display each section id for the user, and for the requested section to come up flush with the bottom of the top fixed div.
For this, I am using the statement:
$('html, body').animate({scrollTop: $('#sectionid').offset().top-xx)}, 0);
- where "xx" above is a number.
I can manually edit and change the "xx" number in my program to set the page section to whatever top I need, and this all works fine.
However, I am also using; "$(window).on('resize', function() { .." in my program, to reset/recalculate the section top to match the bottom of the fixed div. This is because the fixed div changes in height whenever the browser window is re-sized by the user. That is, the text in the fixed div will re-flow onto the next line when the browser window is made smaller etc..
So I tried using a variable name for the "top-xx" value, such as ".offset().top-myPageTop". But this does not work and the sectionid top always lands on "top-0" under the fixed div.
After much trial & error, I came up with this solution:
$('html, body').animate({scrollTop: eval('$('#sectionid').offset().top-' + myPageTop)}, 0);
- where "myPageTop" is a variable that is set/reset by the "$(window).on('resize'.." function mentioned above.
For my website, the above last jquery statement works just fine. But I am left wondering that maybe this is not really the correct way of doing this. I have looked through the jquery documentation and searched this site (and others), but I could not find much on using "top-xx" with a variable name in the above statement. Is there a better way of doing this?
Related
I'm having a problem implementing relatively complicated auto-scroll functionality on my page. This displays the issue in my code...
http://codepen.io/d3wannabe/pen/XXxdQq
I have multiple divs on my page (blue,red,green in my example) that I not only want to be able to scroll to (which the top 3 buttons in my example achieve perfectly), but I want to be able to scroll WITHIN (which the bottom 3 buttons represent my best attempt at).
The thing I can't figure out, is why the scroll within function works well on my first div ("scrollTo3rdBlueItem" button), but then less accurately with the other divs ("scrollTo3rdRedItem" and "scrollTo3rdGreenItem" buttons). In my full web application (which obviously has more data to scroll through), I basically see that the lower down the page the parent div is positioned, the less accurately I'm able to scroll within it.
I'm struggling to identify much of a pattern though so can't simply try tweaking the offset values. Any ideas what I might be doing wrong here would be hugely appreciated!!
...since I wasn't allowed to post this without quoting code - here's the jquery function you can see in my codepen!
function scrollToParent(parentID){
$('html,body').animate({scrollTop: $('#'+parentID).offset().top}, 500);
}
function scrollToChild(parentID, childID){
//first focus on the parent
scrollToParent(parentID);
$('#'+parentID).animate(
{scrollTop: $('#'+ childID).offset().top - 100}
, 500);
}
UPDATE
Answer here was COMPLETETLY wrong. Left here to preserve the comments.
UPDATE 2
Got IT! You need to take in to account the offset of the parent div. Update your scrollToChild function to the below;
$('#'+parentID).animate(
{
scrollTop: $('#'+ childID).offset().top - $('#'+parentID).offset().top
}, 500);
I tried to do a minimal version of the problem i am having. In short i am doing header with navigation that always sticks to the top of page when scrolling.
Now the problem is if you try and click on a section in the navigation, when you get scrolled to the section the navigation blocks half the content at the top by getting in the way.
This means the user has to scroll back up a little to see the content properly. I am using lorem ipsum as content replacement there.
How would i adjust where my browser position lands when the user clicks the navigation button so i can position the window correctly?
https://jsbin.com/hopiqe/edit?html,css
Eli-
Using HTML/CSS only, you'd have to do a hack like Kommodore suggests to get this working properly. Your really need JS to do this right.
You can do this with jQuery and a little foresight:
// Button 1 is what you click to start the interaction
$(".button1").click(function() {
// Using jQuery Animate and ScrollTop...
$('html, body').animate({
// We point user to div1
// We have an offset from the top of the window minus 50px
// `-50` should match the height of your header
scrollTop: $("#div1").offset().top-50
// 500 is milliseconds to do the `Animate` interaction
}, 500);
});
You could also use a combination of jQuery plugins called ScrollTo and LocalScroll.
I wired up a working CodePen that builds off the code you provided. The JS probably needs more tightening but you should get the idea.
The easiest way should be adding another div as a placeholder with height: 140px in front of each div (which then has to be called instead of the div) or using margin-top: 140px for each div.
I am working on building a schedule. So far it's pretty straight-forward. There is one bit of functionality I am having issues with.
I have an ul that has a fixed height to allow scrolling. There are "Labels" (li.dayLabel) withing the ul that separate the hours. What I am trying to do is to have it so that when a label is scrolled out of view it will change the text in the placeholder to it's text. Then once that works, I need it to work in reverse. So when they label scrolls back into view it updates the placeholder. Basically, I am trying to make the placeholder be a title for the available items until another label is then scrolled out of view. This is for scrolling from the top. So as you scroll down the list the placeholder is meant to be a title for the section you are viewing until you reach another section and it takes its place. Then when you scroll back down I need it to replace the text with the previous li.dayLabel so the sections stay organized. I hope this makes sense.
You can see what I am trying to do by looking at the original that I am basing this off of. Notice how the placeholder changes as you scroll down the list and changes back when you scroll back up.
Demo: jsFiddle // Note: line 54 is the part that is in question
I originally used:
$(".snlf-schedule-list li.dayLabel:visible:first").text();
as the :first selector is suppose to only match a single element.
I later tried:
$(".snlf-schedule-list li.dayLabel:visible").filter(":eq(0)")
as this is suppose to be the same thing.
It seems that when an element is out of view it still is considered :visible I believe this is my issue.
Am I doing this completely wrong? I was under the impression that when you scroll an element like this it should no longer be :visible. After reading the documentation I have learned that this is not the correct selector to use.
It would appear that scrollTop is how I should be doing this. Now I have used scrollTop for scrolling down pages to disable animations when not in view but I am not clear on how to untilize this for a ul with scrollbars.
I tried:
var _first = $('li.dayLabel:first'); // next element to scroll out of view?
if( $(this).scrollTop() > (_first.offset().top+_first.height())) {
// Out of view
console.log("out");
} else {
// in view
console.log("in");
}
Updated Demo: jsFiddle
But it seems to be redundant as it's already calculating the first element so I am not sure how to get the correct element (the next one that's about to scroll out of view.) Then I need this to work when they scroll back up...
Any insight on this is much appreciated. Hopefully it's something simple I am just over complicating or missing completely.
Thanks,
Jeremy
The solution for my case was:
// Set placeholder text on scroll
var _scrollCagePositionTop = $(".snlf-schedule-list").offset().top;
var _first = $('li.dayLabel:first'); // first dayLabel element
$(".snlf-schedule-list").scroll(function(){
var _lastOffText = $(_first).text();
$("li.dayLabel").each(function() {
if ($(this).offset().top < _scrollCagePositionTop) {
_lastOffText = $(this).text();
}
});
$("#schedule-placeholder").text(_lastOffText);
});
What I did was set the known position of the top of the scroll cage (_scrollCagePositionTop)
When the user scrolls I set a variable _lastOffText that keeps track of the last item text content when scrolled out of view (less offset top than the palceholder). I then set this value to the placeholder.
This method allows me to have the proper text in my placeholder when the user scrolls up or down.
To fix the issue of an empty placeholder when the user scrolls back to the top I just set the default of _lastOffText to be the text of the first label ($(_first).text())
Hope others find this useful.
Here is the working demo: jsFiddle Final
My problem is that after scrolling in the #leftnav the #leftnavHover does not position itself according to the new top css value. I need the #leftnavHover div to follow in the same way the native title text for the browser does.
Here's a fiddle http://jsfiddle.net/fauverism/b4rwb/6/
Here's a step by step of what I'm describing...
Visit the link and hover over Sabers in the nav
Scroll inside the nav div
Hover over Sabers again and you'll notice that the placement of the Sabers text inside of the #leftnavHover is in the same place. The div placement does not insert the new topAfterScroll array. The array is only present once and it then gets removed with the original value.
Here are some details...
I can't seem to store the array that is retrieved after the scroll from topAfterScroll into a new var
This only has to work in Chrome :)
Yes I know that this does seem strange to do since browsers handle this functionality just fine. It's a Chromium issue.
Just subtract the scrolled pixels using jQuerys scrollTop (API) on #leftnav like this:
$('#leftnavHover').text(this.title).css('top', this.offsetTop - $('#leftnav').scrollTop());
http://jsfiddle.net/b4rwb/7/
I've been racking my brain and my Google Fu for a few hours now trying to find a solution to this one, but can't seem to come up with anything satisfactory.
I want to affix an element to the side of the page for some search criteria, much like Bootstrap's "Affix" plugin. (Demo Here). The problem is that it's going to be very common that the element is much taller than the window. So there will be scrolling of the element itself involved.
Usually this wouldn't be a problem because as the user hits the top + bottom of the document they would be able to see the top and bottom of the fixed element. (See bootstrap example while shrinking you're window very short). But we're planning on using infinite scroll on our results set, meaning there won't be a bottom to hit, and therefore they'll never see the bottom of the fixed element. As the user scrolls down, it needs to be bottom fixed so the user sees all criteria, then on the way up, it needs to be top fixed.
So I started off by modifying Bootstrap's plugin (I'm not actually using bootstrap). Now scrolling down the page is easy, using a fixed point on the bottom of the element means that it's not affixed until you reach the bottom of it.
But scrolling back up again is where I'm hitting issues.
Am I missing something really obvious and easy here (it is Monday morning after all), or does anyone know of a plugin / patch to bootstraps affix.
TL;DR
Need to affix a very tall element to the page and allow it to scroll. So it's fixed on the way down, then as they scroll back up, the element isn't fixed so it's also being scrolled up. Once the top of the element is hit, fix it there.
Is this what you Want to do DEMO
Simple jQuery function that will help.
$(function()
{
affix= $(".affix-top");
var affixHeight = parseInt(affix.height());
var affixTop = parseInt(affix.offset().top);
var affixBottom = parseInt(affixTop + affixHeight);
// Bind a scroll event for the whole page
$(document).bind("scroll", function(e)
{
// Calculate how far down the user has scrolled
var screenBottom = parseInt($(window).height() +$(window).scrollTop() );
// Test if the div has been revealed
if(screenBottom > affixBottom)
{
affix.attr("style","");
affix.css({"bottom":"0px","position":"fixed"});
}
else
{
affix.attr("style","");
affix.css({"top":"0px","position":"relative"});
}
});
});