• 2 min read
jQuery’s hide() and show() slow in Chrome
Whilst working on a project where I’m filtering elements on the client using JavaScript I came across a very interesting issue with Chrome.
I filter elements by running jQuery’s hide() or show() on them depending on what the user entered and there’s around 750 elements that need this filtering. I noticed that this was quite slow in Chrome as it took around 2-3 seconds for the page to become responsive whilst filtering. I tested the page in Internet Explorer 9 to confirm that the code I had written was to blame, but the filtering was instant. What the hell Chrome?
I then asked a friend who uses Firefox to test it out and it also filtered instantly. I did a bit of research on the subject and came across a few people with the same issue as well as a bug report for Chromium.
One of the answers on Stack Overflow had a work around that seemed to work fine for Chrome. Instead of using the hide() and show() methods I used the following (with overflow: hidden;) :
$element.css("margin-top", "0"); // For showing
$element.css("margin-top", "-1000000px"); // For hiding
Filtering was now instant again, but I remembered whilst searching for an answer I heard that negative top margins don’t work too well on older browsers. Well I fired up IETester to give it a test in some of the older versions of Internet Explorer and they were right. The elements still showing should collapse downwards but in Internet Explorer 8 and below they don’t collapse properly, but instead gaps are left where the hidden elements once were.
To fix this I ended up detecting if the user was using Chrome using my own version of the jQuery browser function which you can find below:
(function ($) {
var userAgent = navigator.userAgent.toLowerCase();
$.browser = {
version: (userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [0, "0"])[1],
chrome: /chrome/.test(userAgent),
safari: /webkit/.test(userAgent),
opera: /opera/.test(userAgent),
msie: /msie/.test(userAgent) && !/opera/.test(userAgent),
mozilla: /mozilla/.test(userAgent) && !/(compatible|webkit)/.test(userAgent),
};
})(jQuery);
And then I used the following to do the rest:
var $cssSelector = "display";
var $hideCSS = "none";
var $showCSS = "block";
if ($.browser.chrome) {
$cssSelector = "margin-top";
$showCSS = "0";
$hideCSS = "-10000px";
}
$("#element").css($cssSelector, $showCSS); // For showing
$("#element").css($cssSelector, $hideCSS); // For hiding
I haven’t tested to see whether this works in earlier versions of Chrome but I can’t see it being much of an issue as Chrome automatically updates with each stable release.