I am using bootstrap's scrollspy to change the navbar item highlighting on page scroll, and then using history.replaceState to add the hash to the url. This question gave me the idea for that part. I also use some jquery to implement a 'smooth scroll' when a navigation item is clicked and I turn the scrollspy off while 'smooth scrolling' down to the anchor, then add the hash to the url and turn scrollspy back on.
The scrollspy part is working fine, the problem comes when clicking on a navigation link. It works as expected in Chrome and Firefox, but in IE 10 & 11 it adds undefined before the hash in the url when clicking on a link and I can't work out why.
Here's my script:
//initiate scroll spy
$('body').scrollspy({ target: '.spy-active', offset: $offset + 1 });
$('.spy-active').on('activate.bs.scrollspy', function (e) {
if (history.replaceState) {
history.replaceState(null, "", $('a[href*=#]:not([href=#])', e.target).attr("href"));
}
});
//smooth scroll
$('a[href*=#]:not([href=#])').click(function (e) {
e.preventDefault();
//deactivate scrollspy for duration of transition
$('nav').removeClass('spy-active');
//remove active class from all list items
$('li').each(function () {
$(this).removeClass('active');
});
//add active class to clicked item
$(this).parent().addClass('active');
var target = this.hash;
var $target = $(target);
$('html, body').stop().animate({
'scrollTop': $target.offset().top - $offset
}, 500, 'swing', function () {
if (history.replaceState) {
history.replaceState(null, "", target);
}
//reactivate scrollspy
$('nav').addClass('spy-active');
});
});
my site is here
This line is executed in IE right when you click on a navigation link:
history.replaceState(null, "", $('a[href*=#]:not([href=#])', e.target).attr("href"));
If no links are found inside e.target the result for .attr("href") is undefined. So you'll need to check if the link is found and then call history.replaceState:
var matchLink = $('a[href*=#]:not([href=#])', e.target);
if(matchLink.length) {
history.replaceState(null, "", matchLink.attr("href"));
}
Related
I am using this code to a wordpress paid theme (Gavick - Creativity) and it uses the code below:
jQuery(document).ready(function () {
// SmoothScroll jQUery substitue
jQuery('a[href^="#"]').click(function (e) {
e.preventDefault();
var target = this.hash,
$target = jQuery(target);
if ($target.length) {
jQuery('html, body').stop().animate({
'scrollTop': $target.offset().top + 150
//'scrollTop': $target.offset().top ORIGINAL
}, 1000, 'swing', function () {
window.location.hash = target+150;
//window.location.hash = target; ORIGINAL
});
} else {
window.location.hash = target;
// window.location.hash = target; ORIGINAL
}
});
The thing is that it smooth scrolls only from internal links and not from external.
When I am at the same page and click on an anchor link it scrolls perfectly.
Visiting the page anchor from another page doesn't scroll at all.
All I need is to visit http://domain.com/#anchortag and scroll to it from the start of the page.
I also need to be able to have different offsets if I am in the same page or in an external one.
Any help?
Well first thing
Visiting the page anchor from another page doesn't scroll at all.
You can make a jQuery function to check for that case:
function checkForAnchor() {
var pathname = jQuery(location).attr('href');
pathname = pathname.split("#");
for(var i = 0; i < pathname.length; i++){
if(pathname[i] == 'YOUR ANCHOR'){
jQuery('html, body').animate({ scrollTop: (jQuery('.YOUR CONTAINER TO SCROLL TO').offset().top)}, 'slow');
}
}
}
I also need to be able to have different offsets if I am in the same page or in an external one.
Therefore you may use a cookie. When the user visits your page first and there is no cookie you can use another offset to scroll to. After that set a cookie and use a different offset.
The website I'm working on: zarwanhashem.com
You can find my previous question (which includes my code) here: Bootstrap one page website themev formatting problems
The selected answer solved my issues but I have another problem because of the jQuery adjustment with the -50. Now the navbar incorrectly indicates the page I am on. i.e. The navbar is supposed to darken the section that you are currently in. So if you click "about" it will take you to the about page and darken the about link in the navbar. But the link BEFORE the page you are on is highlighted because the -50 makes the navbar think that it is on the previous section. You can easily try this to see what I mean.
How can I fix this? Thanks. The reason I didn't add this onto my old question is because the person stopped looking at it.
Also please keep your explanations simple/dumb them down a little for me. I know very basic HTML and CSS, and I don't know any Javascript.
scrolling js:
//jQuery to collapse the navbar on scroll
$(window).scroll(function() {
if ($(".navbar").offset().top > 50) {
$(".navbar-fixed-top").addClass("top-nav-collapse");
} else {
$(".navbar-fixed-top").removeClass("top-nav-collapse");
}
});
//jQuery for page scrolling feature - requires jQuery Easing plugin
$(function() {
$('a.page-scroll').bind('click', function(event) {
var $anchor = $(this);
$('html, body').stop().animate({
scrollTop: $($anchor.attr('href')).offset().top -50
}, 1500, 'easeInOutExpo');
event.preventDefault();
});
});
js added at end of document as suggested by poster in previous question:
$(window).ready(function(){
$('div[class^="content-section"]').css('min-height', $(window).height());
})
You are putting the .active class on the wrong element somehow. You need to put the .active class on the clicked element. You should handle the active state with js. This is my solution based on your HTML structure but I'm sure there are different solutions as well.
$(document).on('click', '.page-scroll', function(event) {
var clicked = event.target; //get the clicked element
if($(clicked).closest('ul').hasClass('dropdown-menu')){ //check if clicked element is inside dropdown
$(clicked).closest('ul').parent().siblings().removeClass('active'); //remove active class from all
$(clicked).closest('ul').parent().addClass('active'); add active class on clicked element parent - in your case <li> tag.
}else{
$(clicked).parent().siblings().removeClass('active');
$(clicked).parent().addClass('active');
}
}
Let me know if this works for you.
EDIT after you posted your code
Try replacing your function with this:
$(function() {
$('a.page-scroll').bind('click', function(event) {
var $anchor = $(this);
$('html, body').stop().animate({
scrollTop: $($anchor.attr('href')).offset().top -50
}, 1500, 'easeInOutExpo');
if($($anchor).closest('ul').hasClass('dropdown-menu')){
$($anchor).closest('ul').parent().siblings().removeClass('active');
$($anchor).closest('ul').parent().addClass('active');
}else{
$($anchor).parent().siblings().removeClass('active');
$($anchor).parent().addClass('active');
}
event.preventDefault();
});
});
here is a work around this problem.
just change the contents of your scrolling-nav.js to the following:
//jQuery to collapse the navbar on scroll
$(window).scroll(function() {
if ($(".navbar").offset().top > 50) {
$(".navbar-fixed-top").addClass("top-nav-collapse");
} else {
$(".navbar-fixed-top").removeClass("top-nav-collapse");
}
});
//jQuery for page scrolling feature - requires jQuery Easing plugin
$(function() {
$('a.page-scroll').bind('click', function(event) {
var $anchor = $(this);
$('html, body').stop().animate({
scrollTop: $($anchor.attr('href')).offset().top -50
}, 1500, 'easeInOutExpo', function(){
$('ul.navbar-nav li, ul.dropdown-menu li').removeClass('active');
$($anchor).parent('li').addClass('active');
});
event.preventDefault();
});
});
I was looking through answers for creating next and prev buttons that go through anchor points on a page, but couldn't find something I need. This one might of been close to what I wanted so I decided to use it as a starting point: How can I make a link go to the next anchor on the page without knowing anchor name?
I created a fiddle with the concept presented in that answer and tried to make it work together with bootstrap's scrollspy (detects the current section and anchor).
I have gotten this far: http://jsfiddle.net/gukne0oL/2/
$('.next').click(function (e) {
e.preventDefault();
var current_anchor = $('li.active a');
var next_anchor = current.next('li a');
$('body').animate({
scrollTop: next_anchor.offset().top
});
})
$('.previous').click(function (e) {
e.preventDefault();
var current_anchor = $('li.active a');
var previous_anchor = current.prev('li a');
$('body').animate({
scrollTop: previous_anchor.offset().top
});
})
The original answer targets the <a> tag, but in bootstrap's scrollspy, it adds the active class to the <li> tag wrapping the <a> tag. So I changed it accordingly... I feel like it's close? but I can't tell...
Can anyone help? Thank you!
Target active li, find the previous/next li, and drill down to the anchor.
http://jsfiddle.net/gukne0oL/9/
// Activate bootstrap scrollspy
$('body').scrollspy({
target: '.navbar'
})
$('.next').click(function (e) {
var next = $('.navbar ul li.active').next().find('a').attr('href');
$('html, body').animate({
scrollTop: $(next).offset().top
}, 500);
})
$('.previous').click(function (e) {
var prev = $('.navbar ul li.active').prev().find('a').attr('href');
$('html, body').animate({
scrollTop: $(prev).offset().top
}, 500);
})
On my homepage I have a menu with ID's, when I click it, it slides to the corresponding div and it works smoot.
But when I'm not on my homepage and I click an item I want to be able to go to the homepage and then slide to the section.
Here is the code I'm using now:
$('#mainMenu a').click(function(e){
e.preventDefault();
var div = $(this).attr('href');
if('<?=get_site_url()?>/' == '<?=get_permalink()?>')
{
$('html, body').animate({scrollTop:$(div).position().top}, 'slow');
}
else
{
window.location.href = '<?=get_site_url()?>/'+div;
}
});
This works excellent, the next part works to but I can't get it to slide to the ID.
if (window.location.hash != "") {
e.preventDefault();
$('html, body').animate({scrollTop:$(window.location.hash).position().top}, 'slow');
}
Is there a way I can prevent the browser from directly jumping to the section and instead sliding to it?
Try to scroll to top right at the start, then roll down:
if (window.location.hash != "") {
$('html, body').scrollTop(0).animate({scrollTop:$(window.location.hash).position().top}, 'slow');
}
Also, remove e.preventDefault(), since you're not defining any variable named e nor an event.
This works like a charm:
$('#mainMenu a').click(function(e){
e.preventDefault();
var div = $(this).attr('href');
if('<?=get_site_url()?>/' == '<?=get_permalink()?>')
{
$('html, body').animate({scrollTop:$(div).position().top}, 'slow');
}
else
{
localStorage.setItem("hash", div);
window.location.href = '<?=get_site_url()?>/';
}
});
if (localStorage.getItem("hash")!=null) {
$('html, body').animate({scrollTop:$(localStorage.getItem("hash")).position().top}, 'slow');
localStorage.removeItem("hash");
}
Instead of putting the hash in my url I stored it in localStorage and in my head of the page I checked if it was set.
Founded this solution just a few minutes after posting the question, thanks to those who helped me :)
I'm using this for my scroll transition between a top and bottom div:
<script type="text/javascript">
$('a').on('click', function (event) {
event.preventDefault();//stop the browser from jumping to the anchor
var href = $(this).attr('href'),
oset = $(href).offset().top;
$('html, body').stop().animate({
scrollTop : oset
}, 1000, function () {
location.hash = href;
});
});
</script>
But it's conflicting with how I'm using fancybox as it's using 'href', I've tried defining the 'div ids' in place and creating a shared class (eg .smooth and called in both links) but it just broke. How can I use this specifing only two divs for it to apply to?
Question spawning from - https://stackoverflow.com/questions/8547378/fancybox-with-iframe-js-conflictions-with-my-site-wont-implement
Change this:
$('#menu a').on('click', function (event) {
event.preventDefault();//stop the browser from jumping to the anchor
var href = $(this).attr('href'),
oset = $(href).offset().top;
$('html, body').stop().animate({
scrollTop : oset
}, 1000, function () {
location.hash = href;
});
});
There is no point in scrolling when 'Gallery' is clicked and opens fancybox.