I have noticed a weird performance thing in IE8 when using mouseover events on a table with many rows (100 in this example). I have tried a lot of different approaches but I can't seem to find any way to get it as fast as I like/need.
If I switch classes on each event the performance goes down in all IE versions, and If I use direct manipulation of the CSS through javascript IE6 and IE7 speeds up alot, but IE8 still performs lousy.
Any ideas ? I would really like to know what it is that makes the mouseover event to perform so sluggish compared to all the other browsers.
If this only happened to IE6 I could understand and let it pass, but when the newest version of the browser is the slowest one, there is only going to be more and more users with a bad experience.
Example using JQuery hover: http://thedungheap.net/research/
EDIT: I have now updated the example so that it is easy to see the difference between having 10 rows and 200. This is in the same document, so this cannot be a problem with the whole DOM size, i guess
The :hover IS very slow on IE8, no matter how you intend to implement it. In fact, the javascript onmouseover, onmouseout events provides way faster methods for creating a hover effect, than CSS does
Fastest example on IE8:
<table>
<tr style="background-color:#FFFFFF" onmouseover="this.style.backgroundColor='#000000'" onmouseout="this.style.backgroundColor='#FFFFFF'">
<td>foo bar</td>
</tr>
</table>
Slower example:
<style type="text/css">
tr.S1 {background-color:#000000}
tr.S2 {background-color:#FFFFFF}
</style>
<table>
<tr class="S1" onmouseover="this.className='S2'" onmouseout="this.className='S1'">
<td>foo bar</td>
</tr>
</table>
VERY slow example: JSFiddle
<style type="text/css">
tr.S {background-color:#000000}
tr.S:hover {background-color:#FFFFFF}
</style>
<table>
<tr class="S">
<td>foo bar</td>
</tr>
</table>
Btw for all browsers you can use :hover selector using css only. And only for IE6 you can add your fastest soluton.
Try using event bubbling. Add the hover event to the table only, and then look at the target element.
$(function() {
$('table').hover(function(e) {
$(e.originalTarget.parentNode).css('backgroundColor', '#ffc000');
}, function(e) {
$(e.originalTarget.parentNode).css('backgroundColor', '#fff');
});
});
Have you tried to see what happens if you only have one per row? Curious if it is the number of elements in the DOM [or in each row] could affect performance. Otherwise, it could be an issue with the way ie8 traverses tags in the selector engine. Not really an answer, but something to try.
No IE8 or I'd try it myself.
Seems fast enough to me, without actually looking at metrics.
You could try mouseover/mouseout instead of toggling. You could also try event delegation, which often helps with this many elements in the dom.
$("tr").mouseover(function() {
$(this).css('backgroundColor', '#ffc000');
})
.mouseout(function() {
$(this).css('backgroundColor', '#fff');
});
I have faced this issue and implemented the following workaround
var viewTable = jQuery("table.MyTable");
var temDiv = jQuery("<div class=\"HighlightClass\" style=\"display:none\"></div>").appendTo("body");
var highlightColor = temDiv.css("background-color");
viewTable.mouseover(function(eventObj){
jQuery(eventObj.target).parents("tr:first").css("background-color", highlightColor);
}).mouseout(function(eventObj){
jQuery(eventObj.target).parents("tr:first").css("background-color","");
});
I hope this could be useful for you.
Sorry to post on an answer this old but I think it is relevant and this page is well ranked by google so...
Wow, I just spent a great amount of time on this problem, I tried to use Javascript, but it was still slow.
This is a solution if you use background images :
This was a real issue for me, because the project I had this problem on was the hover effect on Left and Right buttons / arrows that I use to animate tabs left and right, the tabs would go under the buttons, a tab slideshow if I may say and when the cursor entered the button area the normal image would disappear, the image below would be visible for a few millisecs and then, the hover image would eventually display, ugly.
The real solution was to use image sprites, that way there is absolutely no lag even in pure css. The idea is to have a single image with all the differents images states insides (normal / hover / selected / inactive / etc), you set the image as background-image, and you just adjust the background-position value for the hover effect and others.
If you want to know better about css sprites : http://css-tricks.com/css-sprites/
Related
I'm in the process of building an A4 size drag and drop page builder.
The elements this builder can contain are images and text boxes.
I am after for some advice on what frameworks are available that can be used to build this type of front-end functionality.
Example of what I'm after, see here canva.com
The two frameworks I tried are so far are fabric js and greensock draggable, which didn’t meet my needs or are pretty difficult to create a complete page builder.
ideally i don't want to use canvas for this.
edit:
Basic Feature:
cropping
rotation
re-sizing
change font style/color/size for textboxes
add backgrounds
frames/ masking images (square image can become star shape with a overlay)
As of my understanding you want to create dashboard which can be configurable.
I would suggest use a table structure Table merge and split in which each cell should have a dropable component like
<table id="mainTable">
<tbody>
<tr>
<td class="set-as-droppable"></td>
<td class="set-as-droppable"></td>
<td class="set-as-droppable"></td>
<td class="set-as-droppable"></td>
</tr>
<tr>
<td class="set-as-droppable"></td>
<td class="set-as-droppable"></td>
<td class="set-as-droppable"></td>
<td class="set-as-droppable"></td>
</tr>
</tbody>
</table>
Like
Then on drop write your own logic
$( ".set-as-droppable" ).droppable({
accept: "div.Dragable",
drop: function( event, ui ) {
}
});
And dragable component can be TEXT or IMAGE and on drop you can give any operation
Most of your goals can be achieved by css 2/3 + some pure js
clipping/masking
http://www.html5rocks.com/en/tutorials/masking/adobe/
re-sizing, change font style/color/size for textboxes, add backgrounds
pure js/css2
rotation
css3 transform property http://www.w3schools.com/cssref/css3_pr_transform.asp
dragging
Can be pretty easily done, using pure js or you can try some open-source plugins, or something like jquery draggable.
As for your current list, I don't actually see, why do you want some framework for this, when most of it can be achieved by pure js/css with a little effort/googling.
In my humble opininon, jquery or something similar is all you really need. Just check jquery's "interactions" section here https://jqueryui.com/draggable/ to see if it can help you with building your builder interface. There are various examples for each interaction (right sidebar).
UPD:
Here is some dirty code example for you (using jquery UI) http://jsfiddle.net/tbpxnxrm/2/. Doubleclick in #main to create additional elements. No collision/overlapping checks implemented, forked from http://jsfiddle.net/4Vfm5/1095/
drag_defaults = {grid: [50,50], containment: "parent"};
resize_defaults = {
aspectRatio: true,
handles: 'ne, se, sw, nw',
grid: [50,50],
minHeight: 50,
minWidth: 50
}
$('.draggable').draggable(drag_defaults);
$('.resizable').resizable(resize_defaults);
UPD2: After a couple of years my example stopped working at all on jsfiddle. Can't surely tell why, yet the main answer is still credible.
I tried to implement this in my free time but its not something that can be done from the ground up using pure js in a couple of after hours. So far I have a jQuery plugin prototype for dropping new dom elements into a page area. I've also been experimenting with making any block component in a page resizable. In the few hours I put into it I had some success.
Resizable block component: (Edit: drag the 4 small handles in the middle of the sides)
Fiddle
Page builder prototype with menu and droppable area (Only the text item can be dropped):
Fiddle
I'll keep updating the fiddles whenever I get to work on it, but I won't have a finished plugin anytime soon.
Too much code to put here! Visit the fiddle
There is a useful jquery plugin for rotation..
Your code:
<div id="product">
<img src="images/01.jpg" />
<img src="images/02.jpg" />
<img src="images/03.jpg" />
<img src="images/04.jpg" />
<img src="images/05.jpg" />
</div>
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery('#product').j360();
});
</script>
This should work.
I think you can't do this with only one framework if your goal is to make it as easy as possible.
If I understand well, what you want to do is to allow your app' user to make some kind of advanced "drawing" made directly in the browser.
First : Without canvas element, their works will have to be exported/generated server-side.
Now, the best way to do this would be to have a javascript object that represents each document and their content, with models included and each properties like position, rotation described. And this object should be rendered making css properties and html elements correspond to the object structure. That is to say AngularJS would be my first choice as it watches almost automatically your models and render the target element in real time as soon as your object is modified. (Angular 2 is better but only documented in TypeScript and Dart)
From here, with html5 & css3, elements can be manipulated with a nice property : transform. It takes values like "translateX(10px)" or "rotateZ(10deg)".
To learn more about it : http://www.w3schools.com/cssref/css3_pr_transform.asp.
Also, for the drag and drop things : http://www.w3schools.com/html/html5_draganddrop.asp.
To crop an image, you should use server-side code. (example with php : http://php.net/manual/fr/function.imagecrop.php)
To play with masks on images, there are also css3 properties that work well :
http://www.w3schools.com/cssref/pr_pos_clip.asp
And for communication between your app and the server, use jQuery functions :
http://api.jquery.com/category/ajax/.
Finally, pick what you want from css3 : http://www.w3schools.com/css/css3_intro.asp.
http://www.w3schools.com/css/css3_images.asp
I hope it'll help you. Good luck !
UPDATE : I found that clip css property is obsolete, now it's clip-path but it works approximatively the same way.
UPDATE 2 : Actually, masks (with images and not paths) can be made through mask css property : https://developer.mozilla.org/en-US/docs/Web/CSS/mask. But be careful, it's still partially supported http://caniuse.com/#search=mask.
I have a script that adds full images dynamically over thumbnails when you hover over them. I've also given the full images a CSS :hover style to make them expand to a larger width (where normally they are constrained to the dimensions of the thumbnail). This works fine if the image loads quickly or is cached, but if the full image takes a long time to load and you don't move the mouse while it's loading, then once it does appear it will usually stay at the thumbnail width (the non-:hover style) until you move the mouse again. I get this behavior in all browsers that I've tried it in. I'm wondering if this is a bug, and if there's a way to fix or work around it.
It may be worth noting that I've also tried to do the same thing in Javascript with .on('mouseenter'), and encountered the same problem.
Due to the nature of the issue, it can be hard to reproduce, especially if you have a fast connection. I chose a largish photo from Wikipedia to demonstrate, but to make it work you might have to change it to something especially large or from a slow domain. Also note that you may have to clear the cache for successive retries.
If you still can't reproduce, you can add an artificial delay to the fullimage.load before the call to anchor.show().
HTML:
<img id="image" src="http://upload.wikimedia.org/wikipedia/commons/thumb/3/32/Cairo_International_Stadium.jpg/220px-Cairo_International_Stadium.jpg" />
CSS:
.kiyuras-image {
position: absolute;
top: 8px;
left: 8px;
max-width: 220px;
}
.kiyuras-image:hover {
max-width: 400px;
}
JS:
$(function () {
var fullimageurl = 'http://upload.wikimedia.org/wikipedia/commons/3/32/Cairo_International_Stadium.jpg';
var fullimage = $('<img/>')
.addClass('kiyuras-image')
.load(function () {
anchor.show();
});
var anchor = $('<a/>').hide().append(fullimage);
$('body').prepend(anchor);
$("#image").on('mouseenter', function () {
fullimage.attr('src',fullimageurl);
$(this).off('mouseenter');
});
});
JS Bin
Updated JS Bin with 1.5-second delay added (Hopefully makes issue clearer)
Again: Reproducing the issue involves clearing your cache of the large image, and then hovering over the original image to initial the loading of large image, then not moving your mouse while it's loading. Intended behavior is for the large image to properly take on the :hover pseudo-class when it eventually loads. Issue I see when it takes longer than ~0.75 secs to load is that it does not take on :hover until you jiggle the mouse a little.
Edit: See my comments on #LucaFagioli's answer for further details of my use case.
Edit, the sequel: I thought I already did this, but I just tried to reproduce the issue in Firefox and I couldn't. Perhaps this is a Chrome bug?
Most browsers update their hover states only when the cursor moves over an element by at least one pixel. When the cursor enters the thumbnail's img it gets hover applied and runs your mouseenter handler. If you keep your cursor still until the full-sized image loads, your old img (the thumbnail) will keep the hover state and the new one won't get it.
To get it working in these browsers, move the hover pseudo-class to a common parent element in the CSS; for example, enclose both imgs in a span.
If the selectors are correct, CSS will be applied to all elements, dynamic or otherwise. This includes all pseudo classes, and will change as attributes in the DOM change.
[Edit: while my explanation might be of interest, pozs' solution above is nicer, so I suggest using that if you can.]
The hover pseudo-class specification is quite relaxed concerning when it should be activated:
CSS does not define which elements may be in the above states,
or how the states are entered and left. Scripting may change
whether elements react to user events or not, and different
devices and UAs may have different ways of pointing to, or
activating elements.
In particular, it is not being activated when you update the visibility of the anchor element on load.
You can get around this fairly easily: copy the hover styles to a class, intercept the cursor moving over the element that it will eventually cover, and based on that add or remove your class from the element.
Demo: JS Bin (based on your delayed example).
Javascript:
$("#image")
.on('mouseenter', function () {
fullimage.attr('src',fullimageurl).toggleClass('mouseover', true);
$(this).off('mouseenter');
})
.mouseleave(function() {
fullimage.toggleClass('mouseover', false);
});
CSS:
.kiyuras-image:hover, .kiyuras-image.mouseover {
max-width: 400px;
}
TL;DR: You cannot rely on :hover applying to dynamically added elements underneath the cursor. However, there are workarounds available in both pure CSS and Javascript.
I'm upvoting both Jordan Gray and posz' answers, and I wish I could award them both the bounty. Jordan Gray addressed the issue re: the CSS specification in a somewhat conclusive way and offered (another) working fix that still allowed for :hover and other CSS effects like transitions, except on load. posz provided a solution that works even better and avoids Javascript for any of the hover events; I provide essentially the same solution here, but with a div instead of a span. I decided to award it to him, but I think Jordan's input was essential. I'm adding and accepting my own answer because I felt the need to elaborate more on all of this myself. (Edit: Changed, I accepted posz')
Jordan referenced the CSS2 spec; I will refer instead to CSS3. As far as I can tell, they don't differ on this point.
The pseudo-class in question is :hover, which refers to elements that the user has "designated with a pointing device." The exact definition of the behavior is deliberately left vague to allow for different kinds of interaction and media, which unfortunately means that the spec does not address questions like: "Should a new element that appears under the pointing device have this pseudo-class applied?" This is a hard question to answer. Which answer will align with user intent in a majority of cases? A dynamic change to a page the user is interacting with would normally be a result of ongoing user interaction or preparation for the same. Therefore, I would say yes, and most current browsers seem to agree. Normally, when you add an element under the cursor, :hover is immediately applied. You can see this here: The jsbin I originally posted. Note that if there's a delay in loading the larger image, you may have to refresh the page to get it to work, for reasons I'll go into.
Now, there's a similar case where the user activates the browser itself with the cursor held stationary over an element with a :hover rule; should it apply in that case? The mouse "hover" in this case was not a result of direct user interaction. But the pointing device is designating it, right? Besides, any movement of the mouse will certainly result in an unambiguous interaction. This is a harder question to answer, and browsers answer it in different ways. When you're activating them, Chrome and Firefox do not change :hover state until you move the mouse (Even if you activated them with a click!). Internet Explorer, on the other hand, updates :hover state as soon as it's activated. In fact, it updates it even when it's not active, as long as it's the first visible window under the mouse. You can see this yourself using the jsbin linked above.
Let's return to the first case, though, because that's where my current issue arises. In my case, the user hasn't moved the mouse for a significant length of time (over a second), and an element is added directly underneath the cursor. This could more easily be argued to be a case where user interaction is ambiguous, and where the pseudo-class should not be toggled. Personally, I think that it should still be applied. However, most browsers do not seem to agree with me. When you hover over the image for the first time and then do not move your mouse in this jsbin (Which is the one I posted in my question to demonstrate the issue, and, like the first one, has a straightforward :hover selector), the :hover class is not applied in current Chrome, Opera, and IE. (Safari also doesn't apply it, but interestingly, it does if you go on to press a key on the keyboard.) In Firefox, however, the :hover class is applied immediately. Since Chrome and Firefox were the only two I initially tested with, I thought this was a bug in Chrome. However, the spec is more or less completely silent on this point. Most implementations say nay; Firefox and I say aye.
Here are the relevant sections of the spec:
The :hover pseudo-class applies while the user designates an element with a pointing device, but does not necessarily activate it. For example, a visual user agent could apply this pseudo-class when the cursor (mouse pointer) hovers over a box generated by the element. User agents not that do not support interactive media do not have to support this pseudo-class. Some conforming user agents that support interactive media may not be able to support this pseudo-class (e.g., a pen device that does not detect hovering).
[...]
Selectors doesn't define if the parent of an element that is ‘:active’ or ‘:hover’ is also in that state.
[...]
Note: If the ‘:hover’ state applies to an element because its child is designated by a pointing device, then it's possible for ‘:hover’ to apply to an element that is not underneath the pointing device.
So! On to the workarounds! As several have zealously pointed out in this thread, Javascript and jQuery provide solutions for this as well, relying on the 'mouseover' and 'mouseenter' DOM events. I explored quite a few of those solutions myself, both before and after asking this question. However, these have their own issues, they have slightly different behavior, and they usually involve simply toggling a CSS class anyway. Besides, why use Javascript if it's not necessary?
I was interested in finding a solution that used :hover and nothing else, and this is it (jsbin). Instead of putting the :hover on the element being added, we instead put it on an existing element that contains that new element, and that takes up the same physical space; in this case, a div containing both the thumbnail and the new larger image (which, when not hovered, will be the same size as the div and thumbnail). This would seem to be fairly specific to my use case, but it could probably be accomplished in general using a positioned div with the same size as the new element.
Adding: After I finished composing this answer, pozs provided basically the same solution as above!
A compromise between this and one of the full-Javascript solutions is to have a one-time-use class that will effectively rely on Javascript/DOM hover events while adding the new element, and then remove all that and rely on :hover going forward. This is the solution Jordan Gray offered (Jsbin)
Both of these work in all the browsers I tried: Chrome, Firefox, Opera, Safari, and Internet Explorer.
From this part of your question: "This works fine if the image loads quickly or is cached, but if the full image takes a long time to load and you don't move the mouse while it's loading,"
Could it be worth while to "preload" all of the images first with JavaScript. This may allow all of the images to load successfully first, and it may be a little more user friendly for people with slower connections.
You could do something like that : http://jsfiddle.net/jR5Ba/5/
In summary, append a loading layout in front of your image, then append a div containing your large image with a .load() callback to remove your loading layer.
The fiddle above has not been simplified and cleaned up due to lack of time, but I can continue to work on it tomorrow if needed.
$imageContainer = $("#image-container");
$image = $('#image');
$imageContainer.on({
mouseenter: function (event) {
//Add a loading class
$imageContainer.addClass('loading');
$image.css('opacity',0.5);
//Insert div (for styling) containing large image
$(this).append('<div><img class="hidden large-image-container" id="'+this.id+'-large" src="'+fullimageurl+'" /></div>');
//Append large image load callback
$('#'+this.id+'-large').load(function() {
$imageContainer.removeClass('loading');
$image.css('opacity',1);
$(this).slideDown('slow');
//alert ("The image has loaded!");
});
},
mouseleave: function (event) {
//Remove loading class
$imageContainer.removeClass('loading');
//Remove div with large image
$('#'+this.id+'-large').remove();
$image.css('opacity',1);
}
});
EDIT
Here is a new version of the fiddle including the right size loading layer with an animation when the large picture is displayed : http://jsfiddle.net/jR5Ba/6/
Hope it will help
Don't let the IMG tag get added to the DOM until it has an image to download. That way the Load event won't fire until the image has been loaded. Here is the amended JS:
$(function () {
var fullimageurl = 'http://upload.wikimedia.org/wikipedia/commons/3/32/Cairo_International_Stadium.jpg';
var fullimage = $('<img/>')
.addClass('kiyuras-image')
.load(function () {
anchor.show(); // Only happens after IMG src has loaded
});
var anchor = $('<a/>').hide();
$('body').prepend(anchor);
$("#image").on('mouseenter', function () {
fullimage.attr('src',fullimageurl); // IMG has source
$(this).off('mouseenter');
anchor.append(fullimage); // Append IMG to DOM now.
});
});
I did that and it worked on Chrome (version 22.0.1229.94 m):
I changed the css as that:
.kiyuras-image{
position: absolute;
top: 8px;
left: 8px;
max-width: 400px;
}
.not-hovered{
max-width: 220px;
}
and the script this way:
$(function(){
var fullimageurl = 'http://upload.wikimedia.org/wikipedia/commons/3/32/Cairo_International_Stadium.jpg';
var fullimage = $('<img/>')
.addClass('kiyuras-image')
.load(function () {
anchor.show();
});
var anchor = $('<a/>').hide().append(fullimage);
$('body').prepend(anchor);
$('.kiyuras-image').on('mouseout',function(){
$(this).addClass('not-hovered');
});
$('.kiyuras-image').on('mouseover',function(){
$(this).removeClass('not-hovered');
});
$("#image").one('mouseover', function(){
fullimage.attr('src',fullimageurl);
});
});
Basically I think it's a Chrome bug in detecting/rendering the 'hover' status; in fact when I tried to simply change the css as:
.kiyuras-image{
position: absolute;
top: 8px;
left: 8px;
max-width: 400px;
}
.kiyuras-image:not(:hover) {
position: absolute;
top: 8px;
left: 8px;
max-width: 220px;
}
it still didn't worked.
PS: sorry for my english.
I'm not 100% sure why the :hover declaration is only triggered on slight mouse move. A possible reason could be that technically you may not really hover the element. Basically you're shoving the element under the cursor while it is loading (until the large image is completely loaded the A element has display: none and can therefore impossible be in the :hover state). At the same time, that doesn't explain the difference with smaller images though...
So, a workaround is to just use JavaScript and leave the :hover statement out of the equation. Just show the user the two different IMG elements depending on the hover state (toggles in JavaScript). As an extra advantage, the image doesn't have to be scaled up and down dynamically by the browser (visual glitch in Chrome).
See http://jsbin.com/ifitep/34/
UPDATE: By using JavaScript to add an .active class on the large image, it's entirely possible to keep using native CSS animations. See http://jsbin.com/ifitep/48
I'm having an unexpected effect and some other bugs when trying to use show/hide with mouseover and mouseout.
What I was trying to do is have a box (div) and when you would mouse over it, another box would appear and slide to the right.
Here's the fiddle for it
http://jsfiddle.net/XtXGR/
Now there's two problems with it. One is the flickering and the other is that it appears by growing from the top-left corner and what I want it to do is appear from the left.
Any help would be greatly be appreciated. Thanks
I think I know what causes the flickering from the similar questions but I still need help with the other issue. Thanks!
Oh also just so you know the context in which this will be used is on a page with a table of items and each item would be the object in the fiddle link I posted above.
The main issue is that moving over a different child element of the container will trigger a mouseout and mouseover combination, which is why you see the element expanding and collapsing. IE circumvented this with the mouseenter and mouseleave events, which act exactly like the CSS :hover.
Speaking of which, the jQuery hover function has this feature too. You should use that instead of mouseover and mouseout.
According to the show API, you should use the slide effect to get what you want.
Your final code should look like this: http://jsfiddle.net/XtXGR/28/
A couple things:
If you want to do a fadein/out this would be better:
$(document).ready(function(){
$("div.item_container").hover(function() {
$("div.item_body").fadeIn(500);
}, function() {
$("div.item_body").fadeOut(500);
});
});
Also, you should probably float the div .item_body to the left..
Demo: http://jsfiddle.net/lucuma/XtXGR/33/
How about using CSS3 transitions instead?
See this: http://jsfiddle.net/EVDj6/2/
Something like this? Using slide will give you the slide from default left effect.
$(document).ready(function(){
$("div.item_container").on('hover',function(){
$("div.item_body").toggle('slide',500);
});
});
http://jsfiddle.net/XtXGR/25/
There were many issues in your code. The href's were invalid and the floating of the elements was not 100% correct. One of the main issues was that you had display:none in your CSS. Bring that dispay:none out and of the CSS and put it inline on the item you want to show/hide. When its default state is "hide" then you need to bring the display:none inline.
Look at this fiddle to get a better idea of how to go about this with a bit more valid syntax:
http://jsfiddle.net/fH3EC/1/
I made something fast, you can go crazy with it :) The animation is pretty smooth, I hope it's useful for you.
http://jsfiddle.net/XtXGR/50/
I'm using jQuery to hide and show rows in a table.
Here is my jsFiddle: http://jsfiddle.net/Nbf75/5/
Notice that when you click a question, the answer slides in but it squishes the question.
It doesn't do that if you set no animation, but I want an animation (not necessarily the preset slow animation, but any animation squishes it.)
So how do I get the animations to not squish the question?
Edit: This happens in Chrome but not Firefox, haven't tested in any other browsers yet
This is an artifact of how the rendering engine handles table cells. You can work around it by wrapping the answer (inside the td) in a div, and operating directly on that div. The td will follow suit (since it's automatically sized) and the effect is the same across all browsers.
See it in action.
Just use fadeOut and fadeIn instead of show and hide. You will achieve the desired affect without the squishing.
Example:
$('table tr td.question').toggle(function() {
$($(this).parent('tr').next('tr').children('.answer')).fadeOut('slow');
}, function() {
$($(this).parent('tr').next().children('.answer')).fadeIn('slow');
});
http://jsfiddle.net/Nbf75/10/
I'm having some minor problems with some animations I'm trying to set up. I have a couple divs stacked on top of each other kind of like this.
<div id="div1">
Stuff...
</div>
<div id="div2">
More Stuff...
</div>
Each of these divs has a drop shadow applied to it via jQuery plugin (jquery.dropshadow.js).
The problem occurs when I expand one of the divs using some kind of animation. The shadow does not update with the size of the div. I can redraw the shadow in the callback of the animation but still looks pretty joggy.
Is there a way that I can update the status of my shadows periodically throughout the course of the animation or can anyone recommend a better drop shadow library that would fix the problem? It doesn't have to be jQuery plugin.
I think the only way to do this (at least with that particular drop shadow plugin) would be targeting both the element you want and all the drop-shadow "phantom" elements, in your animation. So, for example:
<style type="text/css">
#div1 { width: 50px; }
</style>
<div id="div1">
<p>Here is a lot of stuff. Stuff stuff stuff.</p>
</div>
<script type="text/javascript">
$(document).ready(function() {
$("#div1").dropShadow();
$("#div1").click(function() {
$("#div1, #div1 + .dropShadow .dropShadow").animate({ width: "400px" }, 1500);
});
});
</script>
This is based on the structure of the rendered code that the drop-shadow plugin produces... all the fuzzy copies of your original element get a class of .dropShadow and get grouped into a container element which also has a class of .dropShadow and gets stuck into the document right after the original element (thus the + selector).
As long as you apply whatever animation you're doing to all of these shadow elements, they all get animated (however, it is a bit jerky from all that processing... uffda).
I would suggest using CSS for your drop shadows, and not JS.
I have dealt with this exact problem in the past and I have completely stopped using JS for drop shadows. I have never seen animations with JS shadows look as smooth as pure CSS. Also, using too much JS to alter the page elements can cause performance issues.
Try to apply the same animation effects to the shadow element(s).
I don't know the exact technique used in jquery.dropshadow.js, but I suspect it creates copies of your shadow casting elements and styles them to achieve shadow like appearance. It is possible that these copies are siblings of their source elements, thus don't "follow" animation (as child elements would).
Ok, I still don't know how you animate, but I give you another example:
$('#foo').slideToggle().ready(function(){
$('#foo').dropShadow(options);
});
So, instead of slideToggle, just use whatever animation thingy you got.
Hope that helps.