Search code examples
htmlcsshover

Is there a selector to only affect the innermost :hover match with CSS only?


For a feature to manage custom layouts, I've created a little wizard with zone indication, to offer a chance on seeing which zone you're editing.

Since it's a nested layout, all containers have the same CSS class values. In order to only issue the innermost element I've written a short piece of JavaScript code. To be precise, it's this:

$outermostContainer.on("mousemove", function(event) {
    var $t = $(event.target).closest("table.dashboardLayoutOutline");
    $layoutWizardTables.removeClass("hovering");
    $t.addClass("hovering");
});

Sample case:

http://jsfiddle.net/w0sw9510/ (The solution is correct if you hover one of the child elements and the parent element does not have a yellow border, while if you hover the outer element only that will receive a yellow border)

Is this really a case where I can't do something with CSS only?

I somehow can't imagine I'm the only one who has a use for this.

I've looked into W3C + mozilladocs for CSS 2/3 selectors and no selector I've seen appeared to handle the case I need.

These days I mainly do backend, so I hope there's one of you who knows a trick for me.

Duplicate questions: While this problem is similar to my issue, I did not find it while searching because of its title. I am just going to leave it here so others will find their answer too in case they use the same search words.


Solution

  • It doesn't seem possible with just CSS, because when a child element is hovered the parent element is hovered too (and pointer-events: none doesn't help). However JavaScript makes it pretty simple:

    $('.zone').on('mouseover mouseout', function(e) {
        $(this).toggleClass('hovering', e.type === 'mouseover');
        e.stopPropagation();
    });
    .zone {
        margin: 10px;
        box-sizing: border-box;
        border: 5px solid transparent;
    }
    
    .zone.hovering {
        border: 5px solid yellow;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div class="zone" id="parent" style='background-color: orange;'>
        <div class="zone" id="child1" style='background-color: red;'>a</div>
        <div class="zone" id="child2" style='background-color: blue;'>b</div>
    </div>

    Well, it's actually possible to do this in just CSS, but the solutions are not very flexible and generic, because it depends on the background color of the parent container:

    .zone {
        margin: 10px;
        box-sizing: border-box;
        border: 5px solid transparent;
        position: relative;
    }
    
    .zone:hover {
        border: 5px solid yellow;
    }
    
    .zone > .parent-border {
        position: absolute;
        top: -5px; left: -5px; bottom: -5px; right: -5px;
        display: none;
        z-index: 1;
    }
    
    .zone > .zone {
        z-index: 2;
    }
    
    .zone > .zone:hover ~ .parent-border {
        border: 5px orange solid;
        display: block;
    }
    <div class="zone" id="parent" style='background-color: orange;'>
        <div class="zone" id="child1" style='background-color: red;'>a</div>
        <div class="zone" id="child2" style='background-color: blue;'>b</div>
        <div class="parent-border"></div>
    </div>