Open Bug 895810 Opened 6 years ago Updated 5 years ago

CSS :hover styling not being removed when pointer leaves target element

Categories

(Core :: CSS Parsing and Computation, defect)

x86_64
All
defect
Not set

Tracking

()

People

(Reporter: standsthechurchclock+mozilla, Unassigned)

References

Details

(Keywords: regression)

Attachments

(2 files, 1 obsolete file)

I have been using a standard CSS approach to generate a popup menu when a user moves over a trigger area. Under some circumstances, I am seeing the correct actions taken when a :hover rule is activated, but it is sometimes not being deactivated when the pointer moves from the relevant area. The problems seem to occur when more than one element has an applicable :hover rule associated with it. The following minimal code demonstrates the problem:

    <html>
      <head>
        <style type="text/css">
          span.dropdown { display: none; }
          span.dropdown_trigger:hover span.dropdown { display: block; }
          div.menu { position: absolute; border: 1px solid black; background-color: white; }
          tr:hover { background-color: yellow; }
        </style>
      </head>
      <body>
        <table>
          <tr>
            <td>
              text text text text
              <span class="dropdown_trigger">
                trigger trigger trigger trigger
                <span class="dropdown">
                  <div class="menu">content content content content content content</div>
                </span>
              </span>
            </td>
          </tr>
        </table>
      </body>
    </html>

This is what I expect to see:
 * The page should show a table with some plain text and some "trigger" text in it.
 * When the pointer is moved over any part of the table row, the row should change background colour to yellow.
 * When the pointer is moved over the trigger text, a popup should become visible containing some content.
 * When the pointer is then moved out of the table, the popup should disappear, as should the yellow background colour of the row.

This is what I actually see when viewing this code in Mozilla Firefox 22.0 for Ubuntu:

 * The page loads correctly: the plain text and "trigger" text is visible
 * When the pointer is moved over any part of the table row, the row correctly changes background colour to yellow.
 * When the pointer is moved over the trigger text, a popup correctly becomes visible containing some content.
 * If I move the pointer over the popup, it correctly remains visible, and the row correctly remains yellow.
 * The behaviour then depends on the direction and speed of the mouse movement:
   - If I move the pointer downwards, off the bottom of the popup, the row correctly reverts to a non-yellow background. However, the popup remains visible.
   - If, instead, I move the pointer very slowly upwards, the popup disappears first, then the row becomes non-yellow. This is correct behaviour.
   - If, instead, I move the pointer very quickly upwards, the popup incorrectly remains visible, but the row correctly becomes non-yellow.

If the CSS line:

          tr:hover { background-color: yellow; }

is removed, no yellow colouring takes place, and the popup behaves entirely correctly. For example, moving the pointer off the bottom of the popup results in the popup disappearing. However, if the CSS line is replaced by:

          tr:hover { }

there is, naturally, still no yellow colouring, but the incorrect popup behaviour is as before.

This bug report so far has been entirely factual, but what follows is speculation, and may be incorrect:

It seems likely that these CSS changes are implemented by Firefox looking for mouse enter and mouse leave events associated with elements which have CSS :hover rules. When one of these events is seen, appropriate changes are made to the styling of affected elements. However, the behaviour described above is consistent with an approach where the occurrence of a second mouse leave event causes the processing of an earlier event to be terminated if that processing has not completed. This would explain the behaviour as seen:

    For upwards pointer movements, there is a small area which is part of the table row, but not the trigger area. Where the pointer is moving slowly, there is time to process the first of these events and remove the popup before the second event is generated, requiring the removal of the yellow.
    For downward pointer movements, the two mouse leave events would be generated at the same time. Provided the trigger area leave event is generated first, and followed immediately by the row leave event, the second event would cause the first not to be processed, and the behaviour would be as seen.

This report follows some discussion here:

  http://forums.mozillazine.org/viewtopic.php?f=25&t=2730365

with the following comments added by user jscher2000:

I can definitely confirm that the absolutely positioned div stubbornly sticks around in many mouse-out scenarios. I happen to also have Portable Firefox 13 for some reason, and get the same behavior there, so I don't think it's a new issue in Firefox 22.

Just to be clear, position:absolute is not necessary to replicate the problem.

However, it does seem that block-element-within-inline-element may be necessary to replicate the problem. If I add the following rule, I can no longer replicate the problem:

    span.dropdown_trigger { display: inline-block; }

It is possible that this relates to Bug 544150.
Regression window(m-c)
Good:
http://hg.mozilla.org/mozilla-central/rev/88fa0b783306
Mozilla/5.0 (Windows; U; Windows NT 6.1; WOW64; en-US; rv:1.9.3a6pre) Gecko/20100618 Minefield/3.7a6pre ID:20100618085618
Bad:
http://hg.mozilla.org/mozilla-central/rev/d4156799e66a
Mozilla/5.0 (Windows; U; Windows NT 6.1; WOW64; en-US; rv:1.9.3a6pre) Gecko/20100617 Minefield/3.7a6pre ID:20100618100908
Pushlog:
http://hg.mozilla.org/mozilla-central/pushloghtml?fromchange=88fa0b783306&tochange=d4156799e66a

In local build,
Last Good: d594bc58ca6b
First Bad: dee1e84a95aa
Regressed by:
	dee1e84a95aa	Boris Zbarsky — Bug 494117 part 2. Don't force selector matching on the whole subtree rooted at an element when the element's style changes. r=dbaron
Blocks: 494117
Status: UNCONFIRMED → NEW
Ever confirmed: true
Keywords: regression
OS: Linux → All
Attached file reporter's testcase
Attached file Simpler testcase (obsolete) —
So what happens here is that the :hover style on the parent means that we start the reresolve there.  We then walk its kids.  When we get to the first frame for the ib-split span, we ask the restyle tracker for any info it has about it, and it says "reresolve all the descendants".  But the first frame only has text as a descendant... and by the time we get to the later continuations of the ib split, we've lost the "reresolve the descendants" information.

In fact, you can get the same bug with continuations, without any need of block-inside-inline stuff; testcase for that coming up.

David, should I look for a way to spot-fix this, or are you planning to do your ReResolveStyleContext redesign soonish?
Flags: needinfo?(dbaron)
Depends on: 828312
Flags: needinfo?(dbaron)
Hopefully going to finish bug 828312 soonish.
I'm still seeing this bug (in Firefox 30.0).  I can reproduce using the first two test cases above, although the third works correctly.
Something in my patch queue for bug 996796 fixes this.
Er, I think the "Even simpler testcase" was fixed before my patches, but the original testcase isn't.
You need to log in before you can comment on or make changes to this bug.