CSS Under the hood - CSS parsing & value processing

Steps of loading a webpage:

  1. Load HTML
  2. Parses HTML ( Build DOM )
  3. Load CSS
  4. Parse CSS ( Build CSSOM )
  5. Render tree is built
  6. Visual formatting model is built
  7. Webpage render

CSS parsing

a css rule consists of a selector and a declaration block.

#my-element {
	color: red;
} 

The cascade

the first step in parsing is resolving conflicting css rules is using the cascade.

the cascade is the process of combining multiple stylesheets and resolving conflicts between rules using Importance, specificity and source order when more than one rule applies to an element in the DOM.

  1. Importance
  2. specificity
  3. Source order

Importance

  1. User !important ( Browser settings i.e. browser font size )
  2. Author !important ( !important found in stylesheets/inline styles)
  3. Author declarations ( stylesheets/inline styles )
  4. User declarations ( Browser settings i.e. prefers-dark-mode )
  5. Default browser declarations ( User agent stylesheet )

Specificity

Specificity of a css rule is represented as a tuple of 4 elements ( 0. 0, 0, 0 ) and each occurrence of an element increments its value by 1.

  1. Inline styles
  2. IDs
  3. Classes, pseudo-classes, html attributes
  4. Elements, pseudo elements

The following css rule uses an occurrence of an id and class selector.

#my-element .my-element-class {
	color: red;
} 

Its specificity would be represented as: ( 0, 1, 1, 0 )

( 0, 2, 1, 0 ) is more specific than ( 0, 1, 100, 0 )

Source order

The last occurrence of a rule in the cascade will override all other rules with equal levels of importance and specificity and this final occurring rule will be applied.

<p class=“text”>Where’s the blog Lebowski?</p>
<style>
p {
	color: red;
}

p {
	color: green;
}

p {
	color: black;
}
</style>

All the above rules have equal levels of specificity and importance - ( 0, 0, 0, 1 ) and so the final rule will be used - the font colour of the element will be black.

Value processing

All CSS properties have an initial value ( even if its 0px ). This is the value that is used if there is no cascaded or inherited value.

Value processing in CSS is the action of taking a series of values applied to an element and deciding on a final value to apply based upon the css declarations targeting this element and the users device. Value processing has 6 steps.

  1. Declared value
  2. Cascaded value
  3. Specified value
  4. Computed value
  5. Used value
  6. Actual value

Consider this markup:

<section>
	<div class=“content”>
		<h1>CSS: Value processing</h1>
		<p>Lorem ipsum dolor, sit amet.</p>
	</div>
</section>
<style>
	section {
		width: 275px;
	}

	section div {
	  width: 200px;
	}

	.content {
		width: 66%;
	}
</style>

If we were to consider the value processing for the width of the :

  1. Declared value: both 200px and 66%.
  2. Cascaded value: 66% - specificity of the class selector ( 0, 0, 1, 0 ) overrides the element selector ( 0, 0, 0, 1 ).
  3. Specified value: 66% - This is a cascaded value, so it overrides the initial value.
  4. Computed value: 66% - converts all relative units to absolute units.
  5. Used value: 181.5px - calculated as 66% of 275px.
  6. Actual value: 182px - browsers can’t render decimal points of pixels so its rounded up.

Understanding relative units to absolute units (px)

Browser specify a root font-size property for the document.

At the end of value processing, relative units ( %, vh, vw, em, rem ) are ALWAYS converted to pixels.

Percentages are measured relative to their parents font-size when specifying font-size.

Percentages are measured relative to parent’s width when specifying length measurements ( width, height, padding, margin, border ).

em are measured relative to the parent font-size if used to specify font-size.

em are measure relative to the current elements font-size, if used to specify length measurements ( width, height, padding, margin, border etc )

rem is always measured relative to the documents root font-size.

vh and vw are percentage measurements of the viewports width and height respectively.

Inheritance

The process of propagating css values from parent to descendant elements. Not all CSS properties can be inherited.

Every property must have a CSS value. During value process, step 3 ( specified value ) asks if there is a cascaded value, and if there is, this is the one that is used. If there is no cascaded value, it then goes on to see if it is possible to inherit a value from an ancestor element.

The actual value that is inherited, is the computed value ( step 4 in value processing ) from the ancestor.

If a value is not inheritable, then the specified value becomes the Initial value. In many cases this might be 0px.

Inheritance occurs in two situations.

  1. When there is no declared value for that property.
  2. When the property’s declared value is inherit.