CSS’ barrier to entry is extremely low, mainly due to the nature of its syntax. Being clear and easy to understand, the syntax makes sense even to the inexperienced Web designer. It’s so simple, in fact, that you could style a simple CSS-based website within a few hours of learning it.
But this apparent simplicity is deceitful. If after a few hours of work, your perfectly crafted website looks great in Safari, all hell might break loose if you haven’t taken the necessary measures to make it work in Internet Explorer. In a panic, you add hacks and filters where only a few tweaks or a different approach might do. Knowing how to deal with these issues comes with experience, with trial and error and with failing massively and then learning the correct way.
Understanding a few often overlooked concepts is also important. The concepts may be hard to grasp and look boring at first, but understanding them and knowing how to take advantage of them is important.
Two of these concepts are specificity and inheritance. Not very common words among Web designers, are they? Talking about
The notion of a “cascade” is at the heart of CSS (just look at its name). It ultimately determines which properties will modify a given element. The cascade is tied to three main concepts: importance, specificity and source order. The cascade follows these three steps to determine which properties to assign to an element. By the end of this process, the cascade has assigned a weight to each rule, and this weight determines which rule takes precedence, when more than one applies.
There is also the
Knowing this, let’s look at the final order, in ascending order of importance:
Upon assessing a rule’s importance, the cascade attributes a specificity to it; if one rule is more specific than another, it overrides it.
If two rules share the same weight, source and specificity, the later one is applied.
The quickest way is to do the following. Add 1 for each element and pseudo-element (for example,
Let’s calculate the specificity of the following selectors using this method:
Andy Clarke’s CSS Specificity Wars chart.
Remember that non-CSS presentational markup is attributed with a specificity of 0, which would apply, for example, to the
Getting back to the
If you are using imported style sheets (
Finally, if two selectors turn out to have the same specificity, the last one will override the previous one(s).
You can follow a few guidelines to avoid major issues:
The CSS specification determines whether each property is inherited by default or not. Not all properties are inherited, but you can force ones to be by using the
Let’s go back to the first sentence of this section, which should make more sense now. When an element inherits a value from its parent, it inherits its computed value. Because the computed value exists even if it isn’t specified in the style sheet, a property can be inherited even then: the initial value will be used. So, you can make use of inheritance even if the parent doesn’t have a specified property.
Imagine you had to specify the
Don’t break it by using the universal selector (
Rarely does a CSS-related article not bring some kind of bad news about Internet Explorer. This article is no exception. IE supports the
For example, here below is Firebug in action, inspecting an element on the page. You can see that some properties are overridden (i.e. crossed out) by other more specific rules:
Firebug in action, informing you how specificity is working.
In the next shot, Safari’s Web Inspector shows the computed values of an element. This way, you can see the values even though they haven’t been explicitly added to the style sheet:
With Safari’s Web Inspector (and Firebug), you can view the computed values of a particular element.
Even if you don’t think about them, these issues are present in your daily work as a CSS author. Especially in the case of specificity, it’s important to know how they affect your style sheets and how to plan for them so that they cause only minimal (or no) problems.
But this apparent simplicity is deceitful. If after a few hours of work, your perfectly crafted website looks great in Safari, all hell might break loose if you haven’t taken the necessary measures to make it work in Internet Explorer. In a panic, you add hacks and filters where only a few tweaks or a different approach might do. Knowing how to deal with these issues comes with experience, with trial and error and with failing massively and then learning the correct way.
Understanding a few often overlooked concepts is also important. The concepts may be hard to grasp and look boring at first, but understanding them and knowing how to take advantage of them is important.
Two of these concepts are specificity and inheritance. Not very common words among Web designers, are they? Talking about
border-radius
and text-shadow
is a lot more fun; but specificity and inheritance are fundamental concepts that any person who wants to be good at CSS should understand. They will help you create clean, maintainable and flexible style sheets. Let’s look at what they mean and how they work.The notion of a “cascade” is at the heart of CSS (just look at its name). It ultimately determines which properties will modify a given element. The cascade is tied to three main concepts: importance, specificity and source order. The cascade follows these three steps to determine which properties to assign to an element. By the end of this process, the cascade has assigned a weight to each rule, and this weight determines which rule takes precedence, when more than one applies.
1. Importance
Style sheets can have a few different sources:- User agent
For example, the browser’s default style sheet. - User
Such as the user’s browser options. - Author
This is the CSS provided by the page (whether inline, embedded or external)
There is also the
!important
declaration to consider in the cascade. This declaration is used to balance the relative priority of user and author style sheets. While author style sheets take precedence over user ones, if a user rule has !important
applied to it, it will override even an author rule that also has !important
applied to it.Knowing this, let’s look at the final order, in ascending order of importance:
- User agent declarations,
- User declarations,
- Author declarations,
- Author
!important
declarations, - User
!important
declarations.
2. Specificity
Every CSS rule has a particular weight (as mentioned in the introduction), meaning it could be more or less important than the others or equally important. This weight defines which properties will be applied to an element when there are conflicting rules.Upon assessing a rule’s importance, the cascade attributes a specificity to it; if one rule is more specific than another, it overrides it.
If two rules share the same weight, source and specificity, the later one is applied.
2.1 How to Calculate Specificity?
There are several ways to calculate a selector’s specificity.The quickest way is to do the following. Add 1 for each element and pseudo-element (for example,
:before
and :after
); add 10 for each attribute (for example, [type=”text”]
), class and pseudo-class (for example, :link
or :hover
); add 100 for each ID; and add 1000 for an inline style.Let’s calculate the specificity of the following selectors using this method:
p.note
1 class + 1 element = 11#sidebar p[lang="en"]
1 ID + 1 attribute + 1 element = 111body #main .post ul li:last-child
1 ID + 1 class + 1 pseudo-class + 3 elements = 123
- a = 1 if the style is inline,
- b = the number of IDs,
- c = the number of attribute selectors, classes and pseudo-classes,
- d = the number of element names and pseudo-elements.
a=1, b=0, c=0, d=0 → 1000footer nav li:last-child
a=0, b=0, c=1, d=3 → 0013#sidebar input:not([type="submit"])
a=0, b=1, c=1, d=1 → 0111
(Note that the negation pseudo-class doesn’t count, but the selector inside it does.)
Andy Clarke’s CSS Specificity Wars chart.
Remember that non-CSS presentational markup is attributed with a specificity of 0, which would apply, for example, to the
font
tag.Getting back to the
!important
declaration, keep in mind that using it on a shorthand property is the same as declaring all of its sub-properties as !important
(even if that would revert them to the default values).If you are using imported style sheets (
@import
) in your CSS, you have to declare them before all other rules. Thus, they would be considered as coming before all the other rules in the CSS file.Finally, if two selectors turn out to have the same specificity, the last one will override the previous one(s).
2.2 Making Specificity Work For You
If not carefully considered, specificity can come back to haunt you and lead you to unwittingly transform your style sheets into a complex hierarchy of unnecessarily complicated rules.You can follow a few guidelines to avoid major issues:
- When starting work on the CSS, use generic selectors, and add specificity as you go along;
- Using advanced selectors doesn’t mean using unnecessarily complicated ones;
- Rely more on specificity than on the order of selectors, so that your style sheets are easier to edit and maintain (especially by others).
Refactoring CSS selectors to be less specific is exponentially more difficult than simply adding specific rules as situations arise.
3. Inheritance
A succinct and clear explanation of inheritance is in the CSS3 Cascading and Inheritance module specifications (still in “Working draft” mode):Inheritance is a way of propagating property values from parent elements to their children.Some CSS properties are inherited by the children of elements by default. For example, if you set the
body
tag of a page to a specific font, that font will be inherited by other elements, such as headings and paragraphs, without you having to specifically write as much. This is the magic of inheritance at work.The CSS specification determines whether each property is inherited by default or not. Not all properties are inherited, but you can force ones to be by using the
inherit
value.3.1 Object-Oriented Programming Inheritance
Though beyond the scope of this article, CSS inheritance shouldn’t be confused with object-oriented programming (OOP) inheritance. Here is the definition of OOP inheritance from Wikipedia, and it makes clear that we are not talking about the same thing:In object-oriented programming (OOP), inheritance is a way to form new classes […] using classes that have already been defined. Inheritance is employed to help reuse existing code with little or no modification. The new classes […] inherit attributes and behavior of the pre-existing classes. …
3.2 How Inheritance Works
When an element inherits a value from its parent, it is inheriting its computed value. What does this mean? Every CSS property goes through a four-step process when its value is being determined. Here’s an excerpt from the W3C specification:The final value of a property is the result of a four-step calculation: the value is determined through specification (the “specified value”), then resolved into a value that is used for inheritance (the “computed value”), then converted into an absolute value if necessary (the “used value”), and finally transformed according to the limitations of the local environment (the “actual value”).In other words:
- Specified value
The user agent determines whether the value of the property comes from a style sheet, is inherited or should take its initial value. - Computed value
The specified value is resolved to a computed value and exists even when a property doesn’t apply. The document doesn’t have to be laid out for the computed value to be determined. - Used value
The used value takes the computed value and resolves any dependencies that can only be calculated after the document has been laid out (like percentages). - Actual value
This is the value used for the final rendering, after any approximations have been applied (for example, converting a decimal to an integer).
background-color
specification states the following:Name: background-colorConfusing? It can be. So, what do we need to understand from all this? And why is it relevant to inheritance?
Value:
Initial: transparent
Applies to: all elements
Inherited: no
Percentages: N/A
Media: visual
Computed value: the computed color(s)
Let’s go back to the first sentence of this section, which should make more sense now. When an element inherits a value from its parent, it inherits its computed value. Because the computed value exists even if it isn’t specified in the style sheet, a property can be inherited even then: the initial value will be used. So, you can make use of inheritance even if the parent doesn’t have a specified property.
3.3 Using Inheritance
The most important thing to know about inheritance is that it’s there and how it works. If you ignore the jargon, inheritance is actually very straightforward.Imagine you had to specify the
font-size
or font-family
of every element, instead of simply adding it to the body
element? That would cumbersome, which is why inheritance is so helpful.Don’t break it by using the universal selector (
*
) with properties that inherit by default. Bobby Jack wrote an interesting post about this on his Five-Minute Argument blog. You don’t have to remember all of the properties that inherit, but you will in time.Rarely does a CSS-related article not bring some kind of bad news about Internet Explorer. This article is no exception. IE supports the
inherit
value only from version 8, except for the direction
and visibility
properties. Great.4. Using Your Tools
If you use tools like Firebug or Safari’s Web Inspector, you can see how a given cascade works, which selectors have higher specificity and how inheritance is working on a particular element.For example, here below is Firebug in action, inspecting an element on the page. You can see that some properties are overridden (i.e. crossed out) by other more specific rules:
Firebug in action, informing you how specificity is working.
In the next shot, Safari’s Web Inspector shows the computed values of an element. This way, you can see the values even though they haven’t been explicitly added to the style sheet:
With Safari’s Web Inspector (and Firebug), you can view the computed values of a particular element.
5. Conclusion
Hopefully this article has opened your eyes to (or has refreshed your knowledge of) CSS inheritance and specificity. We encourage you to read the articles cited below, as well as Smashing Magazine’s previous article on the topic.Even if you don’t think about them, these issues are present in your daily work as a CSS author. Especially in the case of specificity, it’s important to know how they affect your style sheets and how to plan for them so that they cause only minimal (or no) problems.
Resources And Further Reading
- Assigning Property Values, Cascading, and Inheritance, W3C
- CSS3: Cascading and Inheritance, W3C
- Selectors Level 3: Calculating a Selector’s Specificity, W3C
- The Cascade, SitePoint
- Inheritance and Cascade, Dev.Opera
- CSS Inheritance, Dorward Online
- Cascading Order and Inheritance in CSS, David’s Kitchen
- Understanding Style Precedence in CSS: Specificity, Inheritance, and the Cascade, Van SEO Design
- Specifics on CSS Specificity, CSS-Tricks
- Link Specificity, meyerweb.com
- Redundancy vs. Dependency, mezzoblue
No comments:
Post a Comment