Not too long ago I asked about setting up a DIV which scrolls with the rest of the page. Post can be found here.
I've set this up, using the following code:
JS..
jQuery(function ($) {
var el = $('#sidebar'),
pos = el.position().top;
alert(pos);
$(window).scroll(function() {
el.toggleClass('fixed', $(this).scrollTop() >= pos);
});
});
CSS..
/* profile sidebar */
#sidebar>div{ width: 300px; margin-top: 10px; }
#sidebar.fixed>div{position:fixed;top:0}
A copy of the page can be found here. The alert was just some debugging.
The problem is, when you scroll a small amount, #sidebar suddenly appears at the very top of the page. In addition, sometimes as you scroll further down, the sidebar appears - and sometimes it doesn't.
Any idea what might be causing such seemingly random functionality?
I'm still trying to figure out why it works in the first place in the jsfiddle example, but anyway, I know how to fix it:
$(window).scroll(function() {
if($(this).scrollTop() >= pos){
el.addClass('fixed');
}else{
el.removeClass('fixed');
}
});
I tested this by unbinding the event you had and replacing it with this code. It seemed to work fine.
The reason I can't understand why it works in the example: toggleClass should be constantly adding and removing "fixed" if you have scrolled enough, because the conditional is true (true here means whether to toggle). The constant adding and removing of the fixed class causes the jumpy behavior.
You can watch this on your page: open up some dev tools (firegubg or Chrome) and watch what happens to your sidebar element.
[UPDATE]
Actually, I misread the docs. True means the class should be added (I don't think the docs are very clear though). Thus... the only way I could explain this is if #dunc was running jQuery v1.2 and the switch was getting ignored completely...
Related
I'm using the jquery on scroll() to apply z-index to a header on scroll.Please find the UPDATED fiddle:
http://jsfiddle.net/L5pc81r6/2/
As seen the header should remain fixed while scrolling the rest of the body content. However there is something missing that causes my scroll method to fail on scrolling. I had set a debugger at the callback function, but it never goes into that debug point. I wonder whats going on
js:
$("#main").on("scroll",function() {
if ($(this).scrollTop() > 0) {
$('#header').addClass('fixed');
} else {
$('#header').removeClass('fixed');
}
});
Any ideas are helpful!! Thanks!!
In jsfiddle on left sidebar under Frameworks & Extensions choose jQuery.
Like this...http://jsfiddle.net/L5pc81r6/4/ using
$('#main').on('scroll'...
as you were
I created a dynamic table that scrolls left and right, has resizable columns, has a fixed header, etc. This table works great on EVERY browser I've tried. Even IE8 looks good (missing features, but still good).
This issue arises when I try to view the table in Safari 7.0.4 on my Macbook.
Attached is what is should look like (the fixed header is on the bottom for demonstration purposes):
when you scroll, the fixed header, body, and fixed scrollbar all are connected via some jQuery scrollLeft() functions (scroll one, scroll all):
var tableHeaderSpace = $('.table-full-wrap-space'),
tableHeader = $('.table-full-wrap-header'),
tableBody = $('.table-full-wrap-body'),
tableScroll = $('.table-full-wrap-scroll');
tableScroll.bind('scroll', function() {
tableHeader.scrollLeft(tableScroll.scrollLeft());
tableBody.scrollLeft(tableScroll.scrollLeft());
});
tableHeader.bind('scroll', function() {
tableScroll.scrollLeft(tableHeader.scrollLeft());
tableBody.scrollLeft(tableHeader.scrollLeft());
});
tableBody.bind('scroll', function() {
tableScroll.scrollLeft(tableBody.scrollLeft());
tableHeader.scrollLeft(tableBody.scrollLeft());
});
$(window).bind("scroll", function() {
var tableHeaderOffset = tableHeaderSpace.offset().top;
if (this.pageYOffset >= tableHeaderOffset) {
tableHeader.addClass('isFixed');
} else {
tableHeader.removeClass('isFixed');
}
});
Again, this works great...but as you scroll right a bit more, the browser starts duplicating content within that fixed header:
The issue is is that no 'actual' content is being duplicated - this is some sort of browser fragmenting that is showing duplicates - without adding elements in the DOM.
The next picture is the browser doing some more "magic". at certain points in horizontal scrolling, the whole fixed header's colors gets inverted:
I wasn't able to get a snapshot of it, but it also once duplicated the "record count" bar below it.
Anyone have any ideas what's going on here? I tried to duplicate this in jsFiddle but no dice. From that, I would assume that this is an issue with my code, but the results are only with ONE specific browser on mac (safari), and it is doing some STRANGE stuff.
Last note - since I can't replicate this in jsFiddle, i'm not sure how I could report this to Apple (the working (or 'broken') example is proprietary and I can't give out access to it).
EDIT:
here's the jsfiddle where I tried to duplicate the issue (very rough - but it's functional):
jsFiddle Duplication Attempt
so - I knew this wouldn't be a hot topic question, but I thought I would still give it a go ahead.
as for the answer, I found some old table css that was overlapping my new stuff - which in turn was somehow flipping safari out so bad that it was fragmenting it.
previous old code: background: transparent;
new code: background: #fff;
This doesn't make sense to me - but until someone else comes up with an hypothesis, I'll mark this as the answer.
now my number-one contender for worst browser: safari - look out, IE.
This may come as a huge surprise to some people but I am having an issue with the IE browser when I am using the $(window).scroll method.
My goal:
I would like to have the menu located on the left retain it's position until the scroll reaches > y value. It will then fix itself to the top of the page until the scroll returns to a < y value.
My error:
Everything seems just fine in Chrome and Firefox but when I go to Internet Explorer it would seem the browser is moving #scroller every time the scroll value changes, this is causing a moving/flickering event.
If someone could point me to a resource or give me a workaround for this I would be very grateful!
Here is a fiddle:
http://jsfiddle.net/CampbeII/nLK7j/
Here is a link to the site in dev:
http://squ4reone.com/domains/ottawakaraoke/Squ4reone/responsive/index.php
My script:
$(window).scroll(function () {
var navigation = $(window).scrollTop();
if (navigation > 400) {
$('#scroller').css('top',navigation - 220);
} else {
$('#scroller').css('top',183);
$('#scroller').css('position','relative');
}
});
You might want to take a look at the jQuery Waypoints plugin, it lets you do sticky elements like this and a lot more.
If you want to stick with your current method, like the other answers have indicated you should toggle fixed positioning instead of updating the .top attribute in every scroll event. However, I would also introduce a flag to track whether or not it is currently stuck, this way you are only updating the position and top attributes when it actually make the transition instead of every scroll event. Interacting with the DOM is computationally expensive, this will take a lot of load off of the layout engine and should make things even smoother.
http://jsfiddle.net/WYNcj/6/
$(function () {
var stuck = false,
stickAt = $('#scroller').offset().top;
$(window).scroll(function () {
var scrollTop = $(window).scrollTop();
if (!stuck && scrollTop > stickAt) {
$('#scroller').css('top', 0);
$('#scroller').css('position','fixed');
stuck = true;
} else if (stuck && scrollTop < stickAt) {
$('#scroller').css('top', stickAt);
$('#scroller').css('position','absolute');
stuck = false;
}
});
});
Update
Switching the #scroller from relative to fixed removes it from the normal flow of the page, this can have unintended consequences for the layout as it re-flows without the missing block. If you change #scroller to use an absolute position it will be removed from the normal flow and will no longer cause these side-effects. I've updated the above example and the linked jsfiddle to reflect the changes to the JS/CSS.
I also changed the way that stickAt is calculated as well, it uses .offset() to find the exact position of the top of #scoller instead of relying on the CSS top value.
Instead of setting the top distance at each scroll event, please consider only switching between a fixed position and an absolute or relative position.All browsers will appreciate and Especially IE.
So you still listen to scroll but you now keep a state flag out of the scroll handler and simply evaluate if it has to switch between display types.
That is so much more optimized and IE likes it.
I can get flickers in Chrome as well if I scroll very quickly. Instead of updating the top position on scroll, instead used the fixed position for your element once the page has scrolled below the threshold. Take a look at the updated fiddle: http://jsfiddle.net/nLK7j/2/
I am new to Jquery but have written a simple vertical accordion. It seems to to the job I require, but at the end of the slide down there is a visible jerk.
If anyone could look at it and suggest a solution, it will stop me pulling any more of my hair out!
Here is a a link to my test page (all my code [css, js etc.] is in one file for ease) : Vertical Accordion
In your custom code, I got rid of the 'jump' by making a small change in the CSS and specifying the height of the p tags within the accordion.
Since you hide them all via script, before you do:
$(".accordion p:not(:first)").hide();
maybe you could walk through and get the calculated heights of each piece and add that to each items style, thereby eliminating that "jerk" you get at the end.
Something along these lines:
$('.accordion p').each(function(index) {
$(this).css('height', $(this).height());
});
Edit
I went ahead and downloaded a copy of your page and tested this, and it seems to work fine in a few quick browser tests, so here's your revised vaccordian.js:
$(document).ready(function(){
$('.accordion p').each(function(index) {
$(this).css('height', $(this).height());
});
$(".accordion h3:first").addClass("active");
$(".accordion p:not(:first)").hide();
$(".accordion h3").click(function(){
$(this).next("p").slideToggle("slow")
.siblings("p:visible").slideUp("slow");
$(this).toggleClass("active");
$(this).siblings("h3").removeClass("active");
});
});
TL;DR - by setting an explicit height on each 'opening' part of the accordion, it removes the jerky animation. so we set those heights via script.
For reference in case somebody else comes across this problem, the following worked for me:
.ui-accordion .ui-accordion-content {
overflow: auto;
box-sizing: content-box;
-moz-box-sizing: content-box;
}
I don't really have time to investigate the details of why this fix works, but thought I'd share anyway.
I was able to fix my problem just by using overflow: auto or overflow: hidden. I think this works because it ignores the height of the element and will show whatever it can. As long as there isnt a small height it should be able to show everything but adding the overflow property allows it transition more smoothly because it is not calculating the height.
I'm building an auto-follow div that is bound to the $(window).scroll() event. Here is my JavaScript.
var alert_top = 0;
var alert_margin_top = 0;
$(function() {
alert_top = $("#ActionBox").offset().top;
alert_margin_top = parseInt($("#ActionBox").css("margin-top"));
$(window).scroll(function () {
var scroll_top = $(window).scrollTop();
if(scroll_top > alert_top) {
$("#ActionBox").css("margin-top", ((scroll_top-alert_top)+(alert_margin_top*2))+"px");
console.log("Setting margin-top to "+$("#ActionBox").css("margin-top"));
} else {
$("#ActionBox").css("margin-top", alert_margin_top+"px");
};
});
});
This code assumes that there is this CSS rule in place
#ActionBox {
margin-top: 15px;
}
And it takes an element with the id "ActionBox" (in this case a div). The div is positioned in a left aligned menu that runs down the side, so it's starting offset is approximately 200 px). The goal is to start adding to the margin-top value once the user has scrolled past the point where the div might start to disappear off the top of the browser viewport (yes I know setting it to position: fixed would do the same thing, but then it would obscure the content below the ActionBox but still in the menu).
Now the console.log shows that the event is firing every time it should and it's setting the correct value. But in some pages of my web app the div isn't redrawn. This is especially odd because in other pages (in IE) the code works as expected (and it works every time in FF, Opera and WebKit). All pages evaluate (0 errors and 0 warnings according to the W3C validator and the FireFox HTMLTidy Validator), and no JS errors are thrown (according to the IE Developer Toolbar and Firebug). One other part to this mystery, if I unselect the #ActionBox margin-top rule in the HTML Style explorer in the IE Developer Tools then the div jumps immediately back in the newly adjusted place that it should have if the scroll event had triggered a redraw. Also if I force IE8 into Quirks Mode or compatibility mode then the even triggers an update.
One More thing, it works as expected in IE7 and IE 6 (thanks to the wonderful IETester for that)
I'm having a problem with your script in Firefox. When I scroll down, the script continues to add a margin to the page and I never reach the bottom of the page. This occurs because the ActionBox is still part of the page elements. I posted a demo here.
One solution would be to add a position: fixed to the CSS definition, but I see this won't work for you
Another solution would be to position the ActionBox absolutely (to the document body) and adjust the top.
Updated the code to fit with the solution found for others to benefit.
UPDATED:
CSS
#ActionBox {
position: relative;
float: right;
}
Script
var alert_top = 0;
var alert_margin_top = 0;
$(function() {
alert_top = $("#ActionBox").offset().top;
alert_margin_top = parseInt($("#ActionBox").css("margin-top"),10);
$(window).scroll(function () {
var scroll_top = $(window).scrollTop();
if (scroll_top > alert_top) {
$("#ActionBox").css("margin-top", ((scroll_top-alert_top)+(alert_margin_top*2)) + "px");
console.log("Setting margin-top to " + $("#ActionBox").css("margin-top"));
} else {
$("#ActionBox").css("margin-top", alert_margin_top+"px");
};
});
});
Also it is important to add a base (10 in this case) to your parseInt(), e.g.
parseInt($("#ActionBox").css("top"),10);
Try marginTop in place of margin-top, eg:
$("#ActionBox").css("marginTop", foo);
I found the answer!
I want to acknowledge the hard work of everyone in trying to find a better way to solve this problem, unfortunately because of a series of larger constraints I am unable to select them as the "answer" (I am voting them up because you deserve points for contributing).
The specific problem I was facing was a JavaScript onScoll event that was firing but a subsequent CSS update that wasn't causing IE8 (in standards mode) to redraw. Even stranger was the fact that in some pages it was redrawing while in others (with no obvious similarity) it wasn't. The solution in the end was to add the following CSS
#ActionBox {
position: relative;
float: right;
}
Here is an updated pastbin showing this (I added some more style to show how I am implementing this code). The IE "edit code" then "view output" bug fudgey talked about still occurs (but it seems to be a event binding issue unique to pastbin (and similar services)
I don't know why adding "float: right" allows IE8 to complete a redraw on an event that was already firing, but for some reason it does.
The correct format for IE8 is:
$("#ActionBox").css({ 'margin-top': '10px' });
with this work.
try this method
$("your id or class name").css({ 'margin-top': '18px' });