Cascading Style Sheets
There are three ways—that I know of—to associate styles with markup.
External CSS
This is probably the most common. Using a link
element with a rel
value of “stylesheet”, you point to a URL using the href
attribute. That URL is a style sheet that is applied to the current document (“the relationship of the linked resource it is that is a ‘stylesheet’ for the current document”).
<link rel="stylesheet" href="/path/to/styles.css">
In theory you could associate a style sheet with a document using an HTTP header, but I don’t think many browsers support this in practice.
You can also pull in external style sheets using the @import
declaration in CSS itself, as long as the @import
rule is declared at the start, before any other styles.
@import url('/path/to/more-styles.css');
When you use link rel="stylesheet"
to apply styles, it’s a blocking request: the browser will fetch the style sheet before rendering the HTML. It needs to know how the HTML elements will be painted to the screen so there’s no point rendering the HTML until the CSS is parsed.
Embedded CSS
You can also place CSS rules inside a style
element directly in the document. This is usually in the head
of the document.
<style>
element {
property: value;
}
</style>
When you embed CSS in the head
of a document like this, there is no network request like there would be with external style sheets so there’s no render-blocking behaviour.
You can put any CSS inside the style
element, which means that you could use embedded CSS to load external CSS using an @import
statement (as long as that @import
statement appears right at the start).
<style>
@import url('/path/to/more-styles.css');
element {
property: value;
}
</style>
But then you’re back to having a network request.
Inline CSS
Using the style
attribute you can apply CSS rules directly to an element. This is a universal attribute. It can be used on any HTML element. That doesn’t necessarily mean that the styles will work, but your markup is never invalidated by the presence of the style
attribute.
<element style="property: value">
</element>
Whereas external CSS and embedded CSS don’t have any effect on specificity, inline styles are positively radioactive with specificity. Any styles applied this way are almost certain to over-ride any external or embedded styles.
You can also apply styles using JavaScript and the Document Object Model.
element.style.property = 'value';
Using the DOM style
object this way is equivalent to inline styles. The radioactive specificity applies here too.
Style declarations specified in external style sheets or embedded CSS follow the rules of the cascade. Values can be over-ridden depending on the order they appear in. Combined with the separate-but-related rules for specificity, this can be very powerful. But if you don’t understand how the cascade and specificity work then the results can be unexpected, leading to frustration. In that situation, inline styles look very appealing—there’s no cascade and everything has equal specificity. But using inline styles means foregoing a lot of power—you’d be ditching the C in CSS.
A common technique for web performance is to favour embedded CSS over external CSS in order to avoid the extra network request (at least for the first visit—there are clever techniques for caching an external style sheet once the HTML has already loaded). This is commonly referred to as inlining your CSS. But really it should be called embedding your CSS.
This language mix-up is not a hill I’m going to die on (that hill would be referring to blog posts as blogs) but I thought it was worth pointing out.