---
title: 'Linking the Stylesheet'
source: 'https://academia.sh/en/courses/css-fundamentals/linking-the-stylesheet'
course: 'Visual Presentation with CSS'
language: en
updated: '2026-08-17T18:09:17+00:00'
license: 'CC BY-SA 4.0'
---

# Linking the Stylesheet

Attaching a set of styles to a document in three ways — inline, internal, and external — and how these three ways differ in request count, reuse, and conflict resolution.

The previous lesson established that a rule consists of a selector and a declaration
block, and wrote the station page's first three rules. Rules have to live somewhere, and
where they live determines both maintenance cost and when the page's first render begins.

This lesson defines the three ways of attaching a stylesheet, shows the differences
between them with a measurable example, and revisits, from the stylesheet's side, the
render-blocking behavior established in the Web Fundamentals and HTML course's
resource-loading-order lesson.

## Three Ways

**Inline style** is written into an element's `style` attribute. There is no selector: the
declarations attach directly to that one element.

```html
<h1 style="color: #8a1c1c; font-size: 2rem">North Slope Measurement Station</h1>
```

**Internal style sheet** is written inside a `style` element in the document's head. The
rules are fully formed; the selectors only look at that one document.

```html
<head>
  <meta charset="utf-8">
  <title>North Slope Measurement Station</title>
  <style>
    h1 { font-size: 2rem; }
  </style>
</head>
```

**External style sheet** is a separate `.css` file attached to the document with a `link`
element. `rel="stylesheet"` states the kind of the link; `href` gives the resource's
address.

```html
<link rel="stylesheet" href="/station.css">
```

There is a fourth way: writing `@import url("…")` inside a style file to pull in another
file. This notation works, but it introduces a sequential dependency: the address of the
imported file cannot be known until the file that calls it has been downloaded and parsed.
This is why an `@import` chain finishes later than the same number of `link` elements
would.

## The External Style Is a Separate Resource

That an external style file is a resource separate from the document is measurable. The
following server serves two addresses separately and logs every request it receives.

```js
// style-server.mjs — serves two resources separately and logs every request received
import { createServer } from "node:http";

const document = `<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>North Slope Measurement Station</title>
<link rel="stylesheet" href="/station.css">
<style>h1 { font-size: 2rem }</style>
</head>
<body>
<h1 style="color: #8a1c1c">North Slope Measurement Station</h1>
</body>
</html>
`;

const style = `body { font-family: system-ui; line-height: 1.5 }
h1 { color: #143a52 }
`;

const server = createServer((request, response) => {
  console.log(`request: ${request.method} ${request.url}`);
  if (request.url === "/station.css") {
    response.writeHead(200, { "content-type": "text/css; charset=utf-8" });
    response.end(style);
  } else {
    response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
    response.end(document);
  }
});

server.listen(8123, "127.0.0.1", () => {
  console.log("listening: 127.0.0.1:8123");
});
```

The server is started in the background and the two addresses are requested separately:

```sh
node style-server.mjs > server.log 2>&1 &
sleep 1
curl -s -o /dev/null -w "%{http_code} %{content_type}\n" http://127.0.0.1:8123/
curl -s -o /dev/null -w "%{http_code} %{content_type}\n" http://127.0.0.1:8123/station.css
cat server.log
```

```
200 text/html; charset=utf-8
200 text/css; charset=utf-8
listening: 127.0.0.1:8123
request: GET /
request: GET /station.css
```

The two lines in the log show that the external style file does not arrive with the
document: a second request is made. This has three consequences.

First, the file is **reusable**. If ten pages attach to the same `station.css` file, the
file is downloaded once; later pages read it from cache. The conditional-request and
time-to-live concepts defined in the How the Internet Works course apply here.

Second, the file **can change independently of the document**. The document's bytes can
stay unchanged while the style is updated, and the reverse is also true.

Third, the second request is a **cost**. The `link` element found while the document is
parsed may require a new connection, and that delays the start of the first render.

## Rendering Does Not Start Until the Style Resolves

The Web Fundamentals and HTML course's resource-loading-order lesson described how
scripts block parsing. A style file does not block parsing — the document tree keeps being
built — but it blocks **rendering**.

The reason becomes visible when looking at what not blocking would cause. If rendering
happened before the style resolved, the page would first render with the default style,
then render again once the file arrived. The user would see two different pages. This is
why the defined behavior is to wait until the style resolves.

This rule produces three practical consequences:

- The style file is attached in the document's **head**. If it is placed at the end of the
  body, rendering still waits, but the wait starts later; the total time grows longer.
- The file is **kept small**; rules unused on a given page delay that page's rendering.
- If a link is only needed under a specific condition, it is conditioned with the `media`
  attribute. A link whose condition is not met still has its file downloaded, but it does
  not block rendering:

```html
<link rel="stylesheet" href="/station.css">
<link rel="stylesheet" href="/print.css" media="print">
```

The second file carries rules written for print output; it does not wait for the start of
screen rendering.

## Comparing the Three Ways

| Criterion | Inline | Internal | External |
|---|---|---|---|
| Selector can be written | No | Yes | Yes |
| Usable across multiple documents | No | No | Yes |
| Separate request | No | No | Yes |
| Cacheable | With the document | With the document | Independently |
| Priority in a conflict | Highest | By source order | By source order |
| Pseudo-class can be written | No | Yes | Yes |

Two rows in the table call for further explanation.

**There is no selector in inline style**, so a pseudo-class cannot be written either. A
declaration that should change when an element is hovered over or focused cannot be
written into the `style` attribute; that requires a rule.

**Inline style has the highest priority.** The specificity calculation covered in a later
section does not cover inline declarations; they sit above the calculation, outside of it.
This makes it effectively impossible to override an inline declaration with a rule through
ordinary means. The result is that inline style is the most expensive way to maintain, and
it is justified only in cases where the value is computed while the document is being
produced.

## Relative Addresses Resolve Against the File Itself

A commonly overlooked consequence of an external style file being a separate resource is
that the relative addresses inside that file resolve not against the document, but against
**the style file's own address**.

Suppose the document is at `/products/station.html` and the style file is at
`/styles/station.css`. If `background-image: url("pattern.png")` is written in the style
file, the address requested is `/styles/pattern.png` — not `/products/pattern.png`. The
same notation written in the document's `style` attribute would resolve against the
document, requesting `/products/pattern.png`.

This distinction is exactly what makes a style file reusable: the file refers to assets
next to it through a fixed path and is unaffected by which document called it. Keeping
image files next to the style file is, for this reason, more than a matter of
organizational preference.

## Attaching the Station Page

The course center uses a single external file. The document's head becomes:

```html
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>North Slope Measurement Station</title>
  <link rel="stylesheet" href="/station.css">
</head>
```

The `station.css` file starts with the previous lesson's three rules and grows through the
course. Attaching to the document from a single point means that changing a rule in later
lessons can be done without touching the document — this is the file-level counterpart of
the structure-presentation distinction.

## Summary

- A set of styles attaches to a document in three ways: an element's `style` attribute
  (inline), a `style` element in the head (internal), and a separate file called with a
  `link` element (external).
- An external style file is a separate HTTP request; it is independently cacheable and
  reusable across multiple documents, but it comes with a request cost.
- A style file does not block parsing, it blocks rendering; this is a behavior defined to
  keep the page from appearing twice, in two different states.
- A link conditioned with the `media` attribute still has its file downloaded, but it does
  not block rendering if its condition is not met.
- Inline style has no selector, so a status style cannot be written with it; its priority
  also sits above the specificity calculation, which makes it hard to override.

## Next Step

Rules now reach the document, but which elements they reach is still limited to a single
example. Writing `h1` selects every top-level heading; what if only the missing values in
the measurement table need to be selected? The next lesson defines the four basic kinds of
selector — type, class, id, and universal — and measures, with a runnable matcher, which
set each one returns from the document tree.
