Make JS detect position on page? - javascript

I got a one-page website, before that it had 3 different pages, and the navigation bar's link to the current page turned to ´id="selected´
#selected {
background-color:white;
color: #645406;
cursor: default;
}
when you are on that page.
Now it's a bit harder, as the links work just as anchor links.
I'd need a script that would detect where the user is scrolling, and automatically turn the anchor's link to ´id="selected"´ when the user scrolls over the anchor.
Example:
http://jsfiddle.net/mbSXB/

Try this http://jsfiddle.net/8NKqf/1/
$(function() {
var anchors = $('.anchor');
var navLinks = $('.navigointi a');
$(window).scroll(function() {
var scrollTop = $(window).scrollTop();
var clientHeight = document.documentElement.clientHeight;
var activeSectionAnchor, hash;
anchors.each(function() {
if ($(this).offset().top < scrollTop + clientHeight) {
activeSectionAnchor = $(this);
}
});
hash = "#" + activeSectionAnchor.attr('name');
activeLink = navLinks.removeClass('selected').filter('[href="' + hash + '"]');
activeLink.addClass('selected');
});
});

Related

Highlighting current section in navbar

I have a scrolling page with a navbar and I want the section the user is scrolling through to be highlighted in the navbar. At the moment it almost accomplishes this, but is highlighting the incorrect link.
A demonstration is at http://codepen.io/meek/pen/NNprYb?editors=1000
The code that does this is as follows:
// highlight current tab
$(window).on("scroll", function() {
var currentPos = $(window).scrollTop();
$('.nav li a').each(function() {
var sectionLink = $(this);
var section = $(sectionLink.attr('href'));
if(section.position().top <= currentPos && sectionLink.offset().top + section.height() >= currentPos) {
$('.nav li').removeClass('active');
sectionLink.parent().addClass('active');
}
else {
sectionLink.parent().removeClass('active');
}
});
});
I've tried several things, but can't get it to reliably add the active class to the correct session. Help appreciated!
edit: to be clearer, the problem is that it's only highlighting the section when you've scrolled a bit into it, instead of right at the top, meaning that when you click a section to scroll to the top of that section automatically, that section is not highlighted.
edit2: So changing the if statement to:
if(currentPos + $('#nav-wrapper').outerHeight() >= section.position().top && currentPos + $('#nav-wrapper').outerHeight() <= sectionLink.offset().top + section.outerHeight()) {
has made an improvement although not completely fixed the issue. The home, about and portfolio sections all highlight the correct link but not contact.
You need to account for the height of the navbar and subtract it from the top of the section you want highlighted.
The height is currently hardcoded in your CSS at 75px but I included a jQuery selector for the height in case it needs to change/disappear for smaller screens.
Nice work by the way.
$(window).on("scroll", function() {
var currentPos = $(window).scrollTop();
$('.nav li a').each(function() {
var sectionLink = $(this);
// capture the height of the navbar
var navHeight = $('#nav-wrapper').outerHeight() + 1;
var section = $(sectionLink.attr('href'));
// subtract the navbar height from the top of the section
if(section.position().top - navHeight <= currentPos && sectionLink.offset().top + section.height()> currentPos) {
$('.nav li').removeClass('active');
sectionLink.parent().addClass('active');
} else {
sectionLink.parent().removeClass('active');
}
});
});

fast jump to make javascript object visible on screen

I have a function that scrolls to make an object visible on screen. However, it is slow. Is there any way to jump to without scrolling the entire page ?
If there is a reasonably portable method that does not use jquery, I would prefer a native one. My definition of reasonably portable is that it works on fairly recent chrome and firefox.
function scrollToId(id) { //TODO: Fix Jquery madness below
var element = $('#' + id); //document.getElementById(id);
var offset = element.offset().top;
if (offset > window.innerHeight) {
// Not in view so scroll to it
$('html,body').animate({
scrollTop: offset
}, 10);
return false;
}
return true;
}
Your best bet for jumping to an area quickly on the page is to use the window.scroll(x, y) method. This does not animate the page, however, it will get your user to that area on the page very quickly.
function scrollToId(id) { //TODO: Fix Jquery madness below
var element = $('#' + id); //document.getElementById(id);
var yPos = element.offset().top;
var xPos = 0; //This could be the left position of an element like element.offset().left
if (offset > window.innerHeight) {
// Not in view so scroll to it
window.scroll(xPos, yPos);
return false;
}
return true;
}
http://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_win_scrollto2
https://developer.mozilla.org/en-US/docs/Web/API/Window/scroll
Is there any way to jump to without scrolling the entire page ?
Try utilizing <a> element with #id set at href attribute , where #id is id of DOM element
#abc {
position:relative;
top:350px;
color:green;
}
#def {
position:relative;
top:650px;
color:orange;
}
abc def
<div id="abc">abc</div>
<div id="def">def</div>
I am not sure how much of a difference this would make, but try snippet below. Instead of scrolling it, just go to it.
function scrollToId(id)
{
var element = $('#' + id);
var curPos = element.offset();
var curTop = curPos.top;
var screenHeight = $(window).height();
return (curTop > screenHeight) ? false : true;
}

Horizontal scrolling page links don't work from another page

I have a section within my page that scrolls horizontally with the help of some Javascript. The issue is the links to these horizonal sections don't work if I reference them from another page. The working example is here ("What We Offer" sub links in the main navigation):
http://fitnessacademysurrey.cloudlevel.me
If I navigate to the blog page and then use the "What We Offer" sub-links, they don't do anything.
Here's the code for the links:
$(document).ready(function () {
var sildeNum = $('.page').length,
wrapperWidth = 100 * sildeNum,
slideWidth = 100/sildeNum;
$('.wrapper').width(wrapperWidth + '%');
$('.page').width(slideWidth + '%');
$('a.scrollitem').click(function(){
$('a.scrollitem').removeClass('selected');
$(this).addClass('selected');
$('#nav-subnav ul li').removeClass('active');
$('.panelHeading').addClass('hidden');
$("a.scrollitem").each(function(index) {
if($(this).hasClass("selected"))
$("#nav-subnav ul li:nth-child("+(index+1)+")").addClass("active"),
$(".panelHeading:nth-child("+(index+2)+")").removeClass("hidden");
});
$('#nextLink').removeClass('disabled');
$('#previousLink').removeClass('disabled');
if($('#nav-subnav ul li.active').is(':last-child'))
$('#nextLink').addClass('disabled');
if($('#nav-subnav ul li.active').is(':first-child'))
$('#previousLink').addClass('disabled');
var slideNumber = $($(this).attr('href')).index('.page'),
margin = slideNumber * -100 + '%';
$('.wrapper').animate({marginLeft: margin},500);
return false;
});
});
$( function() {
var hash = window.location.hash;
if (hash.length > 1) {
$("[href='" + hash + "']").click();
}
});
previousLink and nextLink are for additional navigation, but I don't think this is relevant.
Can anyone help?
Well the problem is you use JavaScript to scroll the page so you need to add code that reads the hash and finds the right link and clicks it.
$( function() {
var hash = window.location.hash;
if (hash.length > 1) {
$("[href='" + hash + "']").click();
}
});

Menu fixed on single page - change color

i want to create a menu for a single page website with link to div from page.
The menu look like this:
<li>Home</li>
...
<div id="home-link"></div>
I want to change color of link from menu when i am in area of home-link div. How is possible to make that thing?
Thanks for answers and for your help.
Have a nice day.
You will need JavaScript for this if the link element is not a child of #home-link.
Something like this:
$('#home-link').on('hover', function () {
$('li a').css('color', '#bada55');
});
This assumes you are using jQuery, but similar approach with other frameworks would work as well.
If I assume from the question that if you are hovering on #home-link and color of anchor should change, then
$('#home-link').hover(function () {
$('li a').css('color', 'red');
});
or if I assume that if the id is present in your page and you want to change the color of the anchor then
if($('#home-link').length){
$('li a').css('color', 'red');
}
I found myself with (what I believe is) the same question: how can I change which navigation link is highlighted to reflect the area I've scrolled to, whether I get there by using the link or just by scrolling down the page?
Here's a page with a very helpful tutorial.
The theory:
We create an array of all our nav a href’s. We then use some calculations using the scroll function. We find the section id, calculate it’s height, see if it’s greater or less than the value from the window top, and if the window falls in between, we add a class nav-active to the list item in question. We create a conditional also, because if the top of a section is not reached and the page can’t scroll anymore, we want to highlight this section.
And the relevant jQuery code:
/**
* This part handles the highlighting functionality.
* We use the scroll functionality again, some array creation and
* manipulation, class adding and class removing, and conditional testing
*/
var aChildren = $("nav li").children(); // find the a children of the list items
var aArray = []; // create the empty aArray
for (var i=0; i < aChildren.length; i++) {
var aChild = aChildren[i];
var ahref = $(aChild).attr('href');
aArray.push(ahref);
} // this for loop fills the aArray with attribute href values
$(window).scroll(function(){
var windowPos = $(window).scrollTop(); // get the offset of the window from the top of page
var windowHeight = $(window).height(); // get the height of the window
var docHeight = $(document).height();
for (var i=0; i < aArray.length; i++) {
var theID = aArray[i];
var divPos = $(theID).offset().top; // get the offset of the div from the top of page
var divHeight = $(theID).height(); // get the height of the div in question
if (windowPos >= divPos && windowPos < (divPos + divHeight)) {
$("a[href='" + theID + "']").addClass("nav-active");
} else {
$("a[href='" + theID + "']").removeClass("nav-active");
}
}
if(windowPos + windowHeight == docHeight) {
if (!$("nav li:last-child a").hasClass("nav-active")) {
var navActiveCurrent = $(".nav-active").attr("href");
$("a[href='" + navActiveCurrent + "']").removeClass("nav-active");
$("nav li:last-child a").addClass("nav-active");
}
}
});

Change url when manually scrolled to an anchor?

By Default, if I have anchors in my website, then the URL on the address bar is changed, when I click on a link (ie. www.mysite.com/#anchor)
Is it possible to change the URL in the address bar instantly when I scroll to an anchor? Or have a long document with multiple anchors and the url changes on address bar, when I hit a new anchor?
Try using this jquery plugin: Scrollorama. It has tons of cool features and you can use window.location.hash to update your browsers hash.
Alternatively, you can add a "scroll" event to check when an anchor is reached.
Here is a working fiddle to illustrate the event: http://jsfiddle.net/gugahoi/2ZjWP/8/
Example:
$(function () {
var currentHash = "#initial_hash"
$(document).scroll(function () {
$('.anchor_tags').each(function () {
var top = window.pageYOffset;
var distance = top - $(this).offset().top;
var hash = $(this).attr('href');
// 30 is an arbitrary padding choice,
// if you want a precise check then use distance===0
if (distance < 30 && distance > -30 && currentHash != hash) {
window.location.hash = (hash);
currentHash = hash;
}
});
});
});
you can use HTML 5 pushstate to change the URL in the address bar
window.history.pushstate
https://developer.mozilla.org/en-US/docs/DOM/Manipulating_the_browser_history
How can I use window.history.pushState 'safely'
Bind a handler to jquery scroll event.
Check if an anchor is currently visible on-screen with this jquery
script.
Use pushstate or set location (probably will cause jumps)
You can bind to the jQuery scroll event (http://api.jquery.com/scroll/) and on each call of the callback called, check how far on the document the user has scrolled by checking this value: .scrollTop (http://api.jquery.com/scrollTop/) and set the anchor by manipulating te location.hash object (http://www.w3schools.com/jsref/prop_loc_hash.asp).
It would be something like this:
// Checks if the passed element is visible on the screen after scrolling
// source: http://stackoverflow.com/questions/487073/check-if-element-is-visible-after-scrolling
function isScrolledIntoView(elem) {
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
$('#document').scroll(function(e) {
var anchors = $('.anchor');
for (var i = 0; i < anchors.length; ++i) {
if (isScrolledIntoView(anchors[i])){
var href = $(anchors[i]).attr('href');
location.hash = href.slice(href.indexOf('#') + 1);
break;
}
}
});
You could be more precise, if you sort the anchors after selecting them, so that the first visible anchor will be set always.
Plain js version
While researching how to update the URL based off positions of HTML section elements on the screen, I kept finding this thread so I hope this is a good place to post this.
This function loops over the HTML section elements.
function updateFragId() {
var len = sections.length;
for (var i = 0; i < len; i++) {
var id = sections[i].id;
Collects the Y scroll position relative to the viewport.
var rect = sections[i].getBoundingClientRect().y;
convert the two arrays into an object
var pageData = {id:id, rect:rect};
set a range for the code to trigger in between. Here it will trigger when the top of the section element is between -200px to 400px
if (pageData.rect > -200 && pageData.rect < 400) {
only run once by making sure the pageData.id and location.hash dont already match. This stops it from flooding your browser with events.
if (pageData.rect > -100 && pageData.rect < 100) {
if (pageData.id !== location.hash.substr(1)) {
fragmentId = pageData.id;
setActiveLink(fragmentId);
} else {
return;
}
}
}
}
window.addEventListener('scroll', updateFragId);
I use a debouncer on this block of code with another block to set the active link. But this is just how to track the # anchors.
I think you need to do something like this. Not tried in action
var myElements = $("div.anchor"); // You target anchors
$(window).scroll(function(e) {
var scrollTop = $(window).scrollTop();
myElements.each(function(el,i) {
if ($(this).offset().top > scrollTop && $(myElements[i+1]).offset().top < scrollTop) {
location.hash = this.id;
}
});
});

Categories

Resources