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.
Related
I have a web application that sizes the html and body elements at 100% width and height and puts overflow: scroll on body to create full screen slide elements. I'm using jQuery Waypoints for sticky navigation and to determine which slide is currently visible.
Since the body element is technically the one scrolling, I set context: body. This works as expected in Firefox, but the waypoints won't fire in Chrome or Safari.
I can get the waypoints to fire by manually calling $.waypoints('refresh'); after scrolling to a point where they should have fired, but calling this after every scroll event seems like a very cumbersome solution.
$('body').on('scroll', function(){$.waypoints('refresh');}) —it works, but sure isn't pretty.
I'm assuming this has something to do with how each browser interprets the DOM, but is there a known reason why Chrome and Safari wouldn't play nicely with waypoints in scrollable elements?
I'm looking for one of two things, either what I've done backwards in my use of waypoints, or what the underlying issue is so I can fix it and make waypoints work properly for everyone.
For the record (and before anyone asks), I've done my research and this isn't an issue with fixed elements.
Edit: finally got a CodePen built for this. Take a look.
Remove overflow:hidden from html. Unfortunately looks like this is required - I hope it doesn't break your layout.
Next, you'll need #nav.stuck { position: fixed; } instead of absolute for a sticky header.
Use this js:
$('#nav').waypoint(function(direction) {
if (direction == 'down') {
$(this).addClass('stuck');
} if (direction == 'up') {
$(this).removeClass('stuck');
};
});
That works for me - see http://codepen.io/anon/pen/GgsdH
How about this?
$(window).load(function() {
$('#myheader').waypoint('sticky');
});
… instead of this:
$(document).ready(function(){
$('#myheader').waypoint('sticky');
});
This is of course stupid if you have a huge amount of images to load, but this solution saved my day.
Try min-height: 100% on body and html instead of height, if appropriate for your layout.
Delete overflows and heights in html and body, also context is not needed. Worked for me.
I am doing a rather simple Tween animation using MooTools. The opening animation is perfectly smooth. But then I added the closing animation (opposite of the opening animation), but it seems to stutter/hiccup at the end almost every time.
I tried the following with no success:
Removed all HTML content from the expanding DIV
Passing the Bounce settings directly to the Set function instead of using the variable
Commented the #content animation to be sure there is only 1 animation running
Commented the addClass and removeClass actions
I can't figure out what's causing the problem. Maybe someone else can have a look…
I put the test-case online here: http://dev.dvrs.eu/mootools/
window.addEvent('domready', function() {
// Set initial Div heights
$('sideBar').setStyle('height', window.getSize().y);
$('sideMenu').setStyle('height', window.getSize().y);
// Set Div heights on Window resize
window.addEvent('resize', function() {
$('sideBar').setStyle('height', window.getSize().y);
$('sideMenu').setStyle('height', window.getSize().y);
});
var bounce = {
transition: Fx.Transitions.Back.easeOut,
duration: 500
};
$$('.button.closeMenu').addEvent('click', function(event) {
event.preventDefault();
$$('.button').removeClass('active');
this.addClass('active');
$('sideMenu').set('tween', bounce);
$('sideMenu').tween('width', 0);
$('content').set('tween', bounce);
$('content').tween('margin-left', 90);
});
$$('.button.menu').addEvent('click', function(event) {
event.preventDefault();
$$('.button').removeClass('active');
this.addClass('active');
$('sideMenu').set('tween', bounce);
$('sideMenu').tween('width', 300);
$('content').set('tween', bounce);
$('content').tween('margin-left', 390);
});
});
Fiddle with example here
The transition you are using goes over the values defined as final value in the .set(property, value);. So when opening the final width is 300px but the transition/effect goes over that and than soft back to the final value.
This works great when opening because width can be 310px or more and then return to 300px, but when with has a transition under the with 0px, it doesn't work so good. It actually works ok if the final width is 10px (check here), but that's not the effect you want.
So my suggestion is to fix it with CSS, or change the transition when closing the sidebar, or use another effect altogether.
Option 1: fiddle - same transition opening, no easeout closing
Option 2: fiddle - same effect as you have but played with CSS and hidded 10px of the sidemenu under the sidebar. (z-index:3; on #sideBar and left:80px;width: 10px; on #sideMenu. Also 10px as the final value for the tween.)
To check different transitions at Mootools demo's look here.
I have an element where I'm using the Twitter Bootstrap Affix plugin. If the window gets vertically resized to the point where it is smaller than the height of the item, I'd like to remove the affix functionality from the element since you wouldn't be able to see all of it in the window.
So far I've tried this in the console just to see if it can be removed, but it doesn't seem to be working.
$("#myElement")
.removeClass("affix affix-top affix-bottom")
.removeData("affix");
$(window)
.off("scroll.affix.data-api, click.affix.data-api");
Maybe I'm going about this the wrong way? How Can I programmatically remove the affix from an element that already had it applied?
I ended up going for a mostly CSS solution, similar to what #Marcin Skórzewski suggested.
This just adds a new class when the height of the window is shorter than the height of the element.
var sizeTimer;
$(window).on("resize", function() {
clearTimeout(sizeTimer);
sizeTimer = setTimeout(function() {
var isWindowTallEnough = $overviewContainer.height() + 20 < $(window).height();
if (isWindowTallEnough) {
$overviewContainer.removeClass("affix-force-top");
} else {
$overviewContainer.addClass("affix-force-top");
}
}, 300);
});
And then in CSS, this class just gets added:
.affix-force-top{
position:absolute !important;
top:auto !important;
bottom:auto !important;
}
EDIT
For bootstrap 3, this seems to be effective:
$(window).off('.affix');
$("#my-element")
.removeClass("affix affix-top affix-bottom")
.removeData("bs.affix");
Deprecated: Answer refers to Twitter Bootstrap v2. Current version is v4.
There are few options to try.
Use function for data-offset-top. Normally, you use the integer value, for number of scrolled pixels to fix the element. According to documentation you can use the JS function, that will calculate the offset dynamically. In this case you can make your function to return different number depending on the conditions of your choice.
Use media query to override affix CSS rule for small window (eg. height 200px or less).
I think, the second variant should be suitable for you. Something like:
#media (max-height: 200px) {
.affix {
position: static;
}
}
If you would provide jsfiddle for your problem others could try to actually solve it, instead of giving just theoretical suggestion, that may or may not work.
PS. Bootstrap's navbar component uses media query for max-width to disable fixed style for small devices. It is good to do that not just because the screen size is to small for navbar, but in mobile devices position: fixed; CSS works really ugly. Take w look at navbar inside the bootstrap-responsive.css file.
Your $(window).off is close, according to #fat (author of bootstrap-affix.js) you can disable the plugin like this:
$(window).off('.affix');
That will disable the affix plugin.
See: https://github.com/twitter/bootstrap/issues/5870
On line 1890 of bootstrap is a conditional for whether the default action should be prevented. This allows your to listen for events and if some condition is met, prevent the affix from happening.
line 1890 from bootstrap:
if (e.isDefaultPrevented()) return
Example:
$('someselector')
.affix()
.on(
'affix.bs.affix affix-top.bs.affix affix-bottom.bs.affix'
, function(evt){
if(/* some condition */){
evt.preventDefault();
}
}
);
Even though this was answered, I just wanted to give my solution for this in case someone ran into a similar situation as mine.
I modified the offset top option to a ridiculous number that would never get scrolled to. This made it so I did not have to do $(window).off('.affix'); and disable affix for everything.
$('#element-id').data('bs.affix').options.offset.top = 1000000000;
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...
UPDATED (see notes at bottom)
I have created an image map and when you hover over a specific section of this image map a description will appear in a designated area (the sidebar) of my website.
Each description is of varying length therefore I have not set any maximum height level for my sidebar area so that the display can grow vertically to accomodate each description.
The problem I am having is that when you rapidly hover over areas of the image map the display produces some weird results; showing blocks up content from another hot spot for a split second in full beneath the newly hovered over area and corresponding description (hope that makes sense)
Is there anyway to complete one function in full before displaying the next to avoid this nasty display/animation?
Here is my code:
$(document).ready(function() {
$("#a-hover").hide();
$("#a").hover(function() {
$("#a-hover").fadeIn();
}).mouseleave(function() {
$("#a-hover").fadeOut();
});
$("#b-hover").hide();
$("#b").hover(function() {
$("#b-hover").fadeIn();
}).mouseleave(function() {
$("#b-hover").fadeOut();
});
$("#c-hover").hide();
$("#c").hover(function() {
$("#c-hover").fadeIn();
}).mouseleave(function() {
$("#c-hover").fadeOut();
});
And my CSS;
#a-hover,#b-hover,#c-hover {
z-index: 2;
float: left;
position: relative;
}
#a-hover,#b-hover,#c-hover,{
position: relative;
top: 0px;
left: 0px;
z-index: 1;
width:326px;
min-height:603px;
background-color:#dedddd;
}
I have shortened my code for readability (I have 9 image map hot spots)
I am a novice when it comes to jQuery but I am making a committment to learn so please go easy as my code may not be up to scratch!
I have tried to solve this myself before posting here, but I am out of my depth and need some expert advice
I appreciate any responses.
Thank You,
Wp.
UPDTAE: I tried the majority of what was provided here as answers and whilst I believe these answers are on the right track I couldn't get the problem to stop however I did notice improvement in the animations overall.
I ended up using a combination .stop(true,true); and **resize font automatically.
**Ultimately not getting the desired result is due to my lack of polish with jQuery but being in a rush I managed to find another way to handle this issue (auto resizable font).****
Thanks to all who took the time out to answer and for those reading this for a similar solution at least know the .stop(true,true); properties did in fact work for me to solve one part of this problem.
Try adding .stop before each fadeIn and fadeOut. You should pass true, true to stop to complete the animating instantly rather than leave it half faded in:
$("#a").hover(function() {
$("#a-hover").stop(true, true).fadeIn();
}).mouseleave(function() {
$("#a-hover").stop(true, true).fadeOut();
});
You can also get rid of all of the repetition by binding on a class instead of id's:
$(".imageMapElement").hover(function() {
$("#" + $(this).attr("id") + "-hover").stop(true, true).fadeIn();
}).mouseleave(function() {
$("#" + $(this).attr("id") + "-hover").stop(true, true).fadeOut();
});
May be you can try Jquery Hover Intent plugin.
try stopping the other functions:
$("#a").hover(function() {
$("#b-hover").stop().hide();
$("#c-hover").stop().hide();
$("#a-hover").fadeIn();
}).mouseleave(function() {
$("#a-hover").fadeOut();
});
Try adding .stop() before each .fadeIn and .fadeOut -- that will cancel any previous animations and immediately begin your new one.
You also have a problem with using .hover() -- that actually encapsulates two actions, mouseover and mouseout. When you assign two functions to it, the first is mouseover and the second is mouseout, but when you assign only one function to it, that one function is used for both mouseover and mouseout. So, in effect, your code is causing the element to fadeIn and fadeOut on mouseout.
Incidentally, you can shorten your code a lot using standard jQuery techniques:
$("#a-hover,#b-hover,#c-hover").hide().hover(function() {
$(this).stop().fadeIn();
}, function() {
$(this).stop().fadeOut();
});
...or even better yet, assign a class to each of those three IDs and select it instead.
You have to chain all the jQuery function calls!