Почему браузеры соответствуют CSS-селекторам справа налево?
Селекторы CSS подбираются движками браузера справа налево. Поэтому они сначала находят детей, а затем проверяют своих родителей, чтобы убедиться, что они соответствуют остальным частям правила.
- Почему это?
- Это только потому, что в спецификации сказано?
- Влияет ли это на возможный макет, если он был оценен слева направо?
Для меня самый простой способ сделать это - использовать селекторы с наименьшим количеством элементов. Сначала идентификаторы (так как они должны возвращать только 1 элемент). Тогда, может быть, классы или элемент, который имеет наименьшее количество узлов - например, на странице может быть только один промежуток, поэтому перейдите непосредственно к этому узлу с любым правилом, которое ссылается на промежуток.
Вот несколько ссылок, подтверждающих мои претензии
- http://code.google.com/speed/page-speed/docs/rendering.html
- https://developer.mozilla.org/en/Writing_Efficient_CSS
Похоже, что это сделано таким образом, чтобы не смотреть на всех детей родителя (которых может быть много), а не на всех родителей ребенка, который должен быть одним. Даже если DOM является глубоким, он будет рассматривать только один узел на уровень, а не несколько при сопоставлении RTL. Проще / быстрее оценить CSS селекторы LTR или RTL?
3 ответа
Помните, что когда браузер выполняет сопоставление селектора, у него есть один элемент (тот, для которого он пытается определить стиль) и все ваши правила и их селекторы, и ему нужно найти, какие правила соответствуют элементу. Это отличается от обычной вещи jQuery, скажем, когда у вас есть только один селектор, и вам нужно найти все элементы, которые соответствуют этому селектору.
Если у вас был только один селектор и только один элемент для сравнения с этим селектором, то слева направо имеет больше смысла в некоторых случаях. Но это определенно не ситуация браузера. Браузер пытается отобразить Gmail или что-то еще и имеет тот <span>
он пытается стилизовать и более 10000 правил, которые Gmail вставляет в свою таблицу стилей (я не придумываю это число).
В частности, в ситуации, когда браузер смотрит на большинство селекторов, которые он считает , не соответствуют рассматриваемому элементу. Таким образом, проблема состоит в том, чтобы решить, что селектор не соответствует так быстро, как это возможно; если это требует дополнительной работы в соответствующих случаях, вы все равно выигрываете из-за всей работы, которую вы сохраняете в случаях, которые не совпадают.
Если вы начнете с сопоставления самой правой части селектора с вашим элементом, скорее всего, он не будет совпадать, и все готово. Если он совпадает, вам придется выполнять больше работы, но только пропорционально глубине вашего дерева, которая в большинстве случаев не так велика.
С другой стороны, если вы начнете с сопоставления самой левой части селектора... с чем вы сравниваете его? Вы должны начать ходить по DOM, ища узлы, которые могут ему соответствовать. Просто обнаружение, что ничто не соответствует этой самой левой части, может занять некоторое время.
Так что браузеры совпадают справа; это дает очевидную отправную точку и позволяет очень быстро избавиться от большинства кандидатов. Вы можете увидеть некоторые данные по адресу http://groups.google.com/group/mozilla.dev.tech.layout/browse_thread/thread/b185e455a0b3562a/7db34de545c17665 (хотя обозначение сбивает с толку), но в результате это, в частности, относится к Gmail два года назад для 70% пар (правило, элемент) вы могли решить, что правило не соответствует, просто изучив части тега / класса /id самого правого селектора для правила. Соответствующий показатель для набора тестов производительности загрузки страниц Mozilla составил 72%. Так что действительно стоит попытаться избавиться от этих 2/3 всех правил так быстро, как только можете, а затем беспокоиться только о соответствии оставшихся 1/3.
Также обратите внимание, что браузеры уже выполняют другие оптимизации, чтобы избежать попыток даже сопоставить правила, которые определенно не будут совпадать. Например, если у самого правого селектора есть идентификатор, и этот идентификатор не совпадает с идентификатором элемента, то в Gecko не будет попытки сопоставить этот селектор с этим элементом вообще: набор "селекторов с идентификаторами", которые предпринимаются исходит из поиска по хеш-таблице идентификатора элемента. Так что это 70% правил, которые имеют довольно хорошие шансы на совпадение, которые все еще не совпадают после рассмотрения только тега / класса /id самого правого селектора.
Разбор справа налево, также называемый анализом снизу вверх, на самом деле эффективен для браузера.
Учтите следующее:
#menu ul li a { color: #00f; }
Браузер сначала проверяет a
, затем li
, затем ul
, а потом #menu
,
Это связано с тем, что, поскольку браузер сканирует страницу, ему просто нужно просмотреть текущий элемент / узел и все предыдущие узлы / элементы, которые он сканировал.
Следует отметить, что браузер начинает обработку в тот момент, когда он получает полный тег / узел, и ему не нужно ждать всю страницу, кроме случаев, когда он находит скрипт, и в этом случае он временно приостанавливает и завершает выполнение скрипта, а затем идет вперед.
Если это происходит наоборот, это будет неэффективно, потому что браузер обнаружил элемент, который он сканировал при первой проверке, но затем был вынужден продолжить просмотр документа для всех дополнительных селекторов. Для этого браузер должен иметь весь HTML-код и, возможно, потребуется отсканировать всю страницу, прежде чем он начнет рисовать CSS.
Это противоречит тому, как большинство парсов разбирает дом. Там дом построен, и ему не нужно сканировать всю страницу, просто найдите первый элемент и затем продолжайте сопоставлять другие внутри него.
Это позволяет каскадно переходить от более конкретного к менее конкретному. Это также допускает короткое замыкание в приложении. Если более конкретное правило применяется во всех аспектах, к которым применяется родительское правило, все родительские правила игнорируются. Если в родительском элементе есть другие биты, они применяются.
Если бы вы пошли другим путем, вы должны отформатировать в соответствии с родителями, а затем переписать каждый раз, когда у ребенка что-то другое. В конечном счете, это гораздо больше работы, чем игнорирование элементов в правилах, о которых уже позаботились.