How Does CSS Work?
Understanding the Default Behavior of Styles in Our Browsers
When you start creating a new website, even before writing a single style, the browser applies styles to it — its default styles.
Have you ever asked yourself who decides what those basic default styles will be?
In this article, I want to teach you and show you the different levels of CSS in the browsers, how they work, and how we can control them.
When I started learning CSS, quite a long time ago, I was taught that all the browser’s basic styles come from the browser’s basic CSS file called the “User-Agent Stylesheet”. But over the years I came to understand that this is only a small part of where the basics styles come from.
Let’s explore the basics of CSS together!
Level 1 — CSS Properties Default Styles
Every CSS property has a Formal Definition section. These Formal Definitions are a part of the W3C’s standardization of CSS, the organization that is in charge of the web’s standards.
The Initial Value
Every CSS property has an initial value. This value doesn’t depend on the HTML element that it applies to. That is, a property’s initial value applies to all the HTML elements the same way.
I think that the majority of web developers are not aware of this basic thing.
Let’s take for example CSS positions:
Have you ever asked yourself what the default values of the CSS Positions properties are?
Many web developers will fail to answer this simple question. The answer is that the position property’s initial value is static .
The other direction properties of CSS positions, top / bottom / left / right — their initial value is auto .
Remember — the basic styles of those CSS properties exist before you write a single style.
CSS Positions’ initial values:
The best way to find each of the CSS properties’ initial value is by looking it up on the MDN website in the “Formal Definition” section.
Example:
CSS Inheritance
The second interesting definition that some of our CSS properties have is the “inheritance behavior”. This behavior means that a style applied to an element is inherited by its descendent elements.
By default, the primary properties that have this behavior are text ones, such as font-family , font-size , color , text-align , and other typography properties.
Think about it: when you give the <body> HTML element a font-size: 20px style, all the inner HTML elements are affected and inherit that font-size , until you declare a new font-size on an inner HTML element.
But when you declare padding: 20px on the <body> HTML element, it doesn’t affect the inner HTML elements. This is because the padding property doesn’t have the inheritance behavior by default.
We take this inheritance behavior for granted and use it almost without noticing.
HTML
CSS
How can we know if styles are “inherited properties” or “non-inherited properties” when debugging in the browser?
When we debug the code above by using the “inspect element” feature on the <div> HTML element, the browser’s developer tools will show us that there are inherited styles from the <body> HTML element.
We will see the font-size property in intense colors because it’s an inherited property. But the padding property will be in faded colors because it isn’t inherited and it doesn’t affect the <div> .
The Formal Way to Check Inherited Behavior
The way to know if a property has the inheritance behavior, besides trying it yourself, is by looking it up on the MDN website under the “Formal Definition” section.
In the image below: we can see that some properties are inherited and some aren’t. This difference creates two types of CSS property groups:
- “Inherited properties”
- “Non-inherited properties”
Examples:
Level 2 — User-Agent-Stylesheet
By default, as we explored in “CSS Properties Default Styles” (Level-1), all the HTML elements get the same values for all CSS properties. Again, this is according to the “CSS Properties Initial Styles” (Level-1), which declares that all CSS properties have only one initial value.
But now comes the part that distinguishes between different types of HTML elements — the “User-Agent-Stylesheet” (Level 2).
The “User-Agent-Stylesheet” (Level 2) is the default CSS file that the browser companies implement in their browsers. This level establishes a direct connection between CSS and HTML by creating styles that distinguish between some of the tags. This is as opposed to the “CSS Properties Initial Styles” (Level-1) where the initial styles have no relation to the HTML elements.
For example, the display property’s initial value is always equal to inline . But as you may already know, the <div> HTML element has a display: block value by default. This change comes from the “User-Agent-Stylesheet” (Level-2).
The best way to understand these differences is by inspecting the <span> and <div> HTML elements:
- When we inspect the<span>HTML element we won’t see any styles. That’s because the dev tools don’t show you the “CSS Properties Initial Styles” (Level-1) in the “inspect element” panel, and the user agent styles (“User-Agent-Stylesheet” (Level 2)), which the dev tools do show, don’t have any additional definitions for the <span> HTML element.
Think about that: you don’t want to see all the CSS properties with their initial value (according to“CSS Properties Default Styles” (Level-1)) for every HTML element which you are debugging.
The display property’s initial value is inline . Because of that, it doesn’t show up in the “inspect element” debugger on our browser.
- But when we inspect the<div>HTML element we will see the display: block style defined for it. This style differs from the CSS specification’s “CSS Properties Initial Styles” (Level-1), in which every element has a default value of display: inline .
These different styles, such as shown in this example of the <div> HTML element, come from the “User-Agent-Stylesheet” (Level 2).
Who Decides What the HTML Elements’ “Special” Styles are?
The decision of what the default styles on some of the HTML elements should be is again part of the W3C/WHATWG web standard. However, unlike the “CSS Properties Initial Styles” (Level-1), there are sometimes differences in how different browsers decide to implement this part.
An example of default Styles for HTML 4 — from the CSS 2.2 Specification:
(If you want to see what these specifications look like, here are some of them: CSS 2.1, CSS 2.2, CSS 3).
Level 3 — Normalize CSS
Since the implementation of the “User-Agent-Stylesheet” (Level-2) doesn’t always follow the W3C web standard in all browsers, the “Normalize CSS” was invented. The “Normalize CSS” gives us an easy way to create consistent styles across different browsers.
Whats is “Normalize CSS” and How Does It Work?
The “Normalize CSS”’s main idea is to create a default HTML style that is the same across all browsers, overriding those styles in the “User-Agent-Stylesheet” (Level 2) that aren’t implemented equally by all browsers.
“Normalize CSS” adds styles that override those user-agent styles that weren’t implemented equally across all the browsers. The normalize.css is a CSS file that addresses these issues so that browsers display all HTML elements the same way.
Example (from normalize.css):
The Normalize.css Project:
The normalize.css is a highly recommended project created by Nicolas Gallagher:
Normalize.css
Normalize.css makes browsers render all elements more consistently and in line with modern standards. It precisely…
Level 4 — CSS Reset
There are many cases in which we wouldn’t want to use the browsers’ basic style. In most cases, we don’t want the default font-size and the margin values that we get from the “User-Agent-Stylesheet” (Level-2) styles. That’s the reason that “CSS Reset” was invented.
What is a “CSS Reset” and How Does It Work?
“CSS Reset” is a CSS file that overrides those styles of the “User-Agent-Stylesheet” (Level-2) whose effect we don’t want right from the beginning of our projects.
Using the example of the <h1> to <h6> HTML elements, the “CSS Reset” will override and thus remove the default styles from those HTML elements that are given by the “User-Agent-Stylesheet” (Level-2).
Example of heading reset:
There are many types of “CSS Reset” files, and the most known one is by Eric Meyer. But I use my own “CSS Reset” file and in it I reset only the elements that I find necessary. An example of my “CSS Reset”:
But don’t be mistaken, “CSS Reset” doesn’t remove all the “User-Agent-Stylesheet” (Level-2) styles. For example, we still keep all the basic styles of display: block on HTML elements like: <div> , <ul> , <section> , <article> and many others.
Because of this, think of “CSS Reset” as an 80 percent reset of the default styles that the “User-Agent-Stylesheet” (Level-2) gives us.
Combining “Normalize CSS” and “CSS Reset”
In my projects I use both of these methods — Normalize and Reset. First, I use the “normalize.css”, which brings all the browser styles to the standard of “User-Agent-Stylesheet” (Level-2). Then I load my own “Reset CSS” file that removes all the styles that I don’t need.
Example (Using “Sass” import):
If you want to go deeper into “Normalize CSS” and “CSS Reset” you can read my earlier article: “Normalize CSS or CSS Reset?!”.
Summarizing the Four Basic CSS Levels
We started by learning about the default CSS levels that we have in our browsers:
- “CSS Properties Default Styles” (Level-1) — this is in charge of creating all the default values of all the properties we have in CSS.
- “User-Agent-Stylesheet” (Level-2) — this is in charge of adding different default styles for some of the HTML elements.
Then, we learned how to control the CSS with your own CSS basic layers:
- “Normalize CSS” (Level-3) — is in charge of keeping the default HTML styles, “User-Agent-Stylesheet” (Level 2), the same way across all browsers.
- “CSS Reset” (Level-4) — overrides almost all the default “User-Agent-Stylesheet” (Level-2) styles whose effect we want to eliminate right from the beginning of our projects.
These four basic CSS layers create the basic styles of our project.
From here, let’s dive now into the “CSS Reset Keywords” (Part-5) and “the all Reset Property” (Part-6), which will give us the power to reset CSS any way we want.
Part 5 — The CSS Reset Keywords
In the last several years, CSS has given us the CSS reset keywords: initial , inherit , unset , and the revert , which have been fully implemented by browsers only in the last few months.
These CSS reset keyword values enable us to reset CSS any way we want. Let’s go over them:
The “inherit” and “initial” keywords
At the beginning of this article, I talked about CSS’s basic styles, “CSS Properties Default Styles” (Level-1). And you saw that there properties that have an inheritance in CSS and those who don’t have.
The ‘inherit’ value:
We will use the inherit value if we have a selector for which we want to reset a specific property that has a default inherited behavior, and keep that behavior.
For example, when I create “CSS Reset” styles in my project, I don’t want the <h1> to <h6> HTML elements’ default styles. Therefore I (re)set their font-size and font-weight properties to the inherit value. This way, they behave like regular HTML elements that didn’t get any font styles, and they will inherit the font-size and font-weight from the parent HTML element.
Example:
The ‘initial’ value:
All the other CSS properties (which are the majority) don’t inherit by default. To keep this behavior when we want to reset these other properties, we will use the initial value.
This way, if we already declared some styles on a CSS selector, we can reset those properties to their initial value — those being the “CSS Properties Default Styles” (Level-1), by using the initial keyword.
Example:
The ‘unset’ value:
As you can see, in most cases, we will want to reset the first group of properties — the ones with the “inherited properties” — to their inherit value. In the second group of properties — the “non-inherited properties” — we will want to reset with the initial value.
To enable this, we got a new keyword value called unset . The unset value will automatically reset a property according to its type:
- Inherited properties — the unset value will act like the inherit value.
- Non-inherited properties — the unset value will act like the initial value.
For example, position: unset will be equal to position: initial .
But when we use the unset value on the font-size property, for example, font-size: unset , it will be equal to font-size: inherit .
This way you can reset all the properties with the same keyword value of unset .
Example:
The Problem with the initial Value
In some cases, when we reset “non-inherited properties”, we might get an effect that we don’t want. For example: if we reset the display property on an HTML element whose default is block , such as the <div> HTML element, this will return us to the inline value.
The reason for this, if you remember from the beginning of this article, is the distinction between “CSS Properties Default Styles” (Level-1) to “User-Agent-Stylesheet” (Level-2). In this distinction, we saw the reason that a <div> HTML element has the display: block declaration. This is because of the default style that the “User-Agent-Stylesheet” (Level-2) applies to the <div> s.
The initial style doesn’t come from the “User-Agent-Stylesheet” (Level-2), and because of this, the <div> HTML element with display: initial will return us to display: inline .
To solve this problem, we have the fourth CSS reset keyword, which is called revert . The revert keyword allows us to reset to the browser’s default style, the “User-Agent-Stylesheet” (Level-2).
The ‘revert’ value:
The revert keyword is the smartest keyword of all the other “CSS reset keywords”. It does three operations for us:
- It gives the default “inherited properties” — will get the inherit value.
- It gives the default “non-inherited properties” case-1 — which have styles from the “User-Agent-Stylesheet” (Level-2), the default style of the specific HTML element that they are applied to.
- It gives the default “non-inherited properties” case-2 — which have no styles on the “User-Agent-Stylesheet” the initial style of the “CSS Properties Default Styles” (Level-1).
Example:
A Summary of the CSS Reset Keywords
As you can see, these CSS reset keywords can be a little confusing in the beginning. But after you understand the browser’s basic logic they become a lot easier to use in controlling the browser’s basic styles.
I created this diagram that presents you how the CSS reset keywords work:
Creating A-Normal styles
It’s very important to remember that we can still reset “inherited properties” such as font-size with the initial value. This way we get the browser default font-size that’s not affected by the font-size in your stylesheet, example:
In the opposite direction, we can inherit properties like padding , which are by default “non-inherited properties”. This way, we can create, for example, an inner HTML element that inherits the padding size from its parent HTML element.
Example:
Live Code:
* This isn’t recommended, but if you can think about a real use-case, you can use this thing.
Part 6 — The “all” Reset Property
If you want to reset an HTML element that has a lot of CSS defined properties, there is a new property called all that you can use.
This new property resets several properties at once. This property’s common usage is with the unset and the revert keyword values (“CSS Reset Keywords” — Part 5), which define the behavior according to the property type and/or the HTML element’s default styles, which are the “CSS Properties Initial Styles” (Level-1) and the User-Agent-Stylesheet (Level-2).
This way, instead of going over each one of the properties, we can reset all of them together.
Example:
We can use this, for example, to reset all the styles defined on a container, and be sure that we don’t get styles from the parent elements.
“The CSS Reset of the Future”
We can assume that several months from now, after the revert keyword gets implemented by the last minor browsers like “Samsung Internet” that still don’t support it, we will see new ways to create “CSS Reset” (Level-4).
Think how easy it will be to reset with the all property and the unset / revert values. Here is an example of the “future CSS reset”, as I imagine it:
Future CSS Reset (can look like):
* The “Samsung Internet” browser is built on the “Chrome” engine but gets its updates in a delayed fashion.
To Summarize
In this article, I tried to give all the necessary information on how the CSS that appears in the browser is built, how to customize it to your website’s needs, and how to control the CSS properties any way you want.
Final Words
That’s all.
I hope you’ve enjoyed this article and learned from my experience.
If you like this post, I would appreciate applause and sharing 🙂
Who Am I?
I am Elad Shechter, a Web Developer specializing in CSS & HTML design and architecture. Working at Yad2.
Introducing the CSS Cascade
The cascade is an algorithm that defines how user agents combine property values originating from different sources. The cascade defines the origin and layer that takes precedence when declarations in more than one origin or cascade layer set a value for a property on an element.
The cascade lies at the core of CSS, as emphasized by the name: Cascading Style Sheets. When a selector matches an element, the property value from the origin with the highest precedence gets applied, even if the selector from a lower precedence origin or layer has greater specificity.
This article explains what the cascade is and the order in which CSS declarations cascade, covering cascade layers and origin type. Understanding origin precedence is key to understanding the cascade.
Origin types
The CSS cascade algorithm’s job is to select CSS declarations in order to determine the correct values for CSS properties. CSS declarations come from different origin types: User-agent stylesheets, Author stylesheets, and User stylesheets.
Though style sheets come from these different origins and can be within different layers in each of these origins, they overlap in scope; to make this work, the cascade algorithm defines how they interact. Before addressing the interactions, let’s define some terms:
User-agent stylesheets
User-agent, or browsers, have basic style sheets that give default styles to any document. These style sheets are named user-agent stylesheets. Most browsers use actual stylesheets for this purpose, while others simulate them in code. The end result is the same.
Some browsers let users modify the user-agent stylesheet, but this is rare and not something that can be controlled.
Although some constraints on user-agent stylesheets are set by the HTML specification, browsers have a lot of latitude: that means some differences exist between browsers. To simplify the development process, Web developers may use a CSS reset stylesheet, such as normalize.css, which sets common properties values to a known state for all browsers before beginning to make alterations to suit their specific needs.
Unless the user-agent stylesheet includes an !important next to a property, making it «important», styles declared by author styles, including a reset style sheet, take precedence over the user-agent styles, regardless of the specificity of the associated selector.
Author stylesheets
Author stylesheets are the most common type of style sheet; these are the styles written by web developers. These styles can reset user-agent styles, as noted above, and define the styles for the design of a given web page or application. The author, or web developer, defines the styles for the document using one or more linked or imported stylesheets, <style> blocks, and inline styles defined with the style attribute. These author styles define the look and feel of the website — its theme.
User stylesheets
In most browsers, the user (or reader) of the website can choose to override styles using a custom user stylesheet designed to tailor the experience to the user’s wishes. Depending on the user agent, user styles can be configured directly or added via browser extensions.
Cascade layers
The cascade order is based on origin type. The cascade within each origin type is based on the declaration order of cascade layers within that type. For all origins — user-agent, author, or user — styles can be declared within or outside of named or anonymous layers. When declared using layer , layer() or @layer , styles are placed into the specified named layer, or into an anonymous layer if no name is provided. Styles declared outside of a layer are treated as being part of an anonymous last declared layer.
Let’s take a look at cascading origin type before diving into cascade layers within each origin type.
Cascading order
The cascading algorithm determines how to find the value to apply for each property for each document element. The following steps apply to the cascading algorithm:
- Relevance: It first filters all the rules from the different sources to keep only the rules that apply to a given element. That means rules whose selector matches the given element and which are part of an appropriate media at-rule.
- Origin and importance: Then it sorts these rules according to their importance, that is, whether or not they are followed by !important , and by their origin. Ignoring layers for the moment, the cascade order is as follows:
Order (low to high) Origin Importance 1 user-agent (browser) normal 2 user normal 3 author (developer) normal 4 CSS @keyframe animations 5 author (developer) !important 6 user !important 7 user-agent (browser) !important 8 CSS transitions - Specificity: In case of equality with an origin, the specificity of a rule is considered to choose one value or another. The specificity of the selectors are compared, and the declaration with the highest specificity wins.
- Order of appearance: In the origin with precedence, if there are competing values for a property that are in style block matching selectors of equal specificity, the last declaration in the style order is applied.
The cascade is in ascending order, meaning animations have precedence of normal values, whether those are declared in user, author, or user-agent styles, important values take precedence over animations, and transitions have precedence over important values.
Note: Transitions and animations
Property values set by animation @keyframes are more important than all normal styles (those with no !important set).
Property values being set in a transition take precedence over all other values set, even those marked with !important .
The cascade algorithm is applied before the specificity algorithm, meaning if :root p < color: red;>is declared in the user stylesheet (line 2) and a less specific p
Basic example
Before taking a deeper look at how cascade layers impact the cascade, let’s look at an example involving multiple sources of CSS across the various origins, and work through the steps of the cascade algorithm:
Here we have a user agent style sheet, two author style sheets, a user stylesheet, and inline styles within the HTML:
User-agent CSS:
Author CSS 1:
Author CSS 2:
User CSS:
HTML:
In this case, declarations inside li and .specific rules should apply.
Once again, there are four steps in the cascade algorithm, in order:
- Relevance
- Origin and importance
- Specificity
- Order of appearance
The 1px is for print media. Due to lack of relevance based on its media type, it is removed from consideration.
No declaration is marked as !important , so the precedence order is author style sheets over user style sheets over user-agent stylesheet. Based on origin and importance, the 1em from the user stylesheet and the 10px from the user-agent stylesheet are removed from consideration.
Note that even though the user style on .specific of 1em has a higher specificity, it’s a normal declaration in a user style sheet. As such, it has a lower precedence than any author styles, and gets removed by the origin and importance step of the algorithm before specificity even comes into play.
There are three declarations in author stylesheets:
The last one, the 5px is part of a cascade layer. Normal declarations in layers have lower precedence than normal styles not in a layer within the same origin type. This is also removed by step 2 of the algorithm, origin and importance.
This leaves the 0 and the 3px , which both have the same selector, hence the same specificity.
We then look at order of appearance. The second one, the last of the two unlayered author styles, wins.
Note: The declaration defined in the user CSS, while it may have greater specificity, is not chosen as the cascade algorithm’s origin and importance is applied before the specificity algorithm. The declaration defined in a cascade layer, though it may come later in the code, will not have precedence either as normal styles in cascade layers have less precedence than normal unlayered styles. Order of appearance only matters when both origin, importance, and specificity are equal.
Author styles: inline styles, layers, and precedence
The table in Cascading order provided a precedence order overview. The table summarized the user-agent, user, and author origin type styles in two lines each with «origin type — normal» and «origin type — !important». The precedence within each origin type is more nuanced. Styles can be contained within layers within their origin type, and, with author styles, there is also the issue of where inline styles land in the cascade order.
The order in which layers are declared is important in determining precedence. Normal styles in a layer take precedence over styles declared in prior layers; with normal styles declared outside of any layer taking precedence over normal layered styles regardless of specificity.
In this example, the author used CSS’s @import rule to import five external style sheets within a <style> information element.
and then in the body of the document we have inline styles:
In the CSS code block above, three cascade layers named «A», «B», and «C», were created, in that order. Three stylesheets were imported directly into layers and two were imported without creating or being assigned to a layer. The «All unlayered styles» in the list below (normal author style precedence — order 4) includes styles from these two stylesheets and the additional unlayered CSS style blocks. In addition, there are two inline styles, a normal line-height declaration and an important text-decoration declaration:
| Order (low to high) | Author style | Importance |
|---|---|---|
| 1 | A — first layer | normal |
| 2 | B — second layer | normal |
| 3 | C — last layer | normal |
| 4 | All unlayered styles | normal |
| 5 | inline style | normal |
| 6 | animations | |
| 7 | All unlayered styles | !important |
| 8 | C — last layer | !important |
| 9 | B — second layer | !important |
| 10 | A — first layer | !important |
| 11 | inline style | !important |
| 12 | transitions |
In all origin types, the non important styles contained in layers have the lowest precedence. In our example, the normal styles associated with the first declared layer (A) have lower precedence than normal styles in the second declared layer (B), which have lower precedence than normal styles in the third declared layer (C). These layered styles have lower precedence than all normal unlayered styles, which includes normal styles from unlayeredStyles.css , moreUnlayeredStyles.css , and the color of p in the <style> itself.
If any of the layered styles in A, B, or C, have selectors with higher specificity matching an element, similar to :root body p < color: black;>, it doesn’t matter. Those declarations are removed from consideration because of origin; normal layered styles have less precedence than normal unlayered styles. If, however, the more specific selector :root body p < color: black;>was found in unlayeredStyles.css , as both origin and importance have the same precedence, specificity would mean the more specific, black declaration would win.
The layer order of precedence is inverted for styles declared as !important . Important styles declared in a layer take precedence over important styles declared outside of a layer. Important styles in the first declared layer (A) take precedence over important declarations found in layer B, which takes precedence over C, which have precedence over important declarations in the unlayered styles.
Inline styles
Only relevant to author styles are inline styles, declared with the style attribute. Normal inline styles take precedence over any other normal author styles, no matter the specificity of the selector. If line-height: 2; were declared in a :root body p selector block in any of the five imported stylesheets, the line height would still be 1.6 .
Normal inline styles take precedence over any other normal author styles unless the property is being altered by a CSS animation.
All important inline styles take precedence over all author styles, important and not, inline and not, layered and not. Important styles also take precedence over animated properties, but not transitioning properties. Three things can override an important inline style: 1) an important user style, 2) an important user agent style, or 3) a property value being transitioned.
Importance and layers
The origin type precedence order is inverted for important styles. Important styles declared outside of any cascade layer have lower precedence than those declared as part of a layer. Important values that come in early layers have precedence over important styles declared in subsequent cascade layers.
Take for example the following CSS:
Even though the red is declared first and has a less specific selector, because unlayered CSS takes precedence over layered CSS, the paragraph will be red. Had we included an inline style on the paragraph setting it to a different color, such as <p style=»color: black»> , the paragraph would be black.
When we add !important to this bit of CSS, the precedence order is reversed with the stylesheet:
Now the paragraph will be blue. The !important in the earliest declared layer takes precedence of subsequent layers and unlayered important declarations. If the inline style contained !important, such as <p style=»color: black !important»> , again the paragraph would be black. Inline importance does take precedence over all other author declared !important declarations, no matter the specificity.
Note: !important reverses the precedence of cascade layers. For this reason, rather than using !important to override external styles, import frameworks, third party styles, widget stylesheets, etc., into layers, demoting their precedence. !important should only be used sparingly, if ever, to guard required styles against later overrides, in the first declared layer.
Styles that are transitioning take precedence over all important styles, no matter who or how they are declared.
Complete cascade order
Now that we have a better understanding of origin type and cascade layer precedence, we realize the table in Cascading order could have more accurately been represented by the following table:
| Precedence Order (low to high) |
Style Origin | Importance |
|---|---|---|
| 1 | user-agent — first declared layer | normal |
| user-agent — last declared layer | ||
| user-agent — unlayered styles | ||
| 2 | user — first declared layer | normal |
| user — last declared layer | ||
| user — unlayered styles | ||
| 3 | author — first declared layer | normal |
| author — last declared layer | ||
| author — unlayered styles | ||
| inline style | ||
| 4 | animations | |
| 5 | author — unlayered styles | !important |
| author — last declared layer | ||
| author — first declared layer | ||
| inline style | ||
| 6 | user — unlayered styles | !important |
| user — last declared layer | ||
| user — first declared layer | ||
| 7 | user-agent — unlayered styles | !important |
| user-agent — last declared layer | ||
| user-agent — first declared layer | ||
| 8 | transitions |
Which CSS entities participate in the cascade
Only CSS property/value pair declarations participate in the cascade. This means that at-rules containing entities other than declarations, such as a @font-face rule containing descriptors, don’t participate in the cascade.
For the most part, the properties and descriptors defined in at-rules don’t participate in the cascade. Only at-rules as a whole participate in the cascade. For example, within a @font-face rule, font names are identified by font-family descriptors. If several @font-face rules with the same descriptor are defined, only the most appropriate @font-face , as a whole, is considered. If more than one are identically appropriate, the entire @font-face declarations are compared using steps 1, 2, and 4 of the algorithm (there is no specificity when it comes to at-rules).
While the declarations contained in most at-rules — such as those in @media , @document , or @supports — participate in the cascade, the at-rule may make an entire selector not relevant, as we saw with the print style in the basic example.
Declarations in @keyframes don’t participate in the cascade. As with @font-face , only the @keyframes as a whole is selected via the cascade algorithm. The precedence order of animation is described below.
When it comes to @import , the @import doesn’t participate itself in the cascade, but all of the imported styles do participate. If the @import defines a named or anonymous layer, the contents of the imported stylesheet are placed into the specified layer. All other CSS imported with @import is treated as the last declared layer. This was discussed above.
Finally, @charset obeys specific algorithms and isn’t affected by the cascade algorithm.
CSS animations and the cascade
CSS animations, using @keyframes at-rules, define animations between states. Keyframes don’t cascade, meaning that at any given time CSS takes values from only one single @keyframes , and never mixes multiple ones together.
If the several keyframe animations are defined with the same animation name, the last defined @keyframes in the origin and layer with the greatest precedence. Only one @keyframes definition is used, even if the @keyframes animate different property. @keyframes with the same name are never combined.
In this example, there are three separate animation declaration named repeatedName . When animation: infinite 5s alternate repeatedName is applied to the paragraph, only one animation is applied: the keyframe animation defined in the unlayered CSS takes precedence over the layered keyframe animation declarations based on origin and cascade layer precedence order. In this example, only the element’s font size will be animated.
Note: There are no important animations, as property declarations in a @keyframes block that contain !important as part of the value are ignored.
Resetting styles
After your content has finished altering styles, it may find itself in a situation where it needs to restore them to a known state. This may happen in cases of animations, theme changes, and so forth. The CSS property all lets you quickly set (almost) everything in CSS back to a known state.
all lets you opt to immediately restore all properties to any of their initial (default) state, the state inherited from the previous level of the cascade, a specific origin (the user-agent stylesheet, the author stylesheet, or the user stylesheet), or even to clear the values of the properties entirely.
What is a user agent stylesheet?
I’m working on a web page in Google Chrome. It displays correctly with the following styles.
It is important to note that I didn’t define these styles. In Chrome developer tools, it says user agent stylesheet in place of the CSS file name.
Now if I submit a form and some validation error occurs, I get the following stylesheet:
The font-size from these new styles is disturbing my design. Is there a way to force my stylesheets and if possible, completely overwrite Chrome’s default stylesheet?
15 Answers 15
What are the target browsers? Different browsers set different default CSS rules. Try including a CSS reset, such as the meyerweb CSS reset or normalize.css, to remove those defaults. Google «CSS reset vs normalize» to see the differences.
![]()
If <!DOCTYPE> is missing in your HTML content you may experience that the browser gives preference to the «user agent stylesheet» over your custom stylesheet. Adding the doctype fixes this.
![]()
Regarding the concept “user agent style sheet”, consult section Cascade in the CSS 2.1 spec.
User agent style sheets are overridden by anything that you set in your own style sheet. They are just the rock bottom: in the absence of any style sheets provided by the page or by the user, the browser still has to render the content somehow, and the user agent style sheet just describes this.
So if you think you have a problem with a user agent style sheet, then you really have a problem with your markup, or your style sheet, or both (about which you wrote nothing).
Marking the document as HTML5 by the proper doctype on the first line, solved my issue.
A user agent style sheet is a ”default style sheet” provided by the browser (e.g., Chrome, Firefox, Edge, etc.) in order to present the page in a way that satisfies ”general presentation expectations.” For example, a default style sheet would provide base styles for things like font size, borders, and spacing between elements.
It is also common to use a CSS Reset to normalize or remove inconsistencies between browsers due to differences between which base styles are applied by each browser.
From the specification.
A user agent’s default style sheet should present the elements of the document language in ways that satisfy general presentation expectations for the document language.
For more information about user agents in general, see user agent.
![]()
Answering the question in title, what is the user agent stylesheet, the set of default styles in the browser: Here are some of them:
Personal opinion: Don’t fight with them. They have good default values, for example, in rtl/bidi cases and are consistent nowadays. Reset what you see irrelevant to you, not all of them at once.
Define the values that you don’t want to be used from Chrome’s user agent style in your own CSS content.
![]()
Some browsers use their own way to read .css files. So the right way to beat this: If you type the command line directly in the .html source code, this beats the .css file, in that way, you told the browser directly what to do and the browser is at position not to read the commands from the .css file. Remember that the commands writen in the .html file is stronger than the command in the .css.
I had the same problem as one of my <div>’s had the margin set by the browser. It was quite annoying but then I figured out as most of the people said, it’s a markup error.
I went back and checked my <head> section and my CSS link was like below:
<link rel=»stylesheet» href=»ex.css»>
I included type in it and made it like below:
<link rel=»stylesheet» type=»text/css» href=»ex.css»>
My problem was solved.
![]()
![]()
I just wanted to expand on the response from @BenM based on what I read here from Ire Aderinokun. Because the user-agent stylesheet provides helpful default styling, think twice before overriding it.
I had a dumb error where a button element didn’t look right in Chrome. I had partially styled it because I didn’t want it to look like a traditional button. However, I left out style elements like border, border-color, etc. So Chrome was stepping in to supply the parts that it thought I was missing.
The problem went away once I added styles like border: none , etc.
So if anyone else is having this problem, make sure you are explicitly overriding all the applicable default user-agent styles for an element if you notice it looks wonky, especially if you don’t want to reset the user agent styles completely. It worked for me.