13

Scenario

I have a CSS selector that is supposed to display sub-content when a label is clicked. The selector is along the lines of input:checked + element + element giving that final element a display of block (default is none). The problem is that it works in all the major browsers with the exception of webkit. Chrome, Safari, and a mobile browser for android (v2.2 sorry, I'm behind the times) all fail to display the element. When I inspect the element in Chrome, it shows that it is supposed to be display: block but it doesn't render it. I can unchec and check the property in developer tools and it displays, but not before.

I assume that this is a bug in webkit.

Question

Here is the multipart question: Is this a known bug in webkit? Am I doing anything wrong with my selectors? And how can I work around the issue for webkit browsers (any creative suggestions)?

Code

HTML

  <input id="c1" type="checkbox">
  <label for="c1">Ein</label>
  <section>Content</section>

  <input id="c2" type="checkbox">
  <label for="c2">Zwei</label>
  <section>Content</section>

  <input id="c3" type="checkbox">
  <label for="c3">Drei</label>
  <section>Content</section>

CSS

input {
  float:left;
  clear:left;
  visibility: hidden;
  position:absolute;
}

label {
  color:green;
  display:block;
  cursor:pointer;
}

section {
  display:none;
}

label:after {
  content:" +";
}

input:checked + label:after {
  content:" -";
}

input:checked + label + section {
  display:block;
}

Demo

Demo: http://jsbin.com/epibin/2
Source: http://jsbin.com/epibin/2/edit

Joseph Marikle
  • 76,418
  • 17
  • 112
  • 129
  • looks like a re-paint "bug", siblings aren't re-painted on check toggle. If in the inspector you toggle the display on/off it does paint correctly. Same result in Safari (PC) – MikeM Jan 07 '13 at 18:34
  • Thanks for the reply, @mdmullinax. That would make sense , but it does render the change from `+` to `-`. I tried a few other attributes to test it as well. See this demo: http://jsbin.com/epibin/6/edit – Joseph Marikle Jan 07 '13 at 18:39
  • The CSS solution in [this answer](http://stackoverflow.com/a/8320736/681807) might better suit your needs as it does not require any additional HTML markup and can be removed when/if the bug is finally fixed – My Head Hurts Jan 07 '13 at 19:18
  • 1
    @MyHeadHurts: I actually found and posted what I consider a better solution for the bug work around than the one you linked to. – ScottS Jun 20 '13 at 18:01
  • @ScottS it is definitely a tidier hack which I will be adding my to my collection :) Thanks! It is a shame that Chrome has so much trouble with chained selectors! – My Head Hurts Jun 21 '13 at 09:36

4 Answers4

18

Chain A Pseudo-Class

This demonstrates that this code fixes the bug (note that nth-child(n) matches any element, but the adding of it into the chain causes it to work):

input:checked + label:nth-child(n) + section {
  display:block;
}
ScottS
  • 71,703
  • 13
  • 126
  • 146
  • 1
    fantastic! This corrects the problem perfectly! How did you come upon this solution if I may ask? – Joseph Marikle Jun 20 '13 at 21:27
  • Trial and error on experimenting with [this more recent question](http://stackoverflow.com/questions/17219286/why-does-the-general-sibling-combinator-allow-toggling-pseudo-elements-content/17220145#17220145) that was related to the same issue. – ScottS Jun 20 '13 at 22:33
  • Perfect. Preferred solution over `webkit-animate` as that causes scroll delays on android devices. – mikedidthis Jul 12 '13 at 09:05
  • 1
    This worked for me, but because it was input:checked + input[type=hidden] label I needed to apply nth-child(n) to the label, not the hidden field. – Sam Sep 06 '13 at 09:37
  • Brilliant! This worked for me too. The USB Debugging helped greatly too. But once it was diagnosed, this thread made much more sense. Thanks. – vr_driver Oct 03 '13 at 11:20
  • If you are using an android touch device, with jquery, you may need this too: $(".form-radios label:not(.checked)").on('click touchstart',(function(){ – vr_driver Oct 03 '13 at 12:21
  • you're my personal Jesus :) – LorDex Aug 20 '14 at 15:16
5

@ScottS provides a solid solution. Another possible one that worked for me and makes more sense from an outsiders "why the heck did they do that" point of view:

input:checked ~ section {
  display:block;
}

which selects every 'section' that come after and are siblings of 'input:checked'.

There are two conditions I can think of where @ScottS's version is superior because the element in the position of 'label' gets selected as well in my solution: (1) 'input's sibling #1 & #2 are the same elements (instead of 'label' & 'section') (2) you are trying to be general by using the '*' selector.

Blake
  • 162
  • 1
  • 5
  • I don't think it's inferior. In fact it's quite intuitive. Thank you for posting this answer. Here is a [tweaked demo of my code with your solution](http://jsbin.com/epibin/33/edit). The one thing I had to change was making the input, label, and section all siblings under the same container element to prevent the indiscriminate previous sibling selector from displaying other sections not belonging to it. I also made them radio buttons just for fun. Although the accepted answer correctly fixes the chrome bug issue, this is a possible alternative method. You at lease deserve a bounty imo. – Joseph Marikle Aug 29 '13 at 02:26
  • ' ~ ' fixed worked for me. The 'nth-child' did not. input ~ label the input was a checkbox. – Yogurt The Wise Nov 25 '14 at 14:56
  • this save my life :D – ZenithS Feb 17 '16 at 08:05
3

sounds like a match to Bug 45168 – CSS multiple adjacent sibling selector sequence is ignored if prefixed with a pseudo-class selector

if you swap the <label> and <input> structure in the markup (and adjust the CSS accordingly) it works.

http://jsbin.com/epibin/10/edit

(but now the + - don't toggle)

EDIT:

putting the <label> and <section> in a div container works: http://jsbin.com/epibin/12/edit

MikeM
  • 27,227
  • 4
  • 64
  • 80
1

As mdmullinax states, this is an outstanding bug in chrome.

This hack worked for me from the link in the accepted answer:

 body { -webkit-animation: bugfix infinite 1s; }
 @-webkit-keyframes bugfix { from { padding: 0; } to { padding: 0; } }
Andrew Bullock
  • 36,616
  • 34
  • 155
  • 231