Prevent CSS :hover style propagation
Solution 1
This is impossible to do with CSS only, except the not-so-clean way described by @Pointy.
You can do this with javascript by using event.stopPropagation()
. So your hover style should become a class that you toggle on mouseover.
This question is a duplicate of css :hover only affect top div of nest
Solution 2
I could not find an answer that worked in all cases, and was also simple to implement. Sadly, there appears to be no consistent solution that is purely CSS and/or requires special arrangements of the HTML.
Here is a jQuery solution that seems to work in all cases.
Any element with .ui-hoverable
will receive a .ui-hover
class that does not propagate. So you can stack .ui-hoverable
elements and only the top-most under the mouse will have the .ui-hover
class.
$('.ui-hoverable').each(function() {
var el = $(this);
el.on('mousemove', function () {
var parent = $(event.target).closest('.ui-hoverable');
if(parent.length && parent[0] == el[0]) {
el.addClass('ui-hover');
return;
}
el.removeClass('ui-hover');
});
el.on('mouseleave', function () {
el.removeClass('ui-hover');
});
});
This works because the mousemove
event searches for the closest .ui-hoverable
and if it is not the current element the .ui-hover
is removed. So the top most will receive the .ui-hover
and an element under it will have it removed.
Enjoy, report any problems.
Thanks,
Solution 3
You can make a negation caluse like Pointy suggests but a more solid solution involves adding an extra node. The idea is that the row and the button become proper siblings since you can't style a TextNode.
<ul class="list-group">
<li class="list-group-item">
<div>Lalalalaiaia</div>
<button class="btn btn-default btn-xs pull-right remove-item">
<span class="glyphicon glyphicon-remove"></span>
</button>
</li>
<li class="list-group-item">
<div>Panananannaeue</div>
<button class="btn btn-default btn-xs pull-right remove-item">
<span class="glyphicon glyphicon-remove"></span>
</button>
</li>
</ul>
Now you can do:
.list-group-item div:hover {
background: #fafafa;
cursor: pointer;
}
You will need some extra trickery to get the button in the right place, like:
// untested
.list-group-item {
position: relative;
}
.list-group-item button {
position: absolute;
top: 5px;
left: 5px;
}
zok
Updated on July 09, 2022Comments
-
zok almost 2 years
In the following example, when I mouse over the 'X' button, the list-item
hover
style gets enabled as well, I do not want this to happen.Is it possible to have a
hover
style on the button independent of thehover
style on thelist-group-item
? Something like prevent the 'hover' propagation?Is there any other way to achieve that? Maybe assembling all of this HTML/CSS/JS in a different way?
<ul class="list-group"> <li class="list-group-item"> Lalalalaiaia <button class="btn btn-default btn-xs pull-right remove-item"> <span class="glyphicon glyphicon-remove"></span> </button> </li> <li class="list-group-item"> Panananannaeue <button class="btn btn-default btn-xs pull-right remove-item"> <span class="glyphicon glyphicon-remove"></span> </button> </li> </ul>
CSS
.list-group-item:hover { background: #fafafa; cursor: pointer; }
JavaScript
$('.list-group-item').on('click', function(){ console.log('clicked item'); }); $('.remove-item').on('click', function(e){ console.log('clicked remove-item btn'); e.stopPropagation(); });
UPDATE
The problem seems to be that when hovering the inner X button, the mouse actually doesn't leave the 'list-group-item' element, thus, it keeps the hover state.
I was able to solve it by manually dispatching
mouseenter
andmouseleave
on the 'list-group-item' in themouseleave
andmouseenter
event of the 'remove-item' button, respectively, without the need to use 'event.stopPropagation()' (except for the button click handler).The drawback is that I need a
mouseenter
and amouseleave
event handler for both elements. Preferably I'd use only CSS, but that seems to be impossible.I'm just not sure whether this is a clean solution, what do you think?
CSS
.list-group-item.mouseover { background: #fafafa; cursor: pointer; } .list-group-item .remove-item.mouseover { background: #aaf; cursor: pointer; }
JavaScript
// LIST-ITEM EVENT HANDLERS $('.list-group-item').on('mouseenter', function(e){ $(this).addClass('mouseover'); }).on('mouseleave', function(e){ $(this).removeClass('mouseover'); }); $('.list-group-item').on('click', function(){ console.log('clicked item'); }); // LIST-ITEM REMOVE BUTTON EVENT HANDLERS $('.remove-item').on('mouseenter', function(e){ $(this).addClass('mouseover'); $(this).parent().mouseleave(); }).on('mouseleave', function(e){ $(this).removeClass('mouseover'); $(this).parent().mouseenter(); }); $('.remove-item').on('click', function(e){ console.log('clicked remove-item btn'); e.stopPropagation(); });
-
zok almost 10 yearsThat's a good idea, and the button would be perfectly aligned by adding
display: inline
to the wrapping div, but the background color would be applied only to the text, not the whole list-item background.. -
zok almost 10 yearsYeah, I guess the only way is to have an event handler to handle the mouseover event. or to place the remove button outside the
li
but next to it somehow, but that doesn't seem to be a good idea -
Halcyon almost 10 yearsRemove any padding from the list-item. It doesn't matter if the background is on the list-item or the div.