CSS:当子元素被点击时,如何防止父元素获取:active伪类

38

JSFiddle

当您点击时,您会看到父

元素的:active伪类被触发。是否有一种纯CSS(或某些JS库)的方法,使:active伪类在button点击时不会切换?

我尝试了z-indexposition: absolute & fixed等方法,但没有成功。


这里的目标是什么?父元素是否需要成为 :active - Amit
@Amit,我的目标是不希望“div”在其子元素点击时获取“:active”类。 - knitevision
是的,我明白了...你想让它在其他事件中也生效吗?否则,就删除这个规则。 - Amit
@RobertMcKee,这里如何使用“tabindex”? o_O - knitevision
@Amit 这只是一个简化的例子。在真实版本中我有很多东西。div 有它自己的 :active 状态,不应该在它的子元素点击时触发。 - knitevision
显示剩余3条评论
12个回答

20

根据规范

选择器并未定义如果元素的父级处于“:active”或“:hover”状态,该元素是否也处于该状态。

这意味着它取决于实现。如果一个实现选择以这种方式操作(正如当前的浏览器所做的),则标准中没有任何东西可以改变它。

使用CSS4,您可能能够执行以下操作:

.parent:active:not(:has(:active)) {
   color: red;
}

但目前这还不可用,也还没有最终确定。


3
可以简单地用标准样式来覆盖 div:active 类。这样,div 元素的活动状态就不会改变。虽然不太优雅,但可以解决问题。 - Germano Plebani

5

我认为伪类:has永远不会在样式表中得到应用。如果浏览器最终决定实现它,它可能只适用于JS API,如querySelector

然而,我对:focus-within更有希望,因为它似乎更容易实现。

#parent:active:not(:focus-within) {
  background-color: red;
}

当然,这只会在点击像按钮这样的可聚焦元素时防止应用于#parent:active。您可以通过添加tabindex =“-1”使其他元素具有焦点。
不幸的是,:focus-within并没有得到广泛支持,但是您可以使用JS polyfill

#parent {
  border: 1px solid black;
  width: 300px;
  height: 300px;
}
#parent:active:not(.focus-within) {
  background-color: red;
}
<script src="https://gist.githubusercontent.com/aFarkas/a7e0d85450f323d5e164/raw/"></script>
<div id="parent">
  <button>Click me</button>
  <p tabindex="-1">Or me</p>
</div>

Github不允许热链接,所以以上代码片段可能无法正常工作,除非您将polyfill复制到自己的服务器并使用它。


5

如果你真的想只使用CSS解决这个问题:

如果你的按钮是active,添加一个:before伪元素,并使用position: absolute;给:before设置与父元素相同的背景。

button:active::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: #eee;
    z-index: -1;
}

现在唯一需要的就是将父元素设置为:
position: relative;
z-index: 0;

请看这个链接:http://jsfiddle.net/s0at4w4b/4/ 这并没有解决潜在的问题,但能够解决你当前的问题。

4
也许最简单的实现你想要的功能的方式是不把按钮放在你不想启用的
中。
这里有一个容器
,其中包含一个背景
(与你原来的例子中的父
等价)。背景
具有与按钮不同的活动状态。

.container {
  position: relative;
  width: 200px;
  height: 200px;
}
.background {
  position: absolute;
  width: 100%;
  height: 100%;
  border: 1px solid black;
  background-color: #eee;
}
.background:active {
  background-color: red;
}
button {
  position: relative;
}
<div class="container">
  <div class="background"></div>
  <button>Click me!</button>
</div>


我认为这是最简单的解决方案。 - Shaun Lebron
我真的很喜欢你的解决方案! - withparadox2

2

这种方法可能适用于您,但这是我使用纯CSS实现的方式。唯一的注意事项是依赖于focus-within,该属性不受IE或Edge支持。

.parent {
  transition: background-color;
}
.parent:active:not(:focus-within) {
  background-color: red;      
  transition-delay: 1ms; // Delay one cycle to allow child to focus 
}

这里发生的情况是,父元素和被点击的子元素都将获得活动状态。唯一的区别是,焦点将应用于子元素,但仅在下一个周期内。为了避免在这个2步骤过程中出现任何动画,可以应用1ms的延迟。下一个周期,元素将处于活动状态,但焦点将应用于子元素。因此,父元素将不应用过渡效果。我想 animation delay: 1ms 将以同样的方式工作。
另一种选择是给该项添加一个 tabindex=-1 属性并使用
.parent {
  transition: background-color;
}
.parent:active:focus {
  background-color: red;      
}

这样做的唯一问题是它可能会改变键盘导航行为,同时也依赖于一些HTML。如果您确实想使用键盘导航,请使用tabindex=0或任何值而不是-1。但是没有使用JS。
有一些很好的polyfill可以用于IE/Edge的focus-within,但这将超出“仅CSS”的范围。
但是,我们可以将它们组合在一起创建这个:
.parent {
  transition: background-color;
}

.parent[tabindex]:active:focus {
  background-color: red;
}

.parent:active:not(:focus):not(:focus-within) {
  background-color: red;
  transition-delay: 1ms;
}

这适用于IE11,Edge和Chrome浏览器。

http://jsfiddle.net/s0at4w4b/42/


0

这里提供了一个jQuery解决方案,而不是使用CSS伪类:active

$(document).ready(function() {
    $('button').mousedown(function(e){
        e.stopPropagation();
        console.log('i got clicked');
    });

    $('div').mousedown(function(e){
        $('div').css('background', 'red')
    }).mouseup(function(e){
        $('div').css('background', '#eee')
    });
    $(document).mouseup(function(e){
        $('div').css('background', '#eee')
    });
});
div {
  width: 200px;
  height: 200px;
  background-color: #eee;
  border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
  <button>Qlick me</button>
</div>


感谢您的贡献。但是您的JS逻辑非常局限于某些样式。我目前有大约20个不同风格的元素,每个元素内部包含约30个元素,其中有许多不同的CSS属性。应用您的技术需要花费大量时间。当我提到JS方法时,我希望能够采用更抽象和远离具体实现的方法。 - knitevision
如果我制作一个更通用的版本呢?比如点击具有classA的元素,不会触发具有classB的父元素上的活动状态,这样你只需要将classA和classB添加到元素中,并将:active CSS选择器切换为activated,这是否适合您的需求? - indubitablee

0

:active 伪类适用于用户激活元素的时候。例如,在用户按下并释放鼠标按钮之间的时间内。在拥有多个鼠标按钮的系统中,:active 仅适用于主要或主要激活按钮(通常是“左”鼠标按钮)和任何别名。

可能存在文档语言或实现特定的限制,规定哪些元素可以成为 :active。例如,[HTML5] 定义了一个可激活元素的列表。

匹配 :active 元素的父元素也会匹配 :active。 因此,没有办法


0

0

应该编写div:active:not(:hover) {...}而不是div:active {...},这样就可以保持background-color不变。

(删除旧片段)

更新

为了保持主要div的行为不变并采用更通用的方法,我通常会创建几个图层。

请查看下面的片段,切换到green只是为了证明它的工作原理,而positionabsolute现在只是简单粗暴的:

#layer-data {
  width: 200px;
  height: 200px;
  background-color: #eee;
  border: 1px solid black;
}
#layer-data:active {
  background-color: red
}
#layer-btns:active {
  background-color: green
}
#layer-btns {
  z-index: 1;
  position: absolute;
  top: 1px;
  left: 1px;
  background: transparent;
  padding: 5px;
  width: auto;
  height: auto
}
#layer-data {
  z-index: 0;
  position: absolute;
  top: 0;
  left: 0;
  text-align: center;
  line-height: 200px
}
<div id="layer-btns">
  <button>Qlick me</button>
  <br/>
  <button>Qlick me too</button>
  <br/>
  <button>Qlick me three</button>
</div>

<div id="layer-data">
  some data-layer
</div>


这样,div本身也失去了:active 的效果,但它不应该失去。 - knitevision
啊,疏忽了。请给出您拥有的样式示例。我在考虑像JS一样的“toggleStyleList(arList, arValues)”之类的东西。 - Rene van der Lende

0
据我所知,活动状态会冒泡。因此,所有父节点都将具有活动状态。
因此,我不知道纯CSS解决方案。您可以通过更改标记使具有活动状态的div不再是按钮的父级来避免javascript解决方案(我认为这才是您真正想要的)。例如,您可以使它们成为兄弟姐妹。
然后,该解决方案的CSS部分是修复布局,使其在它们是兄弟姐妹时与它们是父>子时相同。
很抱歉,如果没有看到您正在使用的fiddle,我无法为您提供更具体的解决方案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接