Basically I've created a single page website and I've used JQuery to create a ScrollTo effect when clicking on different links. Because I have a fixed div at the top of the page, I've offset the target to the height of the fixed div at the top of the page, so that when it scrolls, the contents isn't hidden by the fixed div at the top of the page:
if ($target) {
var targetOffset = $target.offset().top - $("#div_at_top_of_page").outerHeight();
This works fine, scrolling the target div below my fixed navigation at the top of my page. However in Safari, the scroll to already scrolls below the div by default, so adding:
$("#div_at_top_of_page").outerHeight();
this causes Safari to scroll to the target, but also adding the height of the div at the top of the page, creating a margin.
I'm just looking for a solution to cancel this:
$("#div_at_top_of_page").outerHeight()
for Safari only. Any help would be appreciated, thanks!
EDIT: I'm open to any other solutions rather than browser detection.
Here's the complete thing:
$(document).ready(function() {
function filterPath(string) {
return string
.replace(/^\//,'')
.replace(/(index|default).[a-zA-Z]{3,4}$/,'')
.replace(/\/$/,'');
}
$('a[href*=#]').each(function() {
if ( filterPath(location.pathname) == filterPath(this.pathname)
&& location.hostname == this.hostname
&& this.hash.replace(/#/,'') ) {
var $targetId = $(this.hash), $targetAnchor = $('[name=' + this.hash.slice(1) +']');
var $target = $targetId.length ? $targetId : $targetAnchor.length ? $targetAnchor : false;
if ($target) {
var targetOffset = $target.offset().top - $("#fixed_div_at_top").outerHeight();
$(this).click(function(e) {
$('html, body').animate({scrollTop: targetOffset}, 800);
e.preventDefault();
var d = document.createElement();
d.style.height = "101%";
d.style.overflow = "hidden";
document.body.appendChild(d);
window.scrollTo(0,scrollToM);
setTimeout(function() {
d.parentNode.removeChild(d);
}, 10);
return false;
});
}
}
The direct answer to your question is to use $.browser (http://api.jquery.com/jQuery.browser/ -- deprecated long ago and removed in jQuery 1.9), but I can't recommend it. Better to use feature detection. Even better not to rely on either method. Have provided this as an answer only because you initially asked specifically about targeting Safari.
Related
I've got the code below in our boilerplate that seems to work fine in the current setup. It scrolls to the section on the page when you click the navigation menu link or a link in a slick slider. What I found hard to solve is making it work when navigating from another page back to the homepage. It'll add the #discover hash to the url just fine, for example, but it won't register it for some reason.
It's been a while since I properly used jQuery 😅.
I've already added the standard on document ready code around the function hoping it would be that, but no dice. Hope anyone can clue me in about what's happening here.
$(function(){ });
/*
Only enable this when you want smooth scrolling!
Usage:
- Give the anchor you want to scroll to a certain position a href which starts with # and the class "scroll" ()
- Give the container you want to scroll to a name (<section name="container"></section)
- ???
- profit
*/
const scrollOffset = 0 // the amount of pixels the animation should scroll "extra" (When you have a sticky navigation for example)
$(function () {
$(
'.menu__item a[href*="#"]:not([href="#"]), .slider-list__link[href*="#"]:not([href="#"])'
).click(function () {
if (
location.pathname.replace(/^\//, '') ==
this.pathname.replace(/^\//, '') &&
location.hostname == this.hostname
) {
var target = $(this.hash)
target = target.length ? target : $('[name=' + this.hash.slice(1) + ']')
$('body').removeClass('no-scroll')
$('.navbar').removeClass('navbar--is-open')
if (target.length) {
setTimeout(() => { // This is used to prevent the animation from the menu closing from interfering with the scrolling animation. It could mess up the offsets otherwise
$('html, body').animate(
{
scrollTop: target.offset().top + scrollOffset, // Scroll to the target
},
400
)
return false
}, 500)
}
}
})
})
I am using some JavaScript to create a smooth scroll effect to achnor links. The site has a fixed header so the content needs to be offset by whatever the height of the header is (this varies due to #media rules). On top of this when the user is logged in to WordPress the content needs to be offset further by the height of the WP admin bar (again, the height of this vaires depending on screen size).
I have set up two variables in my script to separately get the height of both these elements:
var headerHeight = $('header').height();
var adminbarHeight = $('#wpadminbar').height();
Further on in the script I want to offset the top by the height of the header plus the height of the admin bar if it exists (i.e. if a user is logged in).
$('html, body').animate({scrollTop: target.offset().top - headerHeight - adminbarHeight }, 500,
I am trying to offset by the headerHeight and the adminbarHeight but this is not working for me. If I remove 'adminbarHeight' it works but then it does not look correct for logged in users.
Is there something wrong with my syntax? Or perhaps I need to create an if statement to check if the adminbarHeight is greater than 0?
The full script I am enqueueing in my WP child theme is below:
( function( $ ) {
'use strict';
$('a[href*="#"]')
.not('[href="#"]')
.not('[href="#0"]')
.click(function(event) {
var headerHeight = $('header').height();
var adminbarHeight = $('#wpadminbar').height();
if (
location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '')
&&
location.hostname == this.hostname
) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) + ']');
if (target.length) {
event.preventDefault();
$('html, body').animate({scrollTop: target.offset().top - headerHeight - adminbarHeight }, 500,
function() {
var $target = $(target);
$target.focus();
if ($target.is(":focus")) {
return false;
} else {
$target.attr('tabindex','-1');
$target.focus();
};
});
}
}
});
}( jQuery ) );
Any help will be greatly appreciated! I am new to JavaScript so apologies if this is a really obvious error.
Thanks,
Chris
I have the Html code like below,
<div data-stored="storenow" data-save="save" class="saveIcon" data-unique="game">Save</div>
And I write the jquery to scroll to the gameNo 456 like below.
var container = $("html,body");
var scrollTo = $(this).find('.saveIcon').attr('data-unique', 456);
container.animate({
scrollTop: scrollTo.offset().top - container.offset().top + container.scrollTop()
});
I am using jQuery version 1.9. I am getting error in console:
Cannot read property 'top' of undefined
Is that not possible to scroll to class name instead of id?
But it is working fine in Firefox. But not in chrome or IE.
I try to find the solutions from stackoverflow. But all other solutions are different than my case.
You are not targeting a DOM object, you are targeting a string.
scrollTo = $(this).find('.saveIcon').attr('data-unique', 456); -> this is wrong
So, while you are trying to target an element, you are actually setting the 'data-unique' to the '.saveIcon' element.
Try this:
scrollTo = $('.saveIcon');
Working code:
var $container = $("html,body");
var $scrollTo = $('.saveIcon');
$container.animate({scrollTop: $scrollTo.offset().top - $container.offset().top + $container.scrollTop(), scrollLeft: 0},300);
have you looked at scroll to view function?
https://developer.mozilla.org/en-US/docs/Web/API/element.scrollIntoView
element.scrollIntoView(true);
these two codes worked for me like a charm this first will take to scroll to the top of the page but if you want to scroll to some specific div use the second one with your div id.
$('body, html, #containerDiv').scrollTop(0);
document.getElementById('yourDivID').scrollIntoView();
If you want to scroll to by a class name use the below code
var $container = $("html,body");
var $scrollTo = $('.main-content');
$container.animate({scrollTop: $scrollTo.offset().top - $container.offset().top +
$container.scrollTop(), scrollLeft: 0},300);
I am using following plain js, please try if you can use it in you codes:
$('a.smooth-scroll[href*=#]:not([href=#])').click(function () {
if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) + ']');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top
}, 1000);
return false;
}
}
});
I basically have a div with set dimensions and overflow: hidden. That div contains 7 child divs (but only shows one at a time) that I would like to be smoothly scrolled through vertically when their respective links are hovered.
However, the first section (div) doesn't have a link and is the default section when no link is hovered.
Take a look at this jsFiddle to see a basic structure of what I'm talking about: http://jsfiddle.net/YWnzc/
I've attempted to accomplish this with jQuery scrollTo but haven't been able to get it to work.
Any help would be greatly appreciated. Thanks.
Something like this?
http://jsfiddle.net/YWnzc/5/
code:
jQuery("#nav").delegate("a", "mouseenter mouseleave", function (e) {
var i, self = this,
pos;
if (e.type == "mouseleave") {
i = 0;
}
else {
//Find out the index of the a that was hovered
jQuery("#nav a").each(function (index) {
if (self === this) {
i = index + 1; //the scrollTop is just calculated from this by a multiplier, so increment
return false;
}
});
}
//Find out if the index is a valid number, could be left undefined
if (i >= 0) {
//stop the previous animation, otherwise it will be queued
jQuery("#wrapper").stop().animate({
scrollTop: i * 200
}, 500);
//I would retrieve .offsetTop, but it was reporting false values :/
}
e.preventDefault();
});
FYI : That JSFIDDLE you sent me to went to MooTools framework, not jQuery... fyi. (might be why its not working?
Copy and paste this code exactly and it will work in jQuery for animated scrolling.
Try this for smooth scrolling within the DIV, I tested it - it works great. You
$(function() {
function filterPath(string) {
return string
.replace(/^\//,'')
.replace(/(index|default).[a-zA-Z]{3,4}$/,'')
.replace(/\/$/,'');
}
var locationPath = filterPath(location.pathname);
var scrollElem = scrollableElement('#wrapper');
// 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;
$(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 [];
}
});
FYI : Credit for this code does not go to me as an individual developer, although I did slightly tweak the code. The owner and creator of this code is Chris Coyier and you can find more about this scrolling code here:
http://css-tricks.com/snippets/jquery/smooth-scrolling/
Here's a working example: http://jsfiddle.net/YWnzc/7/
And the code (pretty similar to rizzle's, with a couple changes that I'll explain):
$('a').hover(function(){
var selector = $(this).data('section');
var scrollAmount = $(selector).offset().top + $('#wrapper')[0].scrollTop - 129;
$('#wrapper').animate({scrollTop: scrollAmount}, 250);
},function(){
$('#wrapper').animate({scrollTop: 0}, 250);
});
First, var selector = $(this).data('section'); because in jsFiddle, the href attribute was returning the full path of the page + the hash. So I changed it to an html5 data attribute (data-section).
The next line is similar to rizzle's, except that we grab the offset of the section and add it to the current scrollTop value of the #wrapper. As he pointed out, there are some weird offset issues going on still, and I found that subtracting 129 did the trick. While this 129 number might seem like something that is likely to break, I did test out changing the sizes of the sections, making them not equal, etc, and it continued to work. I'm using Chrome, and perhaps a non-webkit browser would need a different constant to subtract. But it does seem like that 129 number is at least some kind of constant.
The rest should be pretty self-explanatory.
One thing to note: as you move your cursor over the <a> tags, the content of the #wrapper div will seem to jump around, but that's just because the mouseleave part of the hover event briefly gets triggered as the cursor moves. I'm sure you can solve that one though :)
$("#nav a").hover(function () {
var sectionName = $(this).attr("href");
var sectionPos = $(sectionName).offset().top;
var wrapperPos = $("#wrapper").offset().top;
var wrapperScroll = $("#wrapper").scrollTop();
var scrollPos = sectionPos - wrapperPos + wrapperScroll;
$("#wrapper").stop().animate({scrollTop:scrollPos}, 600);
}, function () { $("#wrapper").stop().animate({scrollTop:0}, 600); });
I’d like to make the browser to scroll the page to a given anchor, just by using JavaScript.
I have specified a name or id attribute in my HTML code:
<a name="anchorName">..</a>
or
<h1 id="anchorName2">..</h1>
I’d like to get the same effect as you’d get by navigating to http://server.com/path#anchorName. The page should be scrolled so that the anchor is near the top of the visible part of the page.
function scrollTo(hash) {
location.hash = "#" + hash;
}
No jQuery required at all!
Way simpler:
var element_to_scroll_to = document.getElementById('anchorName2');
// Or:
var element_to_scroll_to = document.querySelectorAll('.my-element-class')[0];
// Or:
var element_to_scroll_to = $('.my-element-class')[0];
// Basically `element_to_scroll_to` just have to be a reference
// to any DOM element present on the page
// Then:
element_to_scroll_to.scrollIntoView();
You can use jQuery's .animate(), .offset() and scrollTop. Like
$(document.body).animate({
'scrollTop': $('#anchorName2').offset().top
}, 2000);
Example link: http://jsbin.com/unasi3/edit
If you don't want to animate, use .scrollTop() like:
$(document.body).scrollTop($('#anchorName2').offset().top);
Or JavaScript's native location.hash like:
location.hash = '#' + anchorid;
2018-2020 Pure JavaScript:
There is a very convenient way to scroll to the element:
el.scrollIntoView({
behavior: 'smooth', // smooth scroll
block: 'start' // the upper border of the element will be aligned at the top of the visible part of the window of the scrollable area.
})
But as far as I understand, it does not have such good support as the options below.
Learn more about the method.
If it is necessary that the element is in the top:
const element = document.querySelector('#element')
const topPos = element.getBoundingClientRect().top + window.pageYOffset
window.scrollTo({
top: topPos, // scroll so that the element is at the top of the view
behavior: 'smooth' // smooth scroll
})
Demonstration example on CodePen
If you want the element to be in the center:
const element = document.querySelector('#element')
const rect = element.getBoundingClientRect() // get rects(width, height, top, etc)
const viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
window.scroll({
top: rect.top + rect.height / 2 - viewHeight / 2,
behavior: 'smooth' // smooth scroll
});
Demonstration example on CodePen
Support:
They write that scroll is the same method as scrollTo, but support shows better in scrollTo.
More about the method.
Great solution by jAndy, but the smooth scroll seems to be having issues working in Firefox.
Writing it this way works in Firefox as well.
(function($) {
$(document).ready(function() {
$('html, body').animate({
'scrollTop': $('#anchorName2').offset().top
}, 2000);
});
})(jQuery);
In 2018, you don't need jQuery for something simple like this. The built in scrollIntoView() method supports a "behavior" property to smoothly scroll to any element on the page. You can even update the browser URL with a hash to make it bookmarkable.
From this tutorial on scrolling HTML Bookmarks, here is a native way to add smooth scrolling to all anchor links on your page automatically:
let anchorlinks = document.querySelectorAll('a[href^="#"]')
for (let item of anchorlinks) { // relitere
item.addEventListener('click', (e)=> {
let hashval = item.getAttribute('href')
let target = document.querySelector(hashval)
target.scrollIntoView({
behavior: 'smooth',
block: 'start'
})
history.pushState(null, null, hashval)
e.preventDefault()
})
}
Here is a pure JavaScript solution without jQuery. It was tested on Chrome and Internet Explorer, but not tested on iOS.
function ScrollTo(name) {
ScrollToResolver(document.getElementById(name));
}
function ScrollToResolver(elem) {
var jump = parseInt(elem.getBoundingClientRect().top * .2);
document.body.scrollTop += jump;
document.documentElement.scrollTop += jump;
if (!elem.lastjump || elem.lastjump > Math.abs(jump)) {
elem.lastjump = Math.abs(jump);
setTimeout(function() { ScrollToResolver(elem);}, "100");
} else {
elem.lastjump = null;
}
}
Demo: https://jsfiddle.net/jd7q25hg/12/
The easiest way to to make the browser to scroll the page to a given anchor is to add *{scroll-behavior: smooth;} in your style.css file and in your HTML navigation use #NameOfTheSection.
*{scroll-behavior: smooth;}
<a href="#scroll-to">Click to Scroll<a/>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<section id="scroll-to">
<p>it will scroll down to this section</p>
</section>
Smoothly scroll to the proper position
Get correct y coordinate and use window.scrollTo({top: y, behavior: 'smooth'})
const id = 'anchorName2';
const yourElement = document.getElementById(id);
const y = yourElement.getBoundingClientRect().top + window.pageYOffset;
window.scrollTo({top: y, behavior: 'smooth'});
$(document).ready ->
$("a[href^='#']").click ->
$(document.body).animate
scrollTop: $($(this).attr("href")).offset().top, 1000
The solution from CSS-Tricks no longer works in jQuery 2.2.0. It will throw a selector error:
JavaScript runtime error: Syntax error, unrecognized expression: a[href*=#]:not([href=#])
I fixed it by changing the selector. The full snippet is this:
$(function() {
$("a[href*='#']:not([href='#'])").click(function() {
if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top
}, 1000);
return false;
}
}
});
});
This works:
$('.scroll').on("click", function(e) {
e.preventDefault();
var dest = $(this).attr("href");
$("html, body").animate({
'scrollTop': $(dest).offset().top
}, 2000);
});
https://jsfiddle.net/68pnkfgd/
Just add the class 'scroll' to any links you wish to animate
Most answers are unnecessarily complicated.
If you just want to jump to the target element, you don't need JavaScript:
# the link:
Click here to jump.
# target element:
<div id="target">Any kind of element.</div>
If you want to scroll to the target animatedly, please refer to 5hahiL's answer.
jQuery("a[href^='#']").click(function(){
jQuery('html, body').animate({
scrollTop: jQuery( jQuery(this).attr('href') ).offset().top
}, 1000);
return false;
});
This is a working script that will scroll the page to the anchor.
To set it up, just give the anchor link an id that matches the name attribute of the anchor that you want to scroll to.
<script>
jQuery(document).ready(function ($){
$('a').click(function (){
var id = $(this).attr('id');
console.log(id);
if ( id == 'cet' || id == 'protein' ) {
$('html, body').animate({ scrollTop: $('[name="' + id + '"]').offset().top}, 'slow');
}
});
});
</script>
I found an easy and simple jQuery solution on CSS-Tricks. That's the one I'm using now.
$(function() {
$('a[href*=#]:not([href=#])').click(function() {
if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top
}, 1000);
return false;
}
}
});
});
A Vue.js 2 solution ... add a simple data property to simply force the update:
const app = new Vue({
...
, updated: function() {
this.$nextTick(function() {
var uri = window.location.href
var anchor = ( uri.indexOf('#') === -1 ) ? '' : uri.split('#')[1]
if ( String(anchor).length > 0 && this.updater === 'page_load' ) {
this.updater = "" // only on page-load !
location.href = "#"+String(anchor)
}
})
}
});
app.updater = "page_load"
/* Smooth scrolling in CSS - it works in HTML5 only */
html, body {
scroll-behavior: smooth;
}