Effective CSS rule specification comparison algorithm

I was wondering what an efficient algorithm would be in the following scenario:

Given a syntax set of css rules, for example.

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

from the css stylesheet, it’s possible that several sets of rules apply to this element (for example, <p class="pStyle anotherPStyle">hello</p> in my document).

I need to determine which rules in the stylesheet are applied to this element first (so here p, pStyle and anotherPStyle ), and then create a Comparator that can sort the applicable rules by specificity (from the most specific to the majority - General). NOTE. I have already developed an algorithm for applying rules after sorting, so you do not need to solve this problem effectively.

I played with several ideas, namely, what is related to determining the level in the DOM tree in which the given rule is specific to ... Although I'm not sure if this is the right way?

How does the browser work so efficiently? I want to reproduce it in Java, but it is more convenient for me with many other languages, so any code that you can offer is most appreciated.

thanks

+7
source share
1 answer

This is determined by the specifics. In this case, since they are both equally specific, the ad that comes last in the file wins.

Unit Cost Calculation

Specificity is calculated by ranking the various parts of the selector .

Rating from most specific to least:

  • Style attribute. If the rule is found in the style attribute, this rank gets 1.
  • ID - for each identifier found in the selector, this rank receives an additional 1.
  • Classes, pseudo-classes, attribute selectors - for each one found in the selector, this rank receives an additional 1.
  • Elements For each element found in the selector, this rank receives an additional 1.

Where rank n > rank n+1 , regardless of how many points each rank has.

Example

 ul#nav li.active a 

Points:

  • 0 - Not a style attribute.
  • Found 1 - 1.
  • 1 - 1 class name found.
  • 3 - 3 Items found.

Therefore, each property in this selector has a specificity value of [0,0,1,1,3] (we get to this extra zero per minute). This value is more specific than any selector, if possible, without an identifier, for example.

Comparison Algorithm:

  • Go from left to right in rows.
  • Compare the rankings of both selectors.
  • The rank with the most points wins.
  • If the ranks are equal, continue right to the next (less specific) rank.
  • If all ranks are equal, the one that comes later in the CSS document wins .

More important notes:

  • The universal selector (*) does not matter specificity (0,0,0,0) Pseudo-elements (for example :first-line ) receive 0,0,0,1 unlike their pseudo- 0,0,1,0 , which receive 0,0,1,0
  • The :not() pseudo-class does not add any specificity per se, only what is inside it in brackets.
  • The !important directive can be applied to a single declaration and adds a dot to the β€œ0” rank, more specifically than anything else. So, in the example above, adding !important to any rule will bump the specificity value for that rule only to [1,0,1,1,2] ,
    giving him an instant victory over any other rules without !important .

Sitelink

See this wonderful related article.


How to determine which styles go to which element

The way that the browser does this is to move from the selector from right to left and filter elements from the DOM as they move.

Returning to the previous example:

  ul#nav li.active a 

The following is done in the browser:

  • Take item a .
  • Now check if it has an ancestor that is a li element with the .active class (this is through the descendant combinator: ancestor descendant ).
  • Now check to see if it has a higher ul ancestor with identifier #nav (again, the descendant combinator is used).

If all these conditions are met for a specific element, then the styles are applied to it.

You can read it:

Select any element a with an ancestor with class .active , which is also li ,
which, in turn, has an ancestor with the identifier #nav , which is also ul .

You need to have a full function and a complete DOM tree in order to be able to successfully determine which element has CSS styles.

+10
source

All Articles