Ответ 1
Однако недавно я прочитал, что большинство движков селектора CSS читаются справа налево, и в этом случае первый пример не будет медленнее?
Какой способ для CSS-селекторных движков читается вообще? Слева направо или справа налево? И если они обычно читают справа налево, кто-то может предложить мне объяснение, почему (я не вижу, как имеет смысл читать справа налево в терминах механизма выбора)?
Честно говоря, почти невозможно определить, какой селектор будет медленнее в данном браузере, а тем более в браузерах. Производительность имеет тенденцию колебаться и быть непредсказуемой, особенно в таких микроскопических масштабах и с непредсказуемыми структурами документов. Даже если говорить о теоретической производительности, это в конечном счете зависит от реализации.
Сказав это, как показано в Борис Збарский, ответьте на этот другой вопрос и в Guffa ответьте на ваш, типичный браузер (в настоящее время это относится ко всем основным механизмам макета) принимает элемент и оценивает все селекторы-кандидаты, чтобы увидеть, какие из них соответствуют, вместо поиска набора элементов, соответствующих данному селектору. Это тонкая, но очень важная разница. Борис предлагает техническое объяснение, которое не только невероятно детализировано, но и авторитетно (поскольку он работает над Gecko, движком, используемым Firefox), поэтому я настоятельно рекомендую его прочитать.
Но я подумал, что я должен рассмотреть то, что, похоже, вызывает еще одно беспокойство в вашем вопросе:
Поскольку движок селектора просто найдет каждый элемент с классом имени, а затем должен определить, какие из них были
div
s?
Также как комментарий Патрика МакЭлхани:
Связанный вопрос объясняет, почему селектора читаются справа налево в целом, поэтому
#foo ul.round.fancy li.current
читаетсяli.current, ul.round.fancy, #foo
, но действительно ли он читается справа налево в каждом элементе (.current, li, .fancy, .round, ul, #foo
)? Должно ли это быть?
Я никогда не реализовал CSS, и не видел, как другие браузеры его реализуют. Мы знаем из ответов, приведенных выше, что браузеры используют совпадение справа налево для просмотра комбинаторов внутри селекторов, таких как комбинаторы >
в этом примере:
section > div.second > div.third
Если элемент не является div.third
, тогда нет точки, проверяющей, является ли его родительский элемент div.second
, родителем которого является section
.
Однако я не считаю, что этот порядок справа налево сверлит весь путь до простого уровня селектора. Другими словами, я не считаю, что браузеры используют оценку справа налево для каждой части простой селекторной последовательности (также известной как составной селектор) в рамках оценки справа налево по ряду составных селекторов, разделенных комбинаторы.
Например, рассмотрите этот надуманный и сильно преувеличенный селектор:
div.name[data-foo="bar"]:nth-child(5):hover::after
Теперь нет гарантии, что браузер обязательно проверит эти условия для элемента в следующем порядке:
- Является ли указатель на этот элемент?
- Является ли этот элемент 5-м дочерним элементом его родителя?
- Этот элемент имеет атрибут
data-foo
со значениемbar
? - Этот элемент имеет класс
name
? - Это элемент
div
?
И этот селектор, который функционально идентичен выше, за исключением того, что его простые селектора перемешались, обязательно оцениваются в следующем порядке:
div:hover[data-foo="bar"].name:nth-child(5)::after
- Является ли этот элемент 5-м дочерним элементом его родителя?
- Этот элемент имеет класс
name
? - Этот элемент имеет атрибут
data-foo
со значениемbar
? - Является ли указатель на этот элемент?
- Это элемент
div
?
Просто нет причин, чтобы такой порядок применялся по соображениям производительности. Фактически, я бы подумал, что производительность будет повышаться, сначала выбирая определенные типы простых селекторов, независимо от того, где они находятся в последовательности. (Вы также заметите, что ::after
не учитывается - потому что псевдоэлементы не являются простыми селекторами и даже не входят в соответствующее уравнение.)
Например, очень хорошо известно, что селекторы ID являются самыми быстрыми. Ну, Борис говорит об этом в последнем абзаце своего ответа на связанный вопрос:
Обратите внимание также, что существуют другие браузеры оптимизации, которые уже делают, чтобы избежать попыток сопоставления правил, которые определенно не совпадают. Например, если самый правый селектор имеет идентификатор и этот идентификатор не совпадает с идентификатором элемента, то не будет попытки сопоставить этот селектор с этим элементом вообще в Gecko: набор "селекторов с идентификаторами", которые предпринимаются происходит из поиска хэш-таблицы на идентификаторе элемента. Таким образом, это 70% правил, которые имеют довольно хорошие шансы на совпадение, которые по-прежнему не совпадают после рассмотрения только тега/класса/идентификатора самого правого селектора.
Другими словами, есть ли у вас селектор, который выглядит так:
div#foo.bar:first-child
Или это:
div.bar:first-child#foo
Gecko всегда будет проверять идентификатор и класс в первую очередь, независимо от того, где он находится в последовательности. Если у элемента нет идентификатора и класса, который соответствует селектору, он мгновенно отбрасывается. Если вы спросите меня, сделайте это быстро.
Это был просто Гекко в качестве примера. Это может различаться и между реализациями (например, Gecko и WebKit могут делать это иначе, чем Trident или даже Presto). Существуют стратегии и подходы, которые, как правило, согласованы поставщиками, конечно (вначале вряд ли будет разница в проверке идентификаторов), но небольшие детали могут отличаться.