Почему комбайнер general-sibling позволяет переключать псевдоэлементный контент, но не соседний брат?

В этом вопросе "Селектор CSS3, который работает как .click()?" I отправил ответ используя :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>

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

JS Fiddle demo.

Как только я отправил ответ, мне пришло в голову, что мы могли бы также переключить текст label, используемый для запуска изменения состояния этого флажка, используя следующие селекторы (изменив текст label на 'навигация'):

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

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

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

Упрощенная/базовая демонстрация JS Fiddle.

Это не сработало, в то время как селектор совпадал, когда 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 ';
}

JS Fiddle demo.

Скорее всего, это сработало (изменилось content label в ответ на измененное состояние input).

Итак, вопрос: почему комбайнер general-sibling допускает обновление более позднего брата, в то время как цепные комбонатчики следующего поколения (которые соответствуют элементам и структуре DOM) не?

Кроме того, похоже, что это работает в Firefox (21, на Windows XP); поэтому я предполагаю, что вопрос слегка изменен, чтобы включить: это ошибка в Chrome/Webkit или ожидаемое поведение?

И еще больше кажется, что, хотя это ошибка в Chrome (спасибо @Boltclock), есть несколько смехотворная 'do-nothing' анимация, который фиксирует нерабочую демонстрацию (хотя существуют другие, возможно, лучшие альтернативы, как показывает ответ Скотта):

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.

Примечание. причина, по которой я обновляю этот вопрос с помощью этого исправления, а не размещать его как ответ, просто потому, что вопрос был не "как я могу это исправить?" но (в основном) "почему он не работает?"

Ответы

Ответ 1

Это давняя ошибка в браузерах WebKit, связанная с использованием некоторых динамических псевдоклассов с комбинаторами следующего поколения. Это происходит независимо от того, применяете ли вы стили к самому элементу-брату или псевдоэлементу этого элемента-брата.

Я не знаю, зарегистрировал ли кто-нибудь отчет об ошибке, но это было довольно часто встречается на сайте:

Странно также сообщалось, что у Chrome возникли проблемы с общим комбинированным сборщиком, но, как вы заметили, он работает в вашем сценарии:

Итак, либо это было исправлено, либо что-то еще запускает/запускает его.

Ответ 2

Работа с ошибками

По-видимому, некоторые действительные псевдоклассы, соединенные вместе, позволяют ему работать.

Эти работы (см. 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

Это не было (см. Fiddle # 4):

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

Я пробовал некоторые другие комбинации :not(), ни одна из которых не позволяла ему работать.

** Лучший выбор **

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