IE :hover

I discovered for myself that hover event is working very slow in some cases (especially on IE), and here I will describe them, and try to suggest solutions for Chrome and IE.

multibkg-3

I read one more time this resource and this resource, and I was sure I was doing right way. Other resources: mouseover, poor performance on IE. It feels hacky. So I googled this simple example/visualization. First I thought that it’s CSS performance issue for all browsers. And fixed it for Chrome. But even example has performance lack on IE.

On my project I have list of <DIV> elements over 1000 items, and this css.

Chrome

So first my mistake was “Using nested CSS selectors with :hover pseudo selector inside”. When I remove it, performance is ok. So I decided to use JavaScript to toggle class “.hover” to element, so that child element can have appropriate css selector path.
But still in a nutshell of IE engine it does the same, so performace lacks.

Internet Explorer (10)

I tried these items:

  • – fix: no DOCTYPE.
  • – fix: DOCTYPE TRANSITIONAL (in example it’s by default).
  • – fix: remove line-height from CSS.
  • – fix: remove :hover inside selectors and use .hover class.
  • – fix: instead of visibility use opacity. Visibility the same.
  • – fix: set exact width of table and td doesn’t help.

This suggestions are slow on Chrome and IE as well.

This was my first guess how to implement:

tr:hover td { 
 background-color: #A1AFD4; 
 border: 1px #000000 solid;
}

Event delegate from table to child fail:

$('table').hover(
	
	   function(e){
			if ( $(e.target).is('tr') ) 
				$(e.target).addClass('hover');
	   },
	   function(e){
			if ( $(e.target).is('tr') ) 
				$(e.target).removeClass('hover');
	   }
);

Because if you hover table and you are inside of table, mouse hover event doesn’t fire again 🙂 only after mouseleave 🙂

This almost the same code, fail as well 😦 But at least it works like expected, event is delegated, but performance still THE SAME BAD.

$("table").delegate("tr", "hover", function ( event ) {
    if (event.type == 'mouseover' || event.type == 'mouseenter') {
        $(event.currentTarget).addClass('hover');
    } else {
        $(event.currentTarget).removeClass('hover');
    }
});

That exampled googled based on TABLE TR TD approach, and that is why on IE it slow. But using P DIV SPAN approach with the same structure and css, IT FAST 🙂 better than tables. Crap, example is tricked me. Fail again. I tried to get rid of display: table and removed all Bootstrap classes, and create my own structure:

<div class="yopta">
 <div>
 <span class="c1">123 </span><span class="c2">456</span><span class="c3">789</span>
 <span class="c4">123 </span><span class="c5">456</span><span class="c6">789</span>
 <span class="c7">123 </span><span class="c8">456</span><span class="c9">789</span>
 <span class="c10">123 </span><span class="c11">456</span><span class="c12">789</span>
 </div><div>
 <span class="c1">123 </span><span class="c2">456</span><span class="c3">789</span>
 <span class="c4">123 </span><span class="c5">456</span><span class="c6">789</span>
 <span class="c7">123 </span><span class="c8">456</span><span class="c9">789</span>
 <span class="c10">123 </span><span class="c11">456</span><span class="c12">789</span>
 </div><div>
 <span class="c1">123 </span><span class="c2">456</span><span class="c3">789</span>
 <span class="c4">123 </span><span class="c5">456</span><span class="c6">789</span>
 <span class="c7">123 </span><span class="c8">456</span><span class="c9">789</span>
 <span class="c10">123 </span><span class="c11">456</span><span class="c12">789</span>
 </div><div>
 <span class="c1">123 </span><span class="c2">456</span><span class="c3">789</span>
 <span class="c4">123 </span><span class="c5">456</span><span class="c6">789</span>
 <span class="c7">123 </span><span class="c8">456</span><span class="c9">789</span>
 <span class="c10">123 </span><span class="c11">456</span><span class="c12">789</span>
 </div><div>
 <span class="c1">123 </span><span class="c2">456</span><span class="c3">789</span>
 <span class="c4">123 </span><span class="c5">456</span><span class="c6">789</span>
 <span class="c7">123 </span><span class="c8">456</span><span class="c9">789</span>
 <span class="c10">123 </span><span class="c11">456</span><span class="c12">789</span>
 </div><div>
 <span class="c1">123 </span><span class="c2">456</span><span class="c3">789</span>
 <span class="c4">123 </span><span class="c5">456</span><span class="c6">789</span>
 <span class="c7">123 </span><span class="c8">456</span><span class="c9">789</span>
 <span class="c10">123 </span><span class="c11">456</span><span class="c12">789</span>
 </div>
 </div>

It’s basically huge LIST of SPAN/DIV elements inside of DIV(s). Tried all variants.

CONCLUSION:

When u have parent DIV element, and many children inside (>2 at least I tested so), U WILL HAVE low performance on this CSS selector:

.parent:hover .child {
   background-color: red;
}

SO WHAT TO DO ???
One fix that can work depending on situation is to add position:relative to the hovered element (where appropriate).

Next what was Googled:

Best practices from Google Page Speed:

  • Avoid descendant selectors: table tbody tr td
  • Avoid redundant ancestors: body section article (body never needed)
  • Avoid universal (*) selectors: body *
  • Avoid tag selectors as the key (right-most): ul li
  • Avoid child or adjacent selectors: ul > li > a
  • Avoid overly qualified selectors: form#UserLogin (# is already specific)
  • Make your rules as specific as possible (class or id).
  • Avoid the :hover pseudo-selector for non-link elements for IE clients.
  • If you use :hover on non-anchor elements, test the page in IE7 and IE8 to be sure your page is usable. If you find that :hover is causing performance issues, consider conditionally using a JavaScript onmouseover event handler for IE clients.

Notes from me:

  • not use mouseover because it’s NOT BUBBLING !!!

Another resource tells:
The problem is more than likely the rendering of the controls (100 select boxes) rather than the table layout.

Ok, so here is an example of code (trying to figure out better solution)

<p>
<div>
<span>0</span>
<span>0</span>
<span>0</span>
<span>0</span>
<span>0</span>
<span>0</span>
<span>0</span>
<span>0</span>
<span>0</span>
<span>0</span>
<span>0</span>
<span>0</span>
<span>0</span>
<span>0</span>
<span>0</span>
<span>0</span>
<span>0</span>
<span>0</span>
<span>0</span>
<span>0</span>
...... MANY SUBLINGS !!!!
</div>
</p>

And this code is ok with this css:
p div:hover {
 background: yellow;
}

When I change structure to this

P > DIV > DIV
Result will be the same, I mean this CSS rule will work fine ON IE as well.
p div:hover {
 background: yellow;
}

OUTCOME:

  • Avoid selectors like div > div > a and regexp selectors.

 

But if DIV has CSS {float:left} IT CAUSING SLOWNESS … so failed again …

In fact DIVs with display-inline-block are a bit faster than DIVs with float:left but not so critical. In case with Twitter Bootstrap it’s about DIV’s with [class*=’span’], and looks like this regex selector is really heavy when applying to large lists.

So looks like as many .CHILD elements inside .PARENT element, .PARENT:hover will slowdown and slowdown on IE 😦 … and it doesn’t depend on any HTML/CSS/Javascript approaches. it’s f*cking IE … and their way how it handle hover (mouseenter/mouseleave) event.

Besides, Twitter Bootstrap is using heavy selectors, and I can’t override them all:

.row:before, .row:after { display: table; },
.row-fluid [class*='span'] {... float: left; ...}

At this time, I don’t have ideal solution for my project. But more than sure – if we get rid of Twitter Bootstrap regexp selectors in grid system, it should increase performance of hovering.

OUTCOME:

  • Avoid using float-ing.

Another CSS example (#TBD)

/*SLOWER*/
.views .datagrid-row:hover .column-zero + .datagrid-cell{
  border-left: 1px solid #88B2CF; /* or whatever */
}

“+” was used to avoid hardcode “by nth-child(2)”, BUT.
As turned out it VERY slows IE work, so, better to use nth-child() in this case.
But this rule doesn’t work when columns reordered by drag-n-drop. Kinda complicated.

/*FASTER*/
.views .datagrid-row:hover .datagrid-cell:nth-child(2){
  border-left: 1px solid #88B2CF; 
}

OUTCOME:

  • Avoid selectors like div + li > a (“+” SLOWS IE VERY MUCH)
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s