You Think You Know CSS (7 Part Series)
The CSS language syntax is simple to learn in matter of hours, newbies can copy tons of CSS snippets and create a delightful website, even designers can write CSS. Things go well until you start to use many
!important or inline styles to achieve expected styles.
You Think You Know CSS is an original series about some core CSS topics
which you think you know but not deep enough to talk about them comfortably.
- How CSS Works Under the Hood (this post)
- Beloved CSS Frameworks
- CSS-in-JS Styling Technique
- Long-standing CSS Methodologies
- Extending standard CSS by preprocessors
- The Opinionated Decision on CSS Resets
- The Need of CSS Style Guides
already perfectly working ignorable stuff.
Besides CSS architecture, solid understanding of specificity and inheritance will help you write less code in a predictable style. The real power of CSS lies in the fact that it allows you specify styles from multiple sources and automatically calculates final styles.
The aim of this post is to develop your understanding of some of the most fundamental concepts of CSS — the cascading, specificity, and inheritance — which control how CSS is applied to HTML and how conflicts are resolved.
The actual process of calculating final CSS property for a given HTML element is the result of very complicated multiple steps:
At this step, all style declarations for a given element are collected from multiple sources like user agents, authors or users.
These declarations must go through all kinds of filtering and validating to see if they are from stylesheets that currently applies to this document and syntactically valid.
This is the core concept of CSS lies in its name Cascading Style Sheets. Solid understanding this step is a must because it is the only step which hugely influenced by developers as
This step takes an unordered list of declarations from previous step
collecting, sorts them according to following criteria, in
descending order of priority:
Origin and Importance: based on combination of declaration origins (user agent, user, author, transition, animation) and
!important annotation. Using
!important as pros and cons depending on circumstances, use it sparingly.
- Transition - User agent + `!important` - User + `!important` - Author + `!important` - Animation - Author - User - User agent
Specificity: based on selector's specificity (The declaration with highest specificity wins) calculated for a given element as follows:
- Inline styles (1000) - ID selectors (100) - Class selectors, attributes selectors, and pseudo-classes (10) - Type selectors and pseudo-elements (1) - Universal selectors (0)
Order of Appearance: the last declaration in document wins in case of equal specificity.
- Imported style sheets are substituted in place - Linked style sheets are concatenated in linking order - Inline styles are place after all style sheets
This step comes in to place when there are no declarations try to set value for a CSS property of an element. There are several ways of defaulting:
Initial value: this initial value of a CSS property is defined in its definition table, the usage of initial value depends on whether it is inherited or not.
inherited property get value from parent element, root
inherited property get
non-inherited property gets
initial value all the time.
Explicit defaulting: instead of setting custom value for a property, you can explicitly use
initial keyword for resetting a property,
inherit for explicit inheritance and
unset for erasing all declarations.
We're using many relative units (
vh), relative URLs, percentages, or some human readable keywords (
bold) to gain maximum flexibility in responsive design. This step will try to absolutize all values as follows:
- Relative units are made absolute by multiplying with appropriate preference size
- Some keywords are replaced according to their definitions
- Percentages are multiplied by a reference value
- Relative URLs are resolved to become absolute
This step will try to resolve property value as far as possible without laying the document, resolving network requests, or retrieving values from somewhere excepts its parent.
This step will format the whole document and finish remaining works from previous step why trying to calculate the absolute theoretical value used in the layout of the document.
This step especially focuses on cases like relative coordination between elements, auto layout, or flex layout. It requires a lot of calculations and yield almost perfectly usable absolute values for browsers to use.
This final step will make some adjustments based on a browsing environment like browser engine, media types, device pixel density, or operating systems before actually drawing.
Some common adjustments are rounding float values to integer values or font size based on available fonts.
This post focuses on an
abstract way how to parse CSS styles from multiple sources in a predictable ways. Understanding this flow will help us write more elegant and maintainable code. It also help us debug CSS styling easier with confidence.
The actual process how a browser applying CSS is different. It has many phases related loading CSS, parsing CSS, creating CSSOM tree and attaching style to DOM nodes. Those steps we've just read implemented in CSS parsing phase.