Эффективный алгоритм сравнения специфичности правил CSS


Мне было интересно, какой эффективный алгоритм будет в следующем сценарии:

Задается разбираемый набор правил css, например.

     p.pStyle{margin-bottom:20px;font-family:Arial;}
     p{font-family:Verdana;}
     p.anotherPStyle{margin-bottom:10px;}

Из таблицы стилей css возможно, что несколько наборов правил применяются к данному элементу (скажем, <p class="pStyle anotherPStyle">hello</p> в моем документе).

Мне нужно сначала определить, какие правила в таблице стилей применяются к данному элементу (так что здесь это p, pStyle and anotherPStyle), а затем создать компаратор, способный сортировать применимые правила по спецификациям (от наиболее специфичных до самое-общее). Примечание: Я уже разработал алгоритм для применения правил после сортировки, поэтому вам не нужно эффективно решать эту проблему. Я играл с несколькими идеями, а именно с одной, которая включает определение уровня в дереве DOM, к которому относится данное правило....Хотя я не уверен, что это правильный путь?

Как браузерный движок делает это эффективно? Я ищу, чтобы скопировать его на Java, но мне удобно со многими другими языками, так что любой код вы можете предложение наиболее ценится.

Спасибо

1 7

1 ответ:

Это определяется спецификой. В этом случае, поскольку они оба одинаково специфичны, объявление, которое приходит последним в файле, выигрывает.

Расчет Специфичности

Специфичность вычисляется путем ранжирования различных частей селектора .

Ранжировано от наиболее специфичного к наименее:

  1. атрибут стиля - Если правило найдено в атрибуте стиля, этот ранг получает 1.
  2. ID-для каждого ID, найденного в селекторе, этот ранг получает дополнительный 1.
  3. Классы, псевдоклассы, селекторы атрибутов-для каждого найденного в селекторе, этот ранг получает дополнительный 1.
  4. элементы-для каждого элемента, найденного в селекторе, этот ранг получает дополнительный 1.

Где rank n > rank n+1, независимо от того, сколько очков имеет каждый ранг.

Пример

ul#nav li.active a

Пункты следующие:

  1. 0-не атрибут стиля.
  2. 1-1 ID найден.
  3. найдено 1-1 имя класса.
  4. 3 - Найдено 3 элемента.
Таким образом, каждое свойство в этом селекторе имеет значение специфичности [0,0,1,1,3] (мы доберемся до этого дополнительного нуля через минуту). Это значение более специфично, чем любой селектор, если он может быть, например, без идентификатора.

Алгоритм сравнения:

    Идите слева направо по рядам. Сравните ранги на обоих селекторах.
  1. выигрывает тот ранг, у которого больше очков.
  2. если ранги равны, переходите сразу к следующему (менее конкретному) рангу.
  3. если все ранги равны, тот , который появляется позже в документе CSS, выигрывает.

Более важные Примечания:

    Универсальный селектор (*) не имеет значения специфичности (0,0,0,0) псевдо-элементы (например, :first-line) получают 0,0,0,1 в отличие от их
    псевдоклассовые братья, которые получают 0,0,1,0
  • псевдокласс :not() не добавляет специфичности сам по себе, только то, что внутри него скобки.
  • директива !important может быть применена к одиночному объявлению и добавляет точку к" 0-му " рангу, который более специфичен, чем что-либо
    еще. Поэтому в приведенном выше примере добавление !important к любому правилу будет
    увеличьте значение специфичности только для этого правила до [1,0,1,1,2],
    предоставление ему мгновенной победы над любыми другими правилами без !important.

Дополнительная Ссылка

См. эта замечательная статья на субъект


Как определить, какие стили переходят к какому элементу

Способ, которым браузер делает это, состоит в том, чтобы перейти по селектору отсправа налево и фильтровать элементы из DOM по мере их прохождения.

Возвращаясь к предыдущему примеру:

    ul#nav li.active a

Браузер делает следующее:

  1. возьмите элемент a.
  2. Теперь проверьте, есть ли у него предок, который является элементом li с классом .active (это через комбинатор потомков: ancestor descendant). Теперь проверьте, есть ли у него более высокий предок, который является ul с идентификатором #nav (снова используется комбинатор потомков).
Если для определенного элемента выполняются все эти условия, то к нему применяются стили.

Вы можете прочитать его:

Выберите любой элемент a
с предком с классом .active, который также является li,
который в свою очередь имеет предка с идентификатором #nav, который также является ul.

Вам потребуется иметь полностью функциональное и полное дерево DOM, чтобы успешно определить, какой элемент имеет какие стили CSS.