How to scroll page down after anchor navigation? - javascript

I have added top menu as a div with position: fixed.
It's placed in the top of the page, so it covers part of the content.
I moved the layout down, so generally it's ok, BUT if user clicks any anchor link, the page scrolled to where the anchor is on top. But it's covered by the top menu.
Is there a way to catch anchor event and process it with javascript (and jQuery if necessary)?

You can use something like this:
$('a').click(function(){
$('html').scrollTop($($(this).attr('href')).position().top + menu_height_offset)
})
To get the anchor position
$($(this).attr('href')).position().top
To make the offset related to the fixed menu
menu_height_offset
To make move the scroll
$('html').scrollTop()
http://api.jquery.com/scrollTop/
http://api.jquery.com/position/

You need to calculate the offset of the element and sroll to the offset of element - height of the navigationbar - position:
$("a").on("click",function(){
// height of the navigation bar
var height= $("#nav").outerHeight();
// position of the referenced dom-element
var pos = $($(this).attr("href")).position().top;
// scroll to the element
$("body").scrollTop(pos - height);
// suppress default
return false;
})​
See it in action here.

/* START --- scroll till anchor */
(function($) {
$.fn.goTo = function() {
var top_menu_height=$('#div_menu_header').height() + 5 ;
//alert ( 'top_menu_height is:' + top_menu_height );
$('html, body').animate({
scrollTop: (-1)*top_menu_height + $(this).offset().top + 'px'
}, 500);
return this; // for chaining...
}
})(jQuery);
$(document).ready(function(){
var url = document.URL, idx = url.indexOf("#") ;
var hash = idx != -1 ? url.substring(idx+1) : "";
$(window).load(function(){
// Remove the # from the hash, as different browsers may or may not include it
var anchor_to_scroll_to = location.hash.replace('#','');
if ( anchor_to_scroll_to != '' ) {
anchor_to_scroll_to = '#' + anchor_to_scroll_to ;
$(anchor_to_scroll_to).goTo();
}
});
});
/* STOP --- scroll till anchror */

Related

How do I code JQuery so that when I scroll to a certain element, Nav bar appears at top, when I scroll back up past that element, nav bar disappears

I have a div called #menu which I want to display when I scroll past the element #section3, if I scroll up past that element again, I want #menu to disappear
How would I code this?
Maybe something like this?
scrolled = "no"
$(window).scroll(function(){
scr = $("body").scrollTop();
if (scr > 100 && scrolled == "no"){
$("#menu").css({"display:block"})
displayed = "yes"
}
if (displayed == "yes" && scrolled = "yes"){
$("#menu").css({"display:none"})
}
});
The above assumes that #section3 is 100 pixels down the page. If you do not know where its going to be on the page then you could use the method outlined here:
Trigger event when user scroll to specific element - with jQuery
With jQuery you can get the scroll position with $("body").scrollTop();.
Expanding on what #Ned Hulton said, I recommend comparing the scroll position to the top of a "container element" (or 'row') in your page like this:
if ($('body').scrollTop() > $('#someRow').offset().top){
//do something
}
That way you can account for your container appearing at a variable distance down the page (which will come in handy for mobile browsing or cases where your text wraps to additional lines)
I just whipped this up in jsfiddle
https://jsfiddle.net/rb56j0yu/
it uses jQuery, and checks the scroll position against the target div. Css sets the menu as position: fixed, and defaults to hidden.
$(window).scroll(function(){
var yPos = $("body").scrollTop();
var yCheck = $("#c3").position().top;
if (yPos > yCheck && !$("#menu").is(":visible"))
{
$("#menu").show();
}
if (yPos <= yCheck && $("#menu").is(":visible"))
{
$("#menu").hide();
}
});
First, get your #section3 top offset and height. Which will be used as the threshold whether #section3 is actually on the window screen.
var top = $('#section3').offset().top;
var bot = topOffset + $('#section3').height();
Then, detect it on your scroll event.
$(window).on('scroll', function () {
var scrollTop = $(window).scrollTop();
if (scrollTop >= top && scrollTop <= bot) {
// #section3 is within the screen.
$('#menu').show();
}
else {
// #section3 is out of screen.
$('#menu').hide();
}
});
This is a common use case, I wrote following code:
// what does "Auto Header" mean, goto https://www.yahoo.com/
// scroll down and you will see the purple part auto fixed to top,
// while when scroll up, it restores and does not be fixed.
// 1. multiple auto header elements handled
// 2. dynamically create/remove elements issue handled
// 3. no unnecessary dom operation, high performance
// usage: just add 'class="auto-header"' to any element you want to auto header
// suggest set each auto-header element specific width and height
// do not guarantee it works when resize or scroll left/right
$(document).ready(function() {
var rawTops = [],
rawLefts = [],
rawStyles = [],
$locations = [], // record next sibling so that element easily find where to restore
fixed = []; // mark whether this element is fixed
$(".auto-header").each(function() {
var $this = $(this),
offset = $this.offset();
rawTops.push(offset.top);
rawLefts.push(offset.left);
rawStyles.push($this.attr("style"));
$locations.push($this.siblings().eq($this.index()));
fixed.push(false);
});
$(window).on("scroll", function() {
$(".auto-header").each(function(i, e) {
if(!fixed[i] && $(window).scrollTop() > rawTops[i]) {
var $te = $(this).clone(true);
$(this).remove();
$locations[i].before($te);
$te.css({
"position": "fixed",
"top": 0,
"left": rawLefts[i],
"z-index": 100
});
fixed[i] = true;
} else if(fixed[i] && $(window).scrollTop() < rawTops[i]) {
$(this).removeAttr("style").attr("style", rawStyles[i]);
fixed[i] = false;
}
});
});
});

JQuery Add Class when bottom of div reaches top

I am trying to add a class when the bottom of a div reaches the top of the window, but am not sure of how to do it.
I have managed to add the class when the top of the div gets to the top of the window, but am not having much luck with the bottom of the div.
Code I am using:
$(document).ready(function() {
var menuLinksTop = $('.container').offset().top;
var menuLinks = function(){
var scrollTop = $(window).scrollTop();
if (scrollTop > menuLinksTop) {
$('header').addClass('black-links');
} else {
$('header').removeClass('black-links');
}
};
menuLinks();
$(window).scroll(function() {
menuLinks();
});
Any help is appreciated.
You should use javascript's getBoundingClientRect() method, watch $(window).scroll event, and look at element's rectangle, its bottom value will give you what you need (if it's negative, your element is all the way up)
$(window).scroll(function() {
console.log($("div.watch")[0].getBoundingClientRect());
if ($("div.watch")[0].getBoundingClientRect().bottom < 0)
alert ("i'm out :3");
});
see jsFiddle http://jsfiddle.net/ja5nnbwr/2/
Add the height of the div. Assuming it is the .container :
var menuLinksTop = $('.container').offset().top + $('.container').height();

Update scroll position on resize of window

I'm currently using a combination of smooth scroll and IDs/anchor tags to scroll to content on my site. The code below is getting the ID of the next 'section' in the DOM, and adding it's ID as the 'view next section' href, so once it's clicked, it'll scroll to the top of that div. Then, it iterates through, updating the href with the next ID each time etc until the last section is seen and it scrolls back to the top. Pretty straightforward.
The only problem is that the 'sections' are fullscreen images, so as it's scrolling to the top of the next section, if you resize the browser, the top position of that section (where we scrolled to) has moved, and means the position is lost.
I've created a JSFiddle. You can see this happening after you click the arrow to visit the next section then resize the window: http://jsfiddle.net/WFQ9t/3/
I'm wanting to keep this top position fixed at all times so even if you resize the browser, the scroll position is updated to reflect this.
Thanks in advance,
R
var firstSectionID = $('body .each-section').eq(1).attr('id');
$('.next-section').attr('href', '#' + firstSectionID);
var i = 1;
$('.next-section').click(function() {
var nextSectionID = $('body .each-section').eq(i).attr('id');
i++;
$('.next-section').attr('href', '#' + nextSectionID);
var numberOfSections = $('body .each-section').length;
var lastSectionID = $('body .each-section').eq(numberOfSections).attr('id');
if ($('.next-section').attr('href') == '#' + lastSectionID ) {
$('.next-section').attr('href', '#introduction');
i = 1;
}
});
Ok, Please check out this fiddle: http://jsfiddle.net/WFQ9t/9/
The few things I did were:
Made some global variables to handle the screen number (which screen you're on and also the initial window height. You will use this when the screen loads and also when you click on the .next-session arrow.
var initWinHeight = $(window).height();
var numSection = 0;
Then I tossed those variables into your resizeContent() function
resizeContent(initWinHeight, numSection)
so that it will work on load and resize
I made the body move around where it needs to, to accomodate for the movement of the divs (I still don't understand what divs are moving when the regular animation happens).
$('body').css({
top: (((windowHeight - initWinHeight)*numSection)*-1) + "px"
});
Then in your click function, I add 1 to the section number, reset the initial window height and then also reset the body to top:0. The normal animation you have already puts the next section at the top of the page.
numSection++;
initWinHeight = $(window).height();
$('body').css({top:"0px"}, 1000);
Finally, I reset the numSections counter when you reach the last page (You might have to make this 0 instead of 1)
numSection = 0;
The fiddle has all of this in the correct places, these are just the steps I took to change the code.
Here is a solution that i found, but I dont use anchor links at this point, i use classes
Here is my HTML code:
<section class="section">
Section 1
</section>
<section class="section">
Section 2
</section>
<section class="section">
Section 3
</section>
<section class="section">
Section 4
</section>
And here is my jQuery/Javascript code,
I actually used a preety simple way:
$('.section').first().addClass('active');
/* handle the mousewheel event together with
DOMMouseScroll to work on cross browser */
$(document).on('mousewheel DOMMouseScroll', function (e) {
e.preventDefault();//prevent the default mousewheel scrolling
var active = $('.section.active');
//get the delta to determine the mousewheel scrol UP and DOWN
var delta = e.originalEvent.detail < 0 || e.originalEvent.wheelDelta > 0 ? 1 : -1;
//if the delta value is negative, the user is scrolling down
if (delta < 0) {
next = active.next();
//check if the next section exist and animate the anchoring
if (next.hasClass('section')) {
var timer = setTimeout(function () {
$('body, html').animate({
scrollTop: next.offset().top
}, 800);
next.addClass('active')
.siblings().removeClass('active');
clearTimeout(timer);
}, 200);
}
} else {
prev = active.prev();
if (prev.length) {
var timer = setTimeout(function () {
$('body, html').animate({
scrollTop: prev.offset().top
}, 800);
prev.addClass('active')
.siblings().removeClass('active');
clearTimeout(timer);
}, 200);
}
}
});
/*THE SIMPLE SOLUTION*/
$(window).resize(function(){
var active = $('.section.active')
$('body, html').animate({
scrollTop: active.offset().top
}, 10);
});

How to Set Offsett for Smooth Scroll

I have implemented the CSS Tricks Smooth Page Scroll on my site and it's working pretty nicely. However, because I have a fixed nav at the top of the page, when the page scrolls to the appropriate anchor div, the top of the div disappears behind the nav. How can I offset the scroll (about 70px) so that the whole div is shown? I tried doing this:
var targetOffset = $target.offset().top - 70;
But that doesn't quite work. The page scrolls to the appropriate spot but then it immediately jumps back up so that the top of the div is hidden. What am I missing? Here's the code in full:
$(function() {
function filterPath(string) {
return string
.replace(/^\//,'')
.replace(/(index|default).[a-zA-Z]{3,4}$/,'')
.replace(/\/$/,'');
}
var locationPath = filterPath(location.pathname);
var scrollElem = scrollableElement('html', 'body');
// Any links with hash tags in them (can't do ^= because of fully qualified URL potential)
$('a[href*=#]').each(function() {
// Ensure it's a same-page link
var thisPath = filterPath(this.pathname) || locationPath;
if ( locationPath == thisPath
&& (location.hostname == this.hostname || !this.hostname)
&& this.hash.replace(/#/,'') ) {
// Ensure target exists
var $target = $(this.hash), target = this.hash;
if (target) {
// Find location of target
var targetOffset = $target.offset().top - 70;
$(this).click(function(event) {
// Prevent jump-down
event.preventDefault();
// Animate to target
$(scrollElem).animate({scrollTop: targetOffset}, 400, function() {
// Set hash in URL after animation successful
location.hash = target;
});
});
}
}
});
// Use the first element that is "scrollable" (cross-browser fix?)
function scrollableElement(els) {
for (var i = 0, argLength = arguments.length; i <argLength; i++) {
var el = arguments[i],
$scrollElement = $(el);
if ($scrollElement.scrollTop()> 0) {
return el;
} else {
$scrollElement.scrollTop(1);
var isScrollable = $scrollElement.scrollTop()> 0;
$scrollElement.scrollTop(0);
if (isScrollable) {
return el;
}
}
}
return [];
}
});
Thanks in advance for your help.
This always happens. I search and search for an answer, get frustrated, post a question asking for help, and then immediately find an answer to my problem. Silly. Anyway, here's the solution for anyone who might be having the same problem.
If you want to change the offset by 70px, for example, change the code to this:
var targetOffset = $target.offset().top - 70;
However, unless you remove this line from the code...
location.hash = target;
... the page will scroll to the right spot and then immediately jump back up so that the top of the div is hidden behind the header. You can remove the above line from the code and everything will work great, except for the fact that the URL will no longer change to reflect the user's position on the page.
If you want the URL to change (and I think this is a good idea for usability purposes), then all you have to do is change the CSS for the anchor divs. Add a positive value for padding-top and a negative value for margin-top. For example:
#anchor-name {
padding-top: 70px;
margin-top: -70px;
}
I only have 3 divs, so I just plugged in that CSS to each of them and voila, everything worked. However, if you have a lot of anchor divs, you might consider creating a class of .anchor, putting the CSS there, and applying the class to all the appropriate divs.
I hope this helps!
I have fixed such a kind of issue with below code:
Working demo HERE. You can play with "Post Topics" section in the sidebar and content in the main-content area.
Code
jQuery(function() {
jQuery('a[href*=#]:not([href=#])').click(function() {
if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
var target = jQuery(this.hash);
target = target.length ? target : jQuery('[name=' + this.hash.slice(1) +']');
if (target.length) {
jQuery('html,body').animate({
scrollTop: target.offset().top -100
}, 1000);
return false;
}
}
});
});
Refer to https://codepen.io/pikeshmn/pen/mMxEdZ
Approach: We get the height of fixed nav using document.getElementById('header').offsetHeight
And offset the scroll to this value.
var jump=function(e){
e.preventDefault(); //prevent "hard" jump
var target = $(this).attr("href"); //get the target
//perform animated scrolling
$('html,body').animate(
{
scrollTop: $(target).offset().top - document.getElementById('header').offsetHeight - 5 //get top-position of target-element and set it as scroll target
},1000,function() //scrolldelay: 1 seconds
{
location.hash = target; //attach the hash (#jumptarget) to the pageurl
});
}
$(document).ready(function()
{
$('a[href*="#"]').bind("click", jump); //get all hrefs
return false;
});
Actually there's a CSS rule for that : scroll-padding-top :)
Combined with a regular padding-top for the top-most element of course.
cf. https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-padding-top
CSS scroll margin or padding
/* Scroll to 2rem above the target */
:target {
scroll-margin-top: 2rem;
}
/* Bonus for a smooth scrolling experience */
body {
scroll-behavior: smooth;
}
Read more about scroll margin and scroll padding on MDN.

One function to rule multiple buttons, and then some

I have 7 buttons. They are distributed on top of a background image and interacting with it. They are placed absolutely. I have created a jQuery function to animate one of the buttons height. The button expands upwards. Check it out here: http://hdpano.no/bf/newindex.html and click the top left button named Deck 8.
I wish this function to handle all the buttons, but there are some variables. The baseline of each button varies, and i need to subtract from it as i expand the height. I also wish to close any other open button if one clicks another.
Here is the jQuery code:
jQuery(document).ready(function() {
$('#link8').toggle(
function()
{
$('#deck8').animate({height: "25px",top:"202"}, 500);
},
function()
{
$('#deck8').animate({height: "150",top:"76"}, 500);
});
});
The function is quite basic and I have stripped it of all my attempts to make it work with the other buttons.
This does what you're looking for. Replace the code in your page with this...
<script type="text/javascript">
jQuery(document).ready(function() {
$('.link').click(function() {
var $me = $(this);
if ($me.height() == 150) {
$me.animate({height: "25px",top:"+=126"}, 500);
} else {
$(".link").each(function() {
if ($(this) != $me) {
if ($(this).height() == 150) {
$(this).animate({height: "25px",top:"+=126"}, 500);
}
}
});
$me.animate({height: "150px",top:"-=126"}, 500);
}
});
});
</script>
You can toggle the position with += and -= so it uses relative positioning, rather than absolute positioning, so that code affects all the divs on the page with class "link".
this in the toggle functions would be the element that is clicked.
Here is what I would do:
remove the <br/> tags. Use margin/padding to achieve spacing.
basically you want to expand/collapse the element ".link" (the container) for the height of the contained <ul>.
use "+=" or "-=" with the animate function to automatically add/remove the specified value.
as your buttons start collapsed, you should invert the two functions in the toggle
Here a code that is more general:
jQuery(document).ready(function() {
// on click of any link with class ".linkContent"
$('.linkContent').toggle(
function() {
// get the parent ".link" container
var $parent = $(this).parent(),
// get the full height of the <ul> to show/hide + the height of the link
h = $parent.find('ul').outerHeight() + $(this).outerHeight();
// animate using += and -= to avoid setting explicit values
$parent.animate({ height: '+=' + h, top: '-=' + h }, 500);
},
function() {
var $parent = $(this).parent(),
h = $parent.find('ul').outerHeight() + $(this).outerHeight();
$parent.animate({ height: '-=' + h, top: '+=' + h }, 500);
});
});
The following demo shows the code in action. You might have to tweak it a bit to get the exact height to add/remove but you get the idea:
DEMO
What you want to do is add a class eg .deck to each button, then toggle .deck'. Inside the toggle function use$(this)` to refer to the current button.

Categories