为什么通用兄弟组合器允许切换伪元素的内容,而不是相邻的兄弟?

Dav*_*mas 10 html css css-selectors

在这个问题" CSS3选择器,像jQuery的.click()? "我发布了一个回答使用的:checked状态input,type="checkbox"以切换元素的显示.

这是我在答案中发布的演示的HTML:

<input type="checkbox" id="switch" />
<nav>
    <h2>This would be the 'navigation' element.</h2>
</nav>
<label for="switch">Toggle navigation</label>
Run Code Online (Sandbox Code Playgroud)

和CSS(为了简洁而剥离过渡):

#switch {
    display: none;
}
#switch + nav {
    height: 0;
    overflow: hidden;
    /* transitions followed */
}
#switch:checked + nav {
    height: 4em;
    color: #000;
    background-color: #ffa;
    /* transitions followed */
}

label {
    cursor: pointer;
}
Run Code Online (Sandbox Code Playgroud)

JS小提琴演示.

有一次,我张贴发生,我认为我们可以在答案切换的文本label用于触发复选框的状态变化,使用下面的选择(已修订label的文本'导航’):

label {
    display: inline-block;
    cursor: pointer;
}

#switch + nav + label::before {
    content: 'Show ';
}

#switch:checked + nav + label::before {
    content: 'Hide ';
}
Run Code Online (Sandbox Code Playgroud)

简化/基本JS小提琴演示.

这不起作用,因为当选择器input处于未检查状态(和label显示Show navigation)时匹配,当选择状态改变时,选择器无法匹配input.请注意,转换仍然在nav元素上进行,原始匹配选择器指示下一个兄弟组合器最初匹配.上面的链接显示了不工作(在Chrome 27/Windows XP中)选择器的简化演示.

然后我想到尝试使用通用兄弟组合器来减少选择链.这导致了以下CSS(为了简洁起见,再次剥离了转换):

#switch:checked + nav {
    background-color: #ffa;
}

label {
    display: inline-block;
    cursor: pointer;
}

#switch ~ label::before {
    content: 'Show ';
}

#switch:checked ~ label::before {
    content: 'Hide ';
}
Run Code Online (Sandbox Code Playgroud)

JS小提琴演示.

有点出乎我的意料,这个工作(在content该的label响应的改变的状态改变input).

所以,问题是:为什么通用兄弟组合子允许更新后来的兄弟,而链接的下一个兄弟组合子(匹配DOM的元素和结构)不是?

此外,这似乎在Firefox(21,在Windows XP)的工作; 所以我想问题略有改变,包括:这是Chrome/Webkit中的一个错误,还是预期的行为?

而且,更进一步,似乎虽然这是Chrome中的一个错误(感谢@Boltclock),有一些有点可笑的"无所事事"动画修复了非工作演示(尽管其他可能更好的替代方案存在,如斯科特的答案显示):

body {
    -webkit-animation: bugfix infinite 1s;
}
@-webkit-keyframes bugfix {
    from {
        padding: 0;
    }
    to {
        padding: 0;
    }
}
#switch {
}
#switch + nav {
    -moz-transition: all 1s linear;
    -ms-transition: all 1s linear;
    -o-transition: all 1s linear;
    -webkit-transition: all 1s linear;
    transition: all 1s linear;
}
#switch:checked + nav {
    background-color: #ffa;
    -moz-transition: all 1s linear;
    -ms-transition: all 1s linear;
    -o-transition: all 1s linear;
    -webkit-transition: all 1s linear;
    transition: all 1s linear;
}
label {
    display: inline-block;
    cursor: pointer;
}
#switch + nav + label::before {
    content:'Show ';
}
#switch:checked + nav + label::before {
    content:'Hide ';
}
Run Code Online (Sandbox Code Playgroud)

JS小提琴演示.

注意:我用这个"修复"更新问题的原因,而不是将其作为答案发布,仅仅是因为问题不是 "我该如何解决这个问题?" 但(基本上)"为什么不起作用?"

Sco*_*ttS 16

Bug工作

显然,链接在一起的某些有效伪类允许它工作.

这些工作(见小提琴#1,小提琴#2,小提琴#3):

#switch:checked + nav:only-of-type + label::before
#switch:checked + nav:nth-of-type(1) + label::before
#switch:checked + nav:nth-child(2) + label::before
Run Code Online (Sandbox Code Playgroud)

这没有(见小提琴#4):

#switch:checked + nav:not([class]) + label::before
Run Code Online (Sandbox Code Playgroud)

我尝试了一些其他的:not()组合,其中没有一个允许它工作.

**最佳选择**

#switch:checked + nav:nth-child(n) + label::before
Run Code Online (Sandbox Code Playgroud)

  • `:nth-​​child(n)`有效吗?如果是这样,那是最好的选择,因为它是一个保证匹配(好吧,技术上等同于`:not(:root)`,但是根元素在这里是无关紧要的). (2认同)

Bol*_*ock 9

这是WebKit浏览器中一个长期存在的错误,它与使用具有下一个兄弟组合子的某些动态伪类有关.无论您是将样式应用于兄弟元素本身还是应用该兄弟元素的伪元素,都会发生这种情况.

我不知道是否还有人提交过错误报告,但网站上经常出现这种情况:

奇怪的是,据报道,Chrome与普通兄弟组合器存在问题,但正如您所指出的那样,它适用于您的特定情况:

所以要么修复了,要么触发/触发它.

  • 你应该知道我对WebKit以及对Trident和Gecko的态度非常偏向于此:PI特别赞扬微软将IE8专注于CSS2.1合规性的策略 - 它真的显示出来,并将像Chrome这样的粗略技术演示放在他们的位置. (2认同)