Label :hover attribute triggers incorrect element

2020-07-11 08:17发布

问题:

This is a little weird, but bear with me. This only affects IE10 and IE11, doesn't affect Chrome, FF, Safari, and IE9 and older. If you have a <label> for another element nested within a class that the :hover is assigned to, it will match that selector, even if you are not hovering over that element. In the example below, if you hover over the first div, both divs are highlighted.

<div>
    <select id="min-price">
        <option>A</option>
    </select>
</div>

<div>
    <label for="min-price"></label>
    <select>            
        <option>B</option>
    </select>
</div>     

and this CSS:

div {
    padding: 1em;
    margin-bottom: 1em;
    border-bottom: 1px solid red;
}

div:hover {
    background: #f1f1f1;
}

div:hover > select {
    background-color: #a3a3a3;
}

Example can be found here.

http://jsfiddle.net/0c67oew2/3/

Any anyone explain why this is happening?

回答1:

I'm going to note before you read this answer that I am an engineer on the Internet Explorer team.

First of all, this is a really cool discovery. What you've stumbled upon is actually a "feature" (quite possibly a bug) of Internet Explorer that doesn't appear to exist in Chrome or Firefox. Let me try to break down an understanding of what is happening, why this is kind of cool, and what you can do to avoid complications with it:

Labels and input elements can become intrinsically related by way of the [for] attribute on a label pointing to the [id] attribute on an input element. As a result, when you click on a label, it can toggle a checkbox, or apply focus to an input field. This feature is often times leveraged to create progressively-enhanced radio buttons and more.

On a related note, when you hover over a label, the associated input element is also hovered. This is the case with Internet Explorer, Firefox, Chrome, and just about everybody else. But what Internet Explorer does differently is apply the hover bi-directional. So if you hover the associated input control, Internet Explorer also invokes :hover on the related label.

This is where things get cool. This allows us to create relationships like the one seen below:

Note here that the relationship is bi-directional, meaning any hover on an input is not simply a hover on itself and its ancestral tree, but also a hover on its associated label. And any hover on a label is a hover on itself, its ancestral tree, and its associated input. This brings us one step closer to understanding what's at play in your demo, and why you're seeing such bizarre results.

When you hover an element, you are covering its parents too. As an example, suppose we had a div with a button inside of it. Any hover on the button is inherently a hover on the parent div as well. You can't get to the children without first going through the parents as far as a cursor is concerned. The same rule applies here; when a label or input is hovered, so too are its parents.

In your demo you have a series of div elements with select elements and label elements inside. You're basing styles for the select elements on the hover pseudo-class of their parent div. So when you hover the select, it invokes the hover of its associated label, which causes the hover of its parent, which affects the styles of any nested select.

Subsequent Suggestion

While the [for] attribute allows you to place label elements just about anywhere, you should proceed in doing so only with special awareness to how this will affect selectors operating off of :hover propagation up the ancestral tree.

Before a complete solution can be given, I must ask why you are putting an empty label in a seemingly arbitrary location in the first place. What visual effect are you trying to achieve? I suspect we could accomplish the same visual layout with different markup.

Following Up from Here

I'm going to open a bug against this in our Internal database, because I get the feeling that this isn't entirely intentional on our part. Our aim, I believe, is to treat the behavior the same bi-directionally, rather than handling the two routes differently.



回答2:

I recommend using :focus instead of :hover when dealing with form inputs. One reason for this is because if a user tabs through using a keyboard, the hover won't do anything, but a focus will.

.control .price:focus {
  background: #a3a3a3;
}