Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
256 views
in Technique[技术] by (71.8m points)

html - Why does the general-sibling combinator allow toggling pseudo-element's content, but not the adjacent-sibling?

In this question "CSS3 Selector That Works like jQuery's .click()?" I posted an answer using the :checked state of an input, of type="checkbox" to toggle the display of an element.

This is the HTML of the demo I posted in that answer:

<input type="checkbox" id="switch" />
<nav>
    <h2>This would be the 'navigation' element.</h2>
</nav>
<label for="switch">Toggle navigation</label>

And the CSS (with transitions stripped for brevity):

#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;
}

JS Fiddle demo.

Once I'd posted the answer it occurred to me that we could also toggle the text of the label used to trigger the state-change of that checkbox, using the following selectors (having amended the label's text to 'navigation'):

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

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

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

Simplified/basic JS Fiddle demo.

This did not work, in that while the selector matched while the input was in its unchecked state (and the label showed Show navigation), the selector failed to match when the state of the input changed. Note that the transitions were still effected on the nav element, and the original matching selector indicates that the next-sibling combinator matched originally. The above link shows a simplified demo of the not-working (in Chrome 27/Windows XP) selectors.

It then occurred to me to try the general-sibling combinator, to reduce the selector-chain. which resulted in the following CSS (with transitions again stripped for brevity):

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

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

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

#switch:checked ~ label::before {
    content: 'Hide ';
}

JS Fiddle demo.

Somewhat to my surprise, this worked (the content of the label changed in response to the changed-state of the input).

So, the question: why does the general-sibling combinator allow for updating of a later-sibling while chained next-sibling combinators (which match the elements and the structure of the DOM) does not?

Further, this does seem to work in Firefox (21, on Windows XP); so I guess the question is altered slightly to include: is this a bug in Chrome/Webkit, or an expected behaviour?

And, even further, it seems that while this is a bug in Chrome (thanks @Boltclock), there's a somewhat ludicrous 'do-nothing' animation that fixes the non-working demo (though other, perhaps better, alternatives exist, as Scott's answer shows):

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 ';
}

JS Fiddle demo.

Note: the reason I'm updating the question with this 'fix,' rather than posting it as an answer, is simply because the question wasn't "how can I fix this?" but (basically) "why doesn't it work?"

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Bug Work Around

Apparently, certain valid pseudo-classes chained together allows it to work.

These work (see Fiddle #1, Fiddle #2, Fiddle #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

This did not (see Fiddle #4):

#switch:checked + nav:not([class]) + label::before

I tried some other :not() combinations, none of which allowed it to work.

** Best choice **

#switch:checked + nav:nth-child(n) + label::before

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...