title: Why does the general-sibling combinator allow toggling pseudo-element's content, but not the adjacent-sibling?
body: <p>In this question "<a href="https://stackoverflow.com/q/17217585/">CSS3 Selector That Works like jQuery&#39;s .click()?</a>" I <a href="https://stackoverflow.com/a/17217826/82548">posted an answer</a> using the <code>:checked</code> state of an <code>input</code>, of <code>type="checkbox"</code> to toggle the display of an element.</p>
  
  <p>This is the HTML of the demo I posted in that answer:</p>
  
  <pre><code>&lt;input type="checkbox" id="switch" /&gt;
  &lt;nav&gt;
      &lt;h2&gt;This would be the 'navigation' element.&lt;/h2&gt;
  &lt;/nav&gt;
  &lt;label for="switch"&gt;Toggle navigation&lt;/label&gt;
  </code></pre>
  
  <p>And the CSS (with transitions stripped for brevity):</p>
  
  <pre><code>#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;
  }
  </code></pre>
  
  <p><a href="http://jsfiddle.net/davidThomas/rUkRS/1/" rel="nofollow noreferrer">JS Fiddle demo</a>.</p>
  
  <p>Once I'd posted the answer it occurred to me that we could <em>also</em> toggle the text of the <code>label</code> used to trigger the state-change of that checkbox, using the following selectors (having amended the <code>label</code>'s text to 'navigation'):</p>
  
  <pre><code>label {
      display: inline-block;
      cursor: pointer;
  }
  
  #switch + nav + label::before {
      content: 'Show ';
  }
  
  #switch:checked + nav + label::before {
      content: 'Hide ';
  }
  </code></pre>
  
  <p><a href="http://jsfiddle.net/davidThomas/rUkRS/6/" rel="nofollow noreferrer">Simplified/basic JS Fiddle demo</a>.</p>
  
  <p>This did not work, in that while the selector matched while the <code>input</code> was in its unchecked state (and the <code>label</code> showed <code>Show navigation</code>), the selector <em>failed</em> to match when the state of the <code>input</code> changed. Note that the transitions were still effected on the <code>nav</code> 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.</p>
  
  <p>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):</p>
  
  <pre><code>#switch:checked + nav {
      background-color: #ffa;
  }
  
  label {
      display: inline-block;
      cursor: pointer;
  }
  
  #switch ~ label::before {
      content: 'Show ';
  }
  
  #switch:checked ~ label::before {
      content: 'Hide ';
  }
  </code></pre>
  
  <p><a href="http://jsfiddle.net/davidThomas/rUkRS/4/" rel="nofollow noreferrer">JS Fiddle demo</a>.</p>
  
  <p>Somewhat to my surprise, this worked (the <code>content</code> of the <code>label</code> changed in response to the changed-state of the <code>input</code>).</p>
  
  <p>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?</p>
  
  <p>Further, this <em>does</em> 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?</p>
  
  <p>And, even <em>further</em>, it seems that while this is a bug in Chrome (thanks @Boltclock), there's a somewhat ludicrous <a href="http://css-tricks.com/webkit-sibling-bug/" rel="nofollow noreferrer">'do-nothing' animation</a> that fixes the non-working demo (though other, perhaps better, alternatives exist, as Scott's answer shows):</p>
  
  <pre><code>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 ';
  }
  </code></pre>
  
  <p><a href="http://jsfiddle.net/davidThomas/rUkRS/14/" rel="nofollow noreferrer">JS Fiddle demo</a>.</p>
  
  <p><strong>Note:</strong> the reason I'm updating the question with this 'fix,' rather than posting it as an answer, is simply because the question <em>wasn't</em> "how can I fix this?" but (basically) "why doesn't it work?"</p>