had a google....
Tried changing my website scroll settings & nothing is happening.
Anyone have a write up or table on mouse scroll jQuery scripts and functions?
(Caches were cleared, cross browser test etc.)
jQuery(window).load(function(){
if(checkBrowser() == 'Google Chrome' && device.windows()){
if (window.addEventListener) window.addEventListener('DOMMouseScroll', wheel, false);
window.onmousewheel = document.onmousewheel = wheel;
var time = 330;
var distance = 300;
function wheel(event) {
if (event.wheelDelta) delta = event.wheelDelta / 90;
else if (event.detail) delta = -event.detail / 3;
handle();
if (event.preventDefault) event.preventDefault();
event.returnValue = false;
}
function handle() {
jQuery('html, body').stop().animate({
scrollTop: jQuery(window).scrollTop() - (distance * delta)
}, time);
}
}
});
function checkBrowser(){
var ua = navigator.userAgent;
if (ua.search(/MSIE/) > 0) return 'Internet Explorer';
if (ua.search(/Firefox/) > 0) return 'Firefox';
if (ua.search(/Opera/) > 0) return 'Opera';
if (ua.search(/Chrome/) > 0) return 'Google Chrome';
if (ua.search(/Safari/) > 0) return 'Safari';
if (ua.search(/Konqueror/) > 0) return 'Konqueror';
if (ua.search(/Iceweasel/) > 0) return 'Debian Iceweasel';
if (ua.search(/SeaMonkey/) > 0) return 'SeaMonkey';
if (ua.search(/Gecko/) > 0) return 'Gecko';
return 'Search Bot';
}
The script looks a bit outdated. The .load() function isn't used like that anymore and browser sniffing is deprecated as well. An approach with the mousewheel plugin (a real gem) would be more reliable and future proof. Here's a script that uses it, making the function itself quite compact :
http://codepen.io/anon/pen/KpPdmX?editors=001
jQuery(window).on('load', function() {
var time = 330;
var distance = 300;
jQuery(this).mousewheel(function(turn, delta) {
jQuery('html, body').stop().animate({
scrollTop: jQuery(window).scrollTop()-(distance*delta)
}, time);
return false;
});
});
// mousewheel.js can be placed here, outside of function scope
It needs a bit of extra script with that plugin but it is well worth it. There also is a wheel event but unfortunately this is still not supported by Opera. In any case, more code would be needed to normalise the delta of the mousewheel turns (this is where mousewheel.js is at it's best).
I'm guessing the $ character is reserved on the web page but if not, the jQuery references could be replaced with it. By the way - you might want to check which version of jQuery is linked to on the site... if there are any other scripts depending on deprecated features (not that there are too many), some things might stop functioning correctly when it is updated. The .on method was introduced in version 1.8 - if you'd like to stick with an older version the above script would need a minor rewrite.
add this function in you script tag
and add data-scroll-speed="10" in your body tag. you can adjust the scroller speed of body
$(function () {
var boxes = $('[data-scroll-speed]'),
$window = $(window);
$window.on('scroll', function () {
var scrollTop = $window.scrollTop();
boxes.each(function () {
var $this = $(this),
scrollspeed = parseInt($this.data('scroll-speed')),
val = -(scrollTop / scrollspeed);
$this.css('transform', 'translateY(' + val + 'px)');
});
});
})
example: fiddled here
check weather this is what you wanted
Related
I found many questions regarding the cross bowser behaviour of $('html, body').animate();, but for some reason I couldn't find an answer for this one:
I want to (finally) remove $.browser, but at the same moment don't want the scroll event to be triggered twice again, which will happen in some browsers if the selector is $('html, body)
// animte page scrolling
pageScroll : function( scrollTo, speed, callback ) {
var rootElem;
scrollTo = scrollTo || 0;
speed = speed || 800;
if ( $.browser.webkit ) {
rootElem = $('body');
} else {
rootElem = $('html');
}
rootElem
.stop()
.animate(
{
scrollTop: scrollTo
}, speed, callback
);
}
I've looked into this for quite a while and haven't found a real solution other than a check on doc ready :
http://codepen.io/anon/pen/yyddER?editors=011
var mainelement;
$('html, body').animate({scrollTop: 1}, 1, function() {
if ($('html').scrollTop()) mainelement = $('html'); // FF and IE
if ($('body').scrollTop()) mainelement = $('body'); // Chrome, Safari and Opera
mainelement.scrollTop(0);
});
Assuming here the content is high enough to create a scrollbar...
Tested on the major browsers and works without a hitch.
Edit - a variation to make sure the trigger to scroll the page back is only acted upon a single time if the browser uses <html> as the main element for overflow :
var mainelement, tested = false;
$('html, body').animate({scrollTop: 1}, 1, function() {
if ($('html').scrollTop()) mainelement = $('html');
else if ($('body').scrollTop()) mainelement = $('body');
if (!tested) {
tested = true;
mainelement.scrollTop(0);
}
});
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
And later came up with this approach as well (which seems to be the most efficient) :
http://codepen.io/anon/pen/NPQNEr?editors=001
var mainelement;
$(window).scrollTop(1);
if ($('html').scrollTop()) mainelement = $('html');
else if ($('body').scrollTop()) mainelement = $('body');
mainelement.scrollTop(0);
This is the code I use in production; works just fine:
function ScrollPage(TheTop) {
TheTop = parseInt(TheTop, 10);
if (!$.isNumeric(TheTop)) {
return;
}
$('html,body').animate({ scrollTop: TheTop }, 400);
}
If the problem is that the event handler is firing twice then it means the function is somehow called twice, and that the bug is therefore elsewhere. On another note, the $.browser() function has been deprecated for a while.
This is my current code: http://jsfiddle.net/spadez/9sLGe/3/
I am concerned that it will be very laggy doing this because it's monitoring scroll. I saw mention on my other question of debouncing a bit like this:
var scrollTimeout,
callback = function () {
/// Do your things here
};
$(window).scroll(function () {
if (scrollTimeout)
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(callback, 40);
});
Can anyone tell me if this is a good idea and how it might be integrated.
James
For smooth results, I would stick with this firing on every scroll event. Otherwise there would be a delay before sticking or unsticking.
However, you can improve the performance of your function by caching the jQuery collections, and only sticking / unsticking if needed.
Here's a simple example module using your code: http://jsfiddle.net/9sLGe/9/
(function() {
var $select = $('#select');
var $window = $(window);
var isFixed = false;
var init = $('#select').offset().top;
$window.scroll(function() {
var currentScrollTop = $window.scrollTop();
if (currentScrollTop > init && isFixed === false) {
isFixed = true;
$select.css({
top: 0,
position: 'fixed'
});
console.log("fixed");
} else if (currentScrollTop <= init && isFixed === true) {
isFixed = false;
$select.css('position', 'relative');
console.log("unfixed");
}
});
}());
The main issue is not really one of rapid-firing events (although debouncing will certainly help, at the cost of a slight lack of responsiveness/immediateness), but more of one that you are changing CSS properties every single time the event fires.
You should consider having a flag like "isStickified", and use your if condition to change that flag. If, and only if, the flag changes, that is when you should set the CSS to update. This will be much more efficient.
Basically what I want to do is when I scroll up, zoom into my table, making it larger and when I scroll down, zoom out of the table, making it smaller.
Here is the js
var mainGridW = $("#mainGrid").width();
var mainGridH = $("#mainGrid").height();
function setupMouseWheel(){
if (zoomContainer.addEventListener) {
zoomContainer.addEventListener('DOMMouseScroll', onMouseWheelSpin, false);
zoomContainer.addEventListener('mousewheel', onMouseWheelSpin, false); // Chrome
}else{
zoomContainer.onmousewheel= onMouseWheelSpin;
}
}
function onMouseWheelSpin(event) {
var nDelta = 0;
if (!event) { event = window.event; }
// cross-bowser handling of eventdata to boil-down delta (+1 or -1)
if ( event.wheelDelta ) { // IE and Opera
nDelta= event.wheelDelta;
if ( window.opera ) { // Opera has the values reversed
nDelta= -nDelta;
}
}
else if (event.detail) { // Mozilla FireFox
nDelta= -event.detail;
}
if (nDelta > 0) {
HandleMouseSpin( 1, event.clientX, event.clientY );
}
if (nDelta < 0) {
HandleMouseSpin( -1, event.clientX, event.clientY );
}
if ( event.preventDefault ) { // Mozilla FireFox
event.preventDefault();
}
event.returnValue = false; // cancel default action
}
function HandleMouseSpin(delta, x, y) {
if (delta < 0){
mainGridW = mainGridW/1.10;
mainGridH = mainGridH/1.10;
$("#mainGrid").width(mainGridW);
$("#mainGrid").height(mainGridH);
}
if(delta > 0){
mainGridW = mainGridW*1.10;
mainGridH = mainGridH*1.10;
$("#mainGrid").width(mainGridW);
$("#mainGrid").height(mainGridH);
}
}
Here is the html
<body onload="setupMouseWheel();">
<div id="zoomContainer">
<table id="mainGrid" height="100%" width="100%" cellpadding="0" cellspacing="0"></table>
</div>
</body>
This all works, except one problem... In firefox there is a lag before it will work. When I try to scroll it says "not responding" for a few seconds then after it starts to respond again it will work but very slowly. Any ideas? Thanks in advance.
There is lag because onMouseWheelSpin is called repeatedly and too fast. Firefox is not as powerful as webkit browser like Chrome, Safari. To resolve this, you can implement a timer to reduce the work.
var timer;
function onMouseWheelSpin(event) {
if (timer) clearTimeout(timer);
timer = setTimeout(function(){
//your code here
}, 30); //delay
}
And also $("#mainGrid") can be converted to document.getElementById('mainGrid') and .width() with .style.width
When doing animation, native code is always faster than jQuery. By using jQuery, you are trading write less with performance.
I think the 2 events you attached above nearly execute at the same time, thus more lag. When you use a mouse wheel, your page is scrolled. Using a clearTimeout(timer) will prevent the previous call to be terminated
I have a single page site:
http://chiaroscuro.telegraphbranding.com/
Each section is dynamically sized based on the user's window. I'm trying to figure out how to have a jQuery smooth scroll function scroll to the top of each section when the link is clicked. It is working great for the first section, funding areas, where I just used a simple offset().top, but the others are not working because they don't know how far to scroll because the window size is always different.
I've been trying to get offset() or position() to work, but no dice. I appreciate any advice.
Here's my jQuery:
`
$(document).ready(function () {
var slowScrollFunding = $('#funding-areas').offset().top;
var slowScrollAbout = $('#about-us').offset().top;
var slowScrollProjects = $('#our-projects').offset().top + 600;
panelOpen = true;
$('#anchor-funding-areas').click(function(event) {
event.preventDefault();
if(panelOpen == true) {
$('#slide-panel-content').stop(true, true).animate({height: '0px'}, 600, function() {
$('#panel-content-container').hide();
$('.scrollableArea').css('z-index', '11');
// Scroll down to 'slowScrollTop'
$('html, body, #home-wrap').animate({scrollTop:slowScrollFunding}, 1000);
panelOpen = false;
});
}else{
$('html, body, #home-wrap').animate({scrollTop:slowScrollFunding}, 1000);
};
});
$('#anchor-aboutus').click(function(event) {
event.preventDefault();
if(panelOpen == true) {
$('#slide-panel-content').stop(true, true).animate({height: '0px'}, 600, function() {
$('#panel-content-container').hide();
$('.scrollableArea').css('z-index', '11');
// Scroll down to 'slowScrollTop'
$('html, body, #aboutus-wrap').animate({scrollTop:slowScrollAbout}, 1000);
panelOpen = false;
});
}else{
$('html, body, #home-wrap').animate({scrollTop:slowScrollAbout}, 1000);
};
});
$('#anchor-ourprojects').click(function(event) {
event.preventDefault();
if(panelOpen == true) {
$('#slide-panel-content').stop(true, true).animate({height: '0px'}, 600, function() {
$('#panel-content-container').hide();
$('.scrollableArea').css('z-index', '11');
// Scroll down to 'slowScrollTop'
$('html, body, #home-wrap').animate({scrollTop:slowScrollProjects}, 1000);
panelOpen = false;
});
}else{
$('html, body, #home-wrap').animate({scrollTop:slowScrollProjects}, 1000);
};
});
$('#header-logo').add('.homelink').click(function() {
if(panelOpen == false) {
$('.scrollableArea').css('z-index', '0');
$('#panel-content-container').show();
$('#slide-panel-content').stop(true, true).animate({height: '389px'}, 600, function() {
// Scroll down to 'slowScrollTop'
panelOpen = true;
});
};
});
});
`
$.offset and $.position can be a little unreliable, especially if you have lots of complicated layouts going on - as your page does. What I've used in the past is the following trick:
var de = document.documentElement ? document.documentElement : document.body;
var elm = $('get_your_anchor_element').get(0);
var destScroll, curScroll = de.scrollTop;
/// check for the function scrollIntoView
if ( elm.scrollIntoView ) {
/// get the browser to scrollIntoView (this wont show up yet)
elm.scrollIntoView();
/// however the new scrollTop is calculated
destScroll = de.scrollTop;
/// then set the scrollTop back to where we were
de.scrollTop = curScroll;
/// you now have your correct scrollTop value
$(de).animate({scrollTop:destScroll});
}
else {
/// most browsers support scrollIntoView so I didn't bother
/// with a fallback, but you could just use window.location
/// and jump to the anchor.
}
The above can occur on the click event. The only thing that needs to be improved is that different browsers scroll on different base elements (body or html). When I used this I had my own element that was scrollable so I didn't need to work out which one the agent was using... When I get a second I'll see if I can find a good bit of code for detecting the difference.
The above has worked in all the modern browsers I've tested (Firefox, Safari, Chrome) however I didn't need to support Internet Explorer so I'm not sure with regard to that.
update:
I'm not quite sure what is going on with your implementation - it is possible that the page is so heavy with content that you actually can see the .scrollIntoView() happening - this has never been my experience, but then I didn't have so much going on on-screen. With that in mind, I've implemented a bare bones system that I would advise you use and build each extra part you need into it:
http://pebbl.co.uk/stackoverflow/13035183.html
That way you know you have a working system to start with, and will easily detect what it is that stops it from working. With regards to chiaro.js your implementation seems to be ok - if a little exploded over many different areas of the file - however this part is slightly erroneous:
$('#anchor-aboutus').click(function() {
event.preventDefault();
if(panelOpen == true) {
$('#slide-panel-content')
.stop(true, true)
.animate({height: '0px'}, 600, function() {
$('#panel-content-container').hide();
$('.scrollableArea').css('z-index', '11');
elm.scrollIntoView(true)
.animate({scrollTop:destScroll}, 1000);
panelOpen = false;
});
}else{
elm.scrollIntoView(true).animate({scrollTop:destScroll});
};
});
In the code above you will only get the correct value of destScroll if panelOpen === true. Ahh, actually I've also spotted another problem - which will explain why it's not working:
elm.scrollIntoView(true)
.animate({scrollTop:destScroll}, 1000);
The above code is mixing pure JavaScript and jQuery, the elm var is a normal DOM element (this supports the scrollIntoView method). But you are then attempting to chain the animate method of jQuery into the mix - you should also be triggering the animate method on the element responsible for the scrollbar. What you should use is as follows:
$('#anchor-aboutus').click(function(e) {
var currentScroll, destScroll;
e.preventDefault();
if(panelOpen == true) {
$('#slide-panel-content')
.stop(true, true)
.animate({height: '0px'}, 600, function() {
$('#panel-content-container').hide();
$('.scrollableArea').css('z-index', '11');
currentScroll = de.scrollTop;
elm.scrollIntoView(true);
destScroll = de.scrollTop;
de.scrollTop = currentScroll;
$(de).animate({scrollTop:destScroll}, 1000);
panelOpen = false;
});
}else{
currentScroll = de.scrollTop;
elm.scrollIntoView(true);
destScroll = de.scrollTop;
de.scrollTop = currentScroll;
$(de).animate({scrollTop:destScroll}, 1000);
};
});
However, what you will also need to do is make sure your de element points to the right element - either html or body depending on the browser - for this you can use this:
var de;
/// calculate which element is the scroller element
$('body, html').each(function(){
if ( this.scrollHeight > this.offsetHeight ) {
de = this;
return false;
}
});
alert( $(de).is('body') ) /// will be true for Chrome, false for Firefox.
You will need to use this code in place of the following code:
var de = document.documentElement ? document.documentElement : document.body;
The reason for changing the code you were using is as follows:
/// store the current scroll position from the de element
currentScroll = de.scrollTop;
/// get the browser to do the scrollTo calculation
elm.scrollIntoView(true);
/// store where the browser scrolled to behind the scenes
destScroll = de.scrollTop;
/// reset our scroll position to where we were before scrollIntoView()
/// if you don't reset then the animation will happen instantaneously
/// because that is what scrollIntoView does.
de.scrollTop = currentScroll;
/// wrap the normal dom element de with jquery and then animate
$(de).animate({scrollTop:destScroll}, 1000);
I'd like to set something up on my site where when you scroll within 15% of the bottom of the page an element flyouts from the side... I'm not sure how to get started here... should I add a listener for a scroll function or something?
I'm trying to recreate the effect at the bottom of this page: http://www.nytimes.com/2011/01/25/world/europe/25moscow.html?_r=1
update
I have this code....
console.log(document.body.scrollTop); //shows 0
console.log(document.body.scrollHeight * 0.85); //shows 1038.7
if (document.body.scrollTop > document.body.scrollHeight * 0.85) {
console.log();
$('#flyout').animate({
right: '0'
},
5000,
function() {
});
}
the console.log() values aren't changing when I scroll to the bottom of the page. The page is twice as long as my viewport.
[Working Demo]
$(document).ready(function () {
var ROOT = (function () {
var html = document.documentElement;
var htmlScrollTop = html.scrollTop++;
var root = html.scrollTop == htmlScrollTop + 1 ? html : document.body;
html.scrollTop = htmlScrollTop;
return root;
})();
// may be recalculated on resize
var limit = (document.body.scrollHeight - $(window).height()) * 0.85;
var visible = false;
var last = +new Date;
$(window).scroll(function () {
if (+new Date - last > 30) { // more than 30 ms elapsed
if (visible && ROOT.scrollTop < limit) {
setTimeout(function () { hide(); visible = false; }, 1);
} else if (!visible && ROOT.scrollTop > limit) {
setTimeout(function () { show(); visible = true; }, 1);
}
last = +new Date;
}
});
});
I know this is an old topic, but the above code that received the check mark was also triggering the $(window).scroll() event listener too many times.
I guess twitter had this same issue at one point. John Resig blogged about it here: http://ejohn.org/blog/learning-from-twitter/
$(document).ready(function(){
var ROOT = (function () {
var html = document.documentElement;
var htmlScrollTop = html.scrollTop++;
var root = html.scrollTop == htmlScrollTop + 1 ? html : document.body;
html.scrollTop = htmlScrollTop;
return root;
})();
// may be recalculated on resize
var limit = (document.body.scrollHeight - $(window).height()) * 0.85;
var visible = false;
var last = +new Date;
var didScroll = false;
$(window).scroll(function(){
didScroll = true;
})
setInterval(function(){
if(didScroll){
didScroll = false;
if (visible && ROOT.scrollTop < limit) {
hideCredit();
visible = false;
} else if (!visible && ROOT.scrollTop > limit) {
showCredit();
visible = true;
}
}
}, 30);
function hideCredit(){
console.log('The hideCredit function has been called.');
}
function showCredit(){
console.log('The showCredit function has been called.');
}
});
So the difference between the two blocks of code is when and how the timer is called. In this code the timer is called off the bat. So every 30 millaseconds, it checks to see if the page has been scrolled. if it's been scrolled, then it checks to see if we've passed the point on the page where we want to show the hidden content. Then, if that checks true, the actual function then gets called to show the content. (In my case I've just got a console.log print out in there right now.
This seems to be better to me than the other solution because the final function only gets called once per iteration. With the other solution, the final function was being called between 4 and 5 times. That's got to be saving resources. But maybe I'm missing something.
bad idea to capture the scroll event, best to use a timer and every few milliseconds check the scroll position and if in the range you need then execute the necessary code for what you need
Update: in the past few years the best practice is to subscribe to the event and use a throttle avoiding excessive processing https://lodash.com/docs#throttle
Something like this should work:
$(window).scroll(function() {
if (document.body.scrollTop > document.body.scrollHeight * 0.85) {
// flyout
}
});
document.body.scrollTop may not work equally well on all browsers (it actually depends on browser and doctype); so we need to abstract that in a function.
Also, we need to flyout only one time. So we can unbind the event handler after having flyed out.
And we don't want the flyout effect to slow down scrolling, so we will run our flytout function out of the event loop (by using setTimeout()).
Here is the final code:
// we bind the scroll event, with the 'flyout' namespace
// so we can unbind easily
$(window).bind('scroll.flyout', (function() {
// this function is defined only once
// it is private to our event handler
function getScrollTop() {
// if one of these values evaluates to false, this picks the other
return (document.documentElement.scrollTop||document.body.scrollTop);
}
// this is the actual event handler
// it has the getScrollTop() in its scope
return function() {
if (getScrollTop() > (document.body.scrollHeight-$(window).height()) * 0.85) {
// flyout
// out of the event loop
setTimeout(function() {
alert('flyout!');
}, 1);
// unbind the event handler
// so that it's not call anymore
$(this).unbind('scroll.flyout');
}
};
})());
So in the end, only getScrollTop() > document.body.scrollHeight * 0.85 is executed at each scroll event, which is acceptable.
The flyout effect is ran only one time, and after the event has returned, so it won't affect scrolling.