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.

Have you published a response to this? :

Responses

Jeremy Keith

Last week, Jeremy Keith wrote an excellent summary of the three ways to inject CSS into a web document. In short, he said:

There are three ways—that I know of—to associate styles with markup.

External CSS

<link rel="stylesheet" href="/path/to/styles.css">

Embedded CSS

<style>element { property: value; }</style>

Inline CSS

<element style="property: value"></element>
Jeremy Keith (summarised)

While talking about external CSS, he hinted at what I consider to be a distinct fourth way with its own unique use cases:; using the Link: HTTP header. I’d like to share with you how it works and why I think it needs to be kept in people’s minds, even if it’s not suitable for widespread deployment today.

Injecting CSS using the Link: HTTP Header

Every one of Jeremy’s suggestions involve adding markup to the HTML document itself. Which makes sense; you almost always want to associate styles with a document regardless of the location it’s stored or the medium over which it’s transmitted. The most popular approach to adding CSS to a page uses the <link> HTML element, but did you know… the <link> element has a semantically-equivalent HTTP header, Link:.

The only active example I’ve been able to find are test pages like Jens Oliver Meiert’s (pictured), Louis Lazaris’s , and Anne van Kesteren’s, but it’s possible that others are hiding elsewhere on the Web.

According to the specifications, the following HTTP responses are equivalent in terms of the CSS that would be loaded and applied to the document:

Traditional external CSS injection:

HTTP/1.1 200 OK Content-Type: text/html; charset=UTF-8 <!doctype html> <html> <head> <title>My page</title>  <link rel="stylesheet" href="/style/main.css"> </head> <body> <h1>My page</h1> </body> </html>

Link: header CSS injection:

HTTP/1.1 200 OK Content-Type: text/html; charset=UTF-8 Link: </style/main.css>; rel="stylesheet" <!doctype html> <html> <head> <title>My page</title>  </head> <body> <h1>My page</h1> </body> </html>

A webserver adds headers when it serves a document anyway. Adding one more is no big deal. Why is this important?

This isn’t something you should put on your website right now. This (21-year-old!) standard is still only really supported in Firefox and pre-Blink Opera, so you lose perhaps 95% of the Web (it could be argued that because CSS ought to be considered progressive enhancement, it’s tolerable so long as your HTML is properly-written).

If it were widely-supported, though, that would be a really good thing: HTTP headers beat meta/link tags for configurability, performance management, and separation of concerns. Need some specific examples? Sure: here’s what you could use HTTP stylesheet linking for:

You have no idea how many times in my career I’d have injected CSS Link: headers using a reverse proxy server the standard was universally-implemented. This technique would have made one of my final projects at the Bodleian so much easier…

  • Performance improvement using aggressively preloaded “top” stylesheets before the DOM parser even fires up.
  • Stylesheet injection by edge caches to provide regionalised/localised changes to brand identity.
  • Strong separation of content and design by hosting content and design elements in different systems.
  • Branding your staff intranet differently when it’s accessed from outside the network than inside it.
  • Rebranding proprietary services on your LAN without deep inspection, using reverse proxies.
  • Less-destructive user stylesheet injection by plugins etc. that doesn’t risk breaking icky on-page Javascript (e.g. theme switchers).
  • Browser detection? 😂 You could use this technique today to detect Firefox. But you absolutely shouldn’t; if you think you need browser detection in CSS, use this instead.

Unfortunately right now though, stylesheet Link: headers remain consigned to the bin of “cool stylesheet standards that we could probably use if it weren’t for fucking Google”; see also alternate stylesheets.

Update: I later used this technique to make a seemingly-empty web page.

Richard MacManus

I’m on the ‘blog posts NOT blogs’ hill too -> 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. adactio.com/journal/17692

1 Share

# Shared by beyond tellerrand on Tuesday, December 15th, 2020 at 4:26pm

13 Likes

# Liked by John F Croston III on Tuesday, December 15th, 2020 at 5:08pm

# Liked by Adam Argyle on Tuesday, December 15th, 2020 at 5:08pm

# Liked by beyond tellerrand on Tuesday, December 15th, 2020 at 5:08pm

# Liked by Brad Frost on Tuesday, December 15th, 2020 at 5:08pm

# Liked by LurkGently on Tuesday, December 15th, 2020 at 5:08pm

# Liked by Eric Wallace on Tuesday, December 15th, 2020 at 5:24pm

# Liked by Luke Dorny on Tuesday, December 15th, 2020 at 7:15pm

# Liked by 7-kurgan-d on Tuesday, December 15th, 2020 at 7:16pm

# Liked by Josh Buchea 😊 on Tuesday, December 15th, 2020 at 7:16pm

# Liked by Hugh Haworth on Tuesday, December 15th, 2020 at 7:16pm

# Liked by Rasmus Kaj on Tuesday, December 15th, 2020 at 8:19pm

# Liked by Batbayar B. on Wednesday, December 16th, 2020 at 1:24am

# Liked by Nelton Gemo on Thursday, December 17th, 2020 at 8:52pm

Related posts

content-visibility in Safari

Safari 18 supports `content-visibility: auto` …but there’s a very niche little bug in the implementation.

Manual ’till it hurts

Try writing your HTML in HTML, your CSS in CSS, and your JavaScript in JavaScript.

Displaying HTML web components

You might want to use `display: contents` …maybe.

Schooltijd

Going back to school in Amsterdam.

Speedier tunes

Improving performance with containment.

Related links

New CSS that can actually be used in 2024 | Thomasorus

Logical properties, container queries, :has, :is, :where, min(), max(), clamp(), nesting, cascade layers, subgrid, and more.

Tagged with

My Modern CSS Reset | jakelazaroff.com

I like the approach here: logical properties and sensible default type and spacing.

Tagged with

Hyper-responsive web components | Trys Mudford

Trys describes exactly the situation where you really do need to use the Shadow DOM in a web component—as opposed to just sticking to HTML web components—, and that’s when the component is going to be distributed and you have no idea where:

This component needed to be incredibly portable, looking great on any third-party website, in any position, at any viewport, with any amount of content. It had to be a “hyper-responsive” component.

Tagged with

Building a robust frontend using progressive enhancement - Service Manual - GOV.UK

Oh, how I wish that every team building for the web would use this sensible approach!

Tagged with

Hire HTML and CSS people

Every problem at every company I’ve ever worked at eventually boils down to “please dear god can we just hire people who know how to write HTML and CSS.”

Tagged with

Previously on this day

8 years ago I wrote Design principles

What makes ‘em good?

9 years ago I wrote Shadows and smoke

Namen sind Schall und Rauch.

11 years ago I wrote Tracking

This post was deleted.

11 years ago I wrote Defining the damn thang

We must go deeper.

20 years ago I wrote Just my type

I made a trip up to London today. I just happened to be in the vicinity of Regent Street so I popped into the new Apple store. It’s quite a stunning shop and I was, needless to say, in my element.

21 years ago I wrote The long debate

It looks like a well-worn chestnut is being resurrected in web design circles (if I may horribly mangle my metaphors).

22 years ago I wrote Rocks

Compare and contrast:

23 years ago I wrote Designomatic

You have to be a real geek to enjoy this kind of thing. Needless to say, I love it.