JQuery cross-browser performance: .animate () in .hover () on over 100 DOM elements

This is my difficulty.

Let me just set the scene:

I have a grid of absolutely positioned elements whose height, width, and position (top and left) are percentages of their container. Basically, it's a grid of boxes that will dynamically resize to always fit the width of the window while maintaining a consistent aspect ratio. Each of these fields should be a clickable link and should contain text that will resize accordingly when resized.
The HTML looks something like this:

<div id="container">
    <!-- The container width is 95% of the window -->
    <img alt="" src="images/aspect-holder.png">
    <!-- This image makes sure the container retains the correct aspect ratio* -->
    <a href="link1" class="element col1 row1">
        <span>Some</span>
        <span>Text</span>
              ...
    </a>
    <a href="link2" class="element col1 row2">
        <span>Other</span>
        <span>Text</span>
              ...
    </a>
    <a href="link3" class="element col1 row3">
        <!-- as above -->
    </a>
              ...
              ...
    <a href="link100something" class="element col18 row9">
        <!-- as above -->
    </a>
</div>

      

* This describes a method using an image to maintain the aspect ratio

The CSS for the grid is pretty simple and the only thing that is noteworthy is that I set the spans font size in the anchor tag as percentages so that I can use JQuery to manipulate them easily, either by manipulating the font size of their parent (anchor) or their parent parent (#container).

Now about the problem:

What I wanted, besides the dynamic nature of the grid, was that whenever the user hovers over one box, he has to "zoom in". Essentially on the mouse field, the window would grow in height and width and shrink its top and left margins to "pop out" of the page. The following is the JQuery I wrote to put it all together: (sorry for any egregious mistakes, I'm here to learn)

container = $('#container');
anchor = container.find('a');
//The Globals have more unique names but I wrote them like this here
//to make it easier to read

//This part handles the font-size resize on Load and on Resize
function fontfix() {
    container.css('font-size', anchor.width() + 'px');
}

$(function() {
    fontfix();
});

$(window).resize(function() {
    fontfix();
});

//This is the code that handles the 'smooth' hover* animation
anchor.hover(function() {
    $(this).filter(':not(:animated)').css('z-index', 2).animate({
        marginTop: '-1.9%',
        marginLeft: '-1.5%',
        height: '15%',
        width: '8%',
        fontSize: '157%'
    });
}, function() {
    $(this).css('z-index', 1).animate({
        marginTop: '0%',
        marginLeft: '0%',
        height: '9.5393%',
        width: '5.2604%',
        fontSize: '100%'
    }, function() {
        $(this).attr('style', '');
    });
});

      

* .filter (': not (: animated)') builds on Chris Coyer's CSS-Tricks article on full jQuery animation .

And it works! ... Well, in WebKit and Opera, or in other browsers, for less than 30 or 40 elements. With 100+ elements on Firefox 10, its stuttering and somewhat lagging, while on IE8 it's practically a slideshow. This disappointed me with this as I was hoping to make it as cross-browser as possible and so I really hope the girls and guys can help you.

So to summarize

  • Did I fake globals? Should I be using something else?
  • Is there a way to make the animation smooth across all browsers?
  • Are there any other tweaks for this code that you would do? Or anything else to celebrate?

Thanks for reading for so long and regretting the long post! Any help with this is appreciated.

Demo on JsFiddle

Violin link http://jsfiddle.net/kkubD/


As it is, it works like a dream in Chrome, on FF you should see a stutter and on IE you should stutter even more.

As an aside, I understand that I can and may need to use an unordered list and thus wrap all my bindings in <li>

s, but I could not find a compelling enough reason for this, since the grid in its current format looks like (even better ) even without CSS. I guess I would find the improved scanning ability or performance as a good enough reason, but I don't know if it will add anything. Am I wrong about that?

+3


source to share


1 answer


Max,

I had a good old game with this and came up with something better, at least in Opera, which initially fought its way through the way you describe for FF.

The result is a two-step custom animation with an instant first step and then a setTimeout()

delay before the second step. At each step, it is used .css(...)

to call one of three hard-coded cards.

mouseenter

and the mouseleave

processing is delegated to the container, and while it doesn't seem particularly important to performance (on my hardware) it should consume less memory.

Overall, I find the resulting performance will vary depending on the vagaries of how long the OS timeframe (Win 7 here) decides to give me the Opera tab. At worst, the visual effect is still a little sluggish and very smooth at best. This varies from minute to minute and is updated prior to being updated.



Here's the code:

$(function() {
    var iam_container = $('#container');
    var iam_anchor = iam_container.find('a').data('t', null);

     $(window).resize(function() {
        iam_container.css('font-size', iam_anchor.width() + 'px');
    }).resize();

    var css_0 = {
        marginTop: 0,
        marginLeft: 0,
        height: '9.5393%',
        width: '5.2604%',
        fontSize: '100%',
        zIndex: 0
    };
    var css_1 = {
        marginTop: '-0.95%',
        marginLeft: '-0.75%',
        height: '12.27%',
        width: '6.63%',
        fontSize: '125%',
        zIndex: 1
    };
    var css_2 = {
        marginTop: '-1.9%',
        marginLeft: '-1.5%',
        height: '15%',
        width: '8%',
        fontSize: '157%',
        zIndex: 2
    };

    function anim($elem, map, delay) {
        clearTimeout($elem.data('t') || null);
         $elem.css(css_1).data('t', setTimeout(function(){$elem.css(map);}, delay));
    }

    iam_container.on('mouseenter', 'a', function() {
        anim($(this), css_2, 50);
    }).on('mouseleave', 'a', function() {
        anim($(this), css_0, 50);
    });
});

      

The 50ms pause latency is experimental and may be better at 100ms or 150ms, otherwise the intermediate animation step may not be perceived on faster hardware.

And here's the fiddle :

+2


source







All Articles