Choppy jQuery Scrolling in Firefox - javascript

I have a small snippet of jQuery that I'm using to move my nav bar when the user scrolls then have it stick 75px from the top of the page.
In IE9 the scrolling is super smooth, but in Firefox it's very jerky and choppy.
Here's my code:
jquery:
$(window).scroll(function(){
var scrollTop = $(this).scrollTop();
$('div.hnav').css('margin-top',Math.max(-235,0-scrollTop));
});
css:
div.hnav {
position: fixed;
top: 300px;
height: 40px;
}
Any suggestions?

Don't use margin-top. Changing the margin values often causes reflow. Why not just use top, as you've already got that set up to be positioned anyway?

I've found often the solution is to let the scrolling be handled by the GPU. One way you can force this to happen is by adding
webkit-transform:translate3d(0,0,0)
to the element you are scrolling. You can see what is being handled by the GPU vs CPU by opening the page in Chrome->Developer Tools->General and selecting "Force accelerated compisiting" and "Show composited layer borders". That will cause an orange border to appear around anything being handled by the GPU.

I suggest you use this approach instead: http://jsfiddle.net/Uxn9f/
Updated CSS
div.hnav {
position: absolute;
top: 300px;
height: 40px;
}
Swapped from fixed to absolute positioning. This allows the element to move with the scroll of the page.
Changed JQuery
$(window).scroll(function () {
if ($(this).scrollTop() > 235) {
$('div.hnav').css({
'position': 'fixed',
'top': 75
})
} else {
$('div.hnav').css({
'position': 'absolute',
'top': 300
})
}
});
Essentially what we're doing is checking the current scroll of the page. When we reach a certain point (235px) we will "lock" the .hnav to be 75px from the top of the viewport by changing its positioning (type and dimension).
If the user scrolls back up past out magic 235px mark, reset the positioning.

Related

Go back to absolute positioning when scrolling up after changing to fixed position when scrolling down

I am working on a page that has a small navigation box on the left that I would like to be always visible as the user scrolls down. I'm using the below script to get that effect and it is working great except for one problem.
When I scroll back up the box does not revert back to its absolute position but keeps the fixed position which then overlaps the beginning banner. I'm new to this idea, any ideas or suggestions on how to make the div go back to it's original settings when the user scrolls up to that point?
$(window).scroll(function(){
if ($(window).scrollTop() >= 229){ //looking for the window to scroll to 229px in this example
$('.timeline').css({position:'fixed',margin:'-250px 0 0 50px'});
} else {
$('.timeline').css({position:'absolute'});
}
});
To see the page I am working on: http://embassyofrock.com/press
You're not unsetting the margin when you revert back to absolute. I would suggest adding/removing a class instead so you don't need to worry about resetting values.
Javascript:
$(window).scroll(function(){
if($(window).scrollTop() >= 229){
$('.timeline').addClass('fixed');
} else {
$('.timeline').removeClass('fixed');
}
});
CSS:
.fixed {
position: fixed;
margin: -250px 0px 0px 50px;
}

Creating a "floating" top navigation like on zendesk.com?

I'd like to create a "floating" top navigation like seen on here.
When scrolling down the page, the top navigation of course dissapears out of the browser window, but it comes back into the view, and stays on top all the way down.
I can see that the CSS is changing at the div#nav-bar-content, but I can't figure out when these styles are applied in JavaScript.
If someone has a pointer to how it can be achieved using jQuery, or where in the Zendesk source code I can find an example of this, it would be great.
Thank you very much in advance!
Regards Kim
You should reposition your menu on each scroll event.
<div class='menu'>Menu content</div>
$(window).scroll(function(e) {
if ($(window).scrollTop() > 20) // 20 - offset from the top
$('.menu').css({
position: 'fixed',
top: '0'
});
else
$('.menu').css({
position: 'static'
});
});
UPDATE: And the static solution using CSS:
div.menu {
position: fixed;
top: 10px;
z-index: 5000;
}

Disable horizontal scroll with JavaScript

Does anyone know if there is a way to disable the horizontal scrollbar using JavaScript?
I don't want to use overflow-x: hidden;.
Without using the perfectly workable overflow-x CSS property, you could resize the content to not require a scroll bar, through javascript or through HTML/CSS design.
You could also do this:
window.onscroll = function () {
window.scrollTo(0,0);
}
... which will detect any scrolling and automatically return the scroll to the top/left. It bears mentioning that doing something like this is sure to frustrate your users.
You're best served by creating an environment where unwanted UI elements are not present at all (through the CSS, through design). The approach mentioned above shows unnecessary UI elements (scroll bars) and then causes them to not work in a way that the user expects (scroll the page). You've "broken a contract" with the user - how can they trust that the rest of your web site or application will do expected things when the user makes a familiar action?
A way to prevent elements from scrolling down in jQuery:
$(element).scroll(function () {
this.scrollTop = 0;
this.scrollLeft = 0;
});
Well, this does not actually prevent the scrolling, but it "scrolls back" to the top-left corner of an element, similar to Chris' solution which was created for the window instead of single elements. Remove the scrollTop or scrollLeft lines to suit your needs.
A dirty trick would be overlapping the scrollbars: http://jsfiddle.net/dJqgf/.
var overlap = $('<div id=b>');
$("#a").wrap($('<div>'));
$("#a").parent().append(overlap);
with:
#a {
width: 100px;
height: 200px;
overflow-x: scroll;
}
#b {
position: relative;
left: 0;
bottom: 20px;
width: 100%;
height: 20px;
background-color: white;
}

Dynamic Background Scrolling

Here's a link to what I'll be referring to.
I'm having some trouble getting the background image to work the way I'd like it to.
I want the background to auto resize based on the width of the window, which it is already doing correctly. If you make your window smaller you'll see the background shrink with it.
Here's the issue. If you make your window wide (short) then the background will resize and go too high so you can't see the top of the background anymore (since the background is bottom positioned).
I want the background to be top position when you are at the top of the page, and as you scroll down it will slowly move to be bottom positioned. Sort of like the effect of an Android phone's background when you move left and right. Of course, keep in mind that I still want the background to auto-resize when you make the window smaller.
html {
background-color: #70d4e3;
height: 100%;
}
body {
height: 100%;
}
.background {
margin-top: 45px;
width: 100%;
position: fixed;
bottom: 0;
left: 0;
z-index: -9999;
}
.banner {
margin: 0px auto;
width: 991px;
margin-bottom: -9px;
}
.content {
background: url("http://i.imgur.com/daRJl.png") no-repeat scroll center center transparent;
height: 889px;
margin: 0 auto;
width: 869px;
}
.innerContent {
padding: 30px;
}
<img src="http://i.imgur.com/6d5Cm.jpg" alt="" class="background" />
<div class="banner">
<img src="http://i.imgur.com/JptsZ.jpg" alt="" />
</div>
<div class="content">
<div class="innerContent">
testing
</div>
</div>
Maybe some javascript or jquery would be needed to achieve this.
Well, this was fun, thanks!
I hope you don't mind me taking the liberty to use percentages to make my life a little bit easier and possibly the script slightly more robust since I can reliably use floats with percentages.
What I did is make the layout, html and css comply with the rules you need for the bg to be animated properly, they stayed largely the same from what you had.
Then it was just a question of figuring out the calculations needed with the right properties to figure out the percentage you were from the top, the *20 is actually the amount of space 'left' to fill by the background image in percentages (as the background height is 80%).
They I moved the calculations to a function so I could call that on scroll and on window resize, making sure it's initiated on any event that modifies the window somehow...
Didn't do extensive testing but it worked in Chrome and I'm tired :p
I believe this is what you are looking for:
http://jsfiddle.net/sg3s/RSqrw/15/ See edit 2
If you wanted this the other way arround just make the page background start at the top and modify that:
http://jsfiddle.net/sg3s/RSqrw/14/ See edit 2
Edit:
As a bonus, and since I had never actually written jquery script as a 'plugin', I decided to convert this into one. What I came up with should be easy to implement and use!
http://jsfiddle.net/sg3s/RSqrw/52/ See Edit 3
Functionality successfully tested in Chrome, Firefox 3.6, IE9 + compatibility mode
Edit 2:
Reading the question again checking if I did it right I noticed I didn't quite do what you want, so I updated the link in the first edit which gives you a plugin in which you can have several options for the scrolling background. It retains my 'old' interpetation while also doing what you want... Read comments in code for some extra descriptions.
Edit 3:
As I went to work today I was bothered with the fact that my plugin 'try' was a little bloated. And as you mentioned in the comment it didn't quite fit the requirements.
So I rewrote it to only do what you want and not much more, tested in Chrome Firefox, IE9 +compat etc etc.. This script is a lot cleaner.
http://jsfiddle.net/sg3s/vZxHW/
You can chose to make the background stick to the top or bottom if the height fits in the window. Nothing else, but that is already more than enough to do some pretty cool stuff :p
An exact solution: Fiddle: http://jsfiddle.net/srGHE/2/show/
View source
Thanks for the challenge. See below for the solution, which is complying with all requirements, including recommended yet optional (with steps on how to remove these) features. I only show the changed parts of your page, with an explanation after each section (CSS, HTML and JavaScript):
CSS (changes):
html,body{
margin: 0;
height: 100%;
padding: 0;
}
body{
background-color: #70d4e3;
}
#background { /*Previously: .background*/
/*Removed: margin-top: 45px;
No other changes*/
}
#banner /*Previously: .banner; no other changes */
#content /*Previously: .content; no other changes */
#innerContent /*Previously: .innerContent; no other changes */
Explanation of CSS revisions:
margin-top:45px at the background is unnecessary, since you're absolutely positioning the element.
All of the elements which are unlikely to appear more than once should be selected via the id (#) selector. This selector is more specific than the class selector.
HTML (changes):
All of the class attributes have been replaced by id. No other changes have been made. Don't forget to include the JQuery framework, because I've implemented your wishes using JQuery.
JavaScript (new):
Note: I have added a feature which you didn't request, but seems logical. The code will automatically reserve sufficient margin at the left side of the window in order to always display the background. Remove anything between the marked comments if you don't want this feature.
$(document).ready(function(){
//"Static" variables
var background = $("#background");
var marginTop = parseFloat(background.css("margin-top")) || 0;
var bannerWidth = $("#banner").width(); /*Part of auto left-margin */
var extraContWidth = (bannerWidth - $("#content").width())/2; /*Same as above*/
function fixBG(){
var bodyWidth = $("body").width();
var body_bg_width_ratio = bodyWidth/1920;
var bgHeight = body_bg_width_ratio * 926; //Calcs the visible height of BG
var height = $(document).height();
var docHeight = $(window).height();
var difHeight = bgHeight - docHeight;
var scrollDif = $(document).scrollTop() / (height - docHeight) || 0;
/*Start of automatic left-margin*/
var arrowWidth = body_bg_width_ratio * 115; //Arrow width
if(bodyWidth - bannerWidth > arrowWidth*2){
$("body > div").css("margin-left", "auto");
} else {
$("body > #banner").css("margin-left", arrowWidth+"px");
$("body > #content").css("margin-left", (arrowWidth+extraContWidth)+"px");
}
/*End of automatic left-margin*/
if(difHeight > 0){
background.css({top:(-scrollDif*difHeight-marginTop)+"px", bottom:""});
} else {
background.css({top:"", bottom:"0"});
}
}
$(window).resize(fixBG);
$(window).scroll(fixBG);
fixBG();
});
Explanation of the JavaScript code
The size of the background is determined by calculating the ratio of the background and document width. The width property is used, because it's the most reliable method for the calculation.
Then, the height of the viewport, document body and background is calculated. If applicable, the scrolling offset is also calculated, to prepare the movement of the background, if necessary.
Optionally, the code determines whether it's necessary to adjust the left margin (to keep the background visible at a narrow window).
Finally, if the background arrow has a greater height than the document's body, the background is moved accordingly, taking the scrolling position into account. The arrow starts at the top of the document, and will move up as the user scrolls (so that the bottom side of the arrow will be the bottom of the page when the user has fully scrolled down). If it's unnecessary to move the background, because it already suits well, the background will be positioned at the bottom of the page.
When the page has finished loading, this functionality is added to the Resize and scroll events, so that the background is always at the right location.
If you've got any other questions, feel free to ask them.
well, I'm not sure if I understand you and why do you want to do that, but you can try adding 2 backgrounds (see http://www.css3.info/preview/multiple-backgrounds/ ), one with the top bg and another with the bottom bg but I think that if the page is not too long it will cause issues, so the other answer with pure CSS is as follows: first add 3 horizontal divs with 100% width. Top div will have your top bg and its height, middle div will be transparent and auto height and bottom div will have your bottom bg and its height. All divs will have a 0 z-index. Then create a higher z-index div to act as a container and you'll be set. If I understand your question right, that's the close I can think of to achieve that. This being said, I'm pretty sure you can do this with JQuery with way better results
Using jQuery I was able to give you what I think you're asking for:
$(window).scroll(function() {
var h = Math.max($(document).height(), $(window).height());
var bottom = h - $(".background").height() - $(window).height();
$(".background").css("top", (($(window).scrollTop() / h) * bottom) + "px");
});
EDIT: Forgot to account for the way scrollTop reports position.
Or maybe:
.background {
margin-top: 45px;
max-width: 100%;
position: fixed;
bottom: 0;
left: 0;
z-index: -9999;
max-height: 100%;
}
I reccomend using jQuery Background Parallax
http://www.stevefenton.co.uk/Content/Jquery-Background-Parallax/
The function is as simple as
$("body").backgroundparallax();
Ask if you don't get it to work.
#abney; as i understand your question may that's you want http://jsfiddle.net/sandeep/RSqrw/60/
you need only css for this:
#background {
position: fixed;
width: 100%;
height:100%;
top: 0;
left:0;
z-index: -1;
}
The solution to your issue is a nice little lightweight plugin by Scott Robin. You can get more info, download it, and make your life easier for all of your projects by visiting his project page here.

How do I make a div follow me as I scroll down the page?

The user enters the site.
At this point, the div is in the middle of the page.
As he scrolls down the page, the div first begins to move upward, but once it hits the top, it stays there.
As he scrolls further down the page, the div stays near the top, always visible to the user.
As he scrolls up the page all the way to the top, the div once again stays back in position where it was originally.
You can hook the scroll event on the window object. When processing the event, look at the vertical scroll position of the window/document (see this answer on SO for how to do that). Use absolute positioning for your div and update its top as coordinate as necessary.
FWIW, I would be very careful doing this. Usually when a user scrolls, it's because they want to look at different content than what's on the page. Personally, I hate boxes that follow me around on web pages. :-) But that doesn't mean there isn't a good reason for doing this on occasion.
Very basic example (live copy):
// Make sure this is in a script tag at the end of the body,
// just prior to the closing </body> tag.
function getScrollTop() {
if (typeof window.pageYOffset !== "undefined" ) {
// Most browsers
return window.pageYOffset;
}
var d = document.documentElement;
if (typeof d.clientHeight !== "undefined") {
// IE in standards mode
return d.scrollTop;
}
// IE in quirks mode
return document.body.scrollTop;
}
window.onscroll = function() {
var box = document.getElementById("box");
var scroll = getScrollTop();
if (scroll <= 28) {
box.style.top = "30px";
} else {
box.style.top = (scroll + 2) + "px";
}
};
#box {
/* Position absolutely, 30px down from the top */
position: absolute;
top: 30px;
/* In my case I'm centering it in the window; do what you like */
margin-left: -100px;
left: 50%;
width: 200px;
/* These are just for my example */
height: 1.25em;
border: 1px solid #bbb;
text-align: center;
}
<div id='box'>I'm the box</div>
<div style="height: 1000px"></div>
(In my case, I'm always keeping it 2 pixels below the top, but if you don't want that you can adjust the numbers accordingly.)
As you can see other people provided ready scripts, but if you want to make one your self (waste of time) [or you may want to learn].. here is a good point to start:
var hscroll = (document.all ? document.scrollLeft : window.pageXOffset);
var vscroll = (document.all ? document.scrollTop : window.pageYOffset);
This solution is a lot simpler and might work just as good for some. Position: Fixed or Position: Sticky could do the job.
<div class="col" style="position:fixed; top: 250px; left: 50%">
<p>this box follows me while scrolling down</p>
</div>
http://jsfiddle.net/25rgq/
This is an old implementation of your desired functionality, which I've used. It's one of the first scripts I wrote, so JS & jQuery knowing people will most likely vomit. I wrote it mainly due all the examples I found online were centered on moving the DIV rather than setting it to fixed, and incrementally adding to the top-margin of the box resulted in really choppy movement.
Basicly it changes to fixed as the specified element is a custom set margin from the top of the browser window, and stops moving down once it hits a custom offset before our footer (we wanted to constrain the followbox to not move past our sidebar space).
Hope it is of any use, and if a plugin to handle this nowadays exists, you would probably be better of using it.

Categories

Resources