防止 CSS :hover 样式传播

Posted

技术标签:

【中文标题】防止 CSS :hover 样式传播【英文标题】:Prevent CSS :hover style propagation 【发布时间】:2014-10-04 11:16:55 【问题描述】:

在以下示例中,当我将鼠标悬停在“X”按钮上时,列表项 hover 样式也会启用,我不希望这种情况发生。

按钮上的hover 样式是否可以独立于list-group-item 上的hover 样式?诸如防止“悬停”传播之类的东西?

还有其他方法可以实现吗?也许以不同的方式组装所有这些 html/CSS/JS?

Working sample here

<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();
  );

更新

问题似乎是当鼠标悬停在内部 X 按钮时,鼠标实际上并没有离开 'list-group-item' 元素,因此,它保持悬停状态。

我能够通过在“删除项目”按钮的 mouseleavemouseenter 事件中的“列表组项目”上手动调度 mouseentermouseleave 来解决这个问题,而无需需要使用'event.stopPropagation()'(按钮点击处理程序除外)。

缺点是我需要两个元素的mouseentermouseleave 事件处理程序。我最好只使用 CSS,但这似乎是不可能的。

我只是不确定这是否是一个干净的解决方案,你怎么看?

Working sample here

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();
  );

【问题讨论】:

只需为 .list-group-item:hover button 创建一个样式,取消组项本身的悬停样式。 @Pointy - 但是.list-group-item:hover button 上的规则会更改按钮的 CSS,而不是列表项,这是 OP 想要更改的。当您将鼠标悬停在按钮上时,他希望它不会激活列表悬停(或看起来不像激活)。 @j08691 哦,好吧,我猜他不希望按钮受到列表组上可继承样式的影响,但看看那些我不知道为什么;背景可能不会改变按钮背景。也许是光标? @Pointy,正好相反,就像 j08691 写的:) @zok 哦哦,我明白了。因此,您希望它在您越过它时使项目变暗,但是当您越过按钮时,它应该保持项目变暗。这对 CSS 来说很难/不可能。我有点想知道它是否看起来不会有点奇怪。我的意思是,毕竟光标仍然在项目上。 【参考方案1】:

除了@Pointy 描述的不太干净的方式外,这不可能只用 CSS 来实现。 您可以使用 event.stopPropagation() 使用 javascript 来执行此操作。因此,您的悬停样式应该成为您在鼠标悬停时切换的类。

这个问题与css :hover only affect top div of nest重复

【讨论】:

是的,我想唯一的方法是有一个事件处理程序来处理鼠标悬停事件。或将删除按钮放在li 之外,但不知何故放在它旁边,但这似乎不是一个好主意【参考方案2】:

您可以像 Pointy 建议的那样进行否定,但更可靠的解决方案是添加一个额外的节点。这个想法是行和按钮成为正确的兄弟,因为您不能设置 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>

现在你可以这样做了:

.list-group-item div:hover 
  background: #fafafa;
  cursor: pointer;

您需要一些额外的技巧才能将按钮放在正确的位置,例如:

// untested
.list-group-item 
  position: relative;

.list-group-item button 
  position: absolute;
  top: 5px;
  left: 5px;

【讨论】:

这是个好主意,通过将 display: inline 添加到包装 div,按钮将完美对齐,但背景颜色将仅应用于文本,而不是整个列表项背景。 . 从列表项中删除任何填充。无论背景是在列表项还是 div 上都没有关系。【参考方案3】:

我找不到适用于所有情况的答案,而且实施起来也很简单。可悲的是,似乎没有一致的解决方案纯粹是 CSS 和/或需要对 HTML 进行特殊安排。

这是一个似乎适用于所有情况的 jQuery 解决方案。

任何带有.ui-hoverable 的元素都将收到一个不会传播的.ui-hover 类。因此,您可以堆叠.ui-hoverable 元素,并且只有鼠标下方最上面的元素才会有.ui-hover 类。

$('.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');
    );
);

这是有效的,因为mousemove 事件搜索最接近的.ui-hoverable,如果它不是当前元素,则删除.ui-hover。所以最上面的会收到.ui-hover 并且它下面的元素会被删除。

享受,报告任何问题。

谢谢,

【讨论】:

以上是关于防止 CSS :hover 样式传播的主要内容,如果未能解决你的问题,请参考以下文章

如何防止点击事件传播

JCrop + 防止点击传播

防止键盘事件在 Flutter 中冒泡(传播给父母)

如何防止 Apollo 客户端 useQuery 中的错误传播?

Python:防止信号传播到子线程

javascript 防止儿童点击传播