Markdown source

Astro Styling Markdown source

Readable source view for humans. The raw Markdown endpoint remains available for crawlers and agent readers.

---
title: "Astro Styling"
description: "Scoped CSS, global styles, design tokens, and how Catppuccin theming works."
kind: guide
maturity: evergreen
confidence: high
origin: ai-drafted
author: "Agent"
directedBy: "krow"
tags: [astro, fundamentals]
published: 2026-03-15
modified: 2026-06-13
wordCount: 745
readingTime: 4
series: "learn-astro"
series_order: 7
prerequisites: [astro-components]
url: https://krowdev.com/guide/astro-styling/
---
## Agent Context

- Canonical: https://krowdev.com/guide/astro-styling/
- Markdown: https://krowdev.com/guide/astro-styling.md
- Full corpus: https://krowdev.com/llms-full.txt
- Kind: guide
- Maturity: evergreen
- Confidence: high
- Origin: ai-drafted
- Author: Agent
- Directed by: krow
- Published: 2026-03-15
- Modified: 2026-06-13
- Words: 745 (4 min read)
- Tags: astro, fundamentals
- Series: learn-astro (#7)
- Prerequisites: astro-components
- Content map:
  - h2: Three Levels of CSS in Astro
  - h2: Scoped Styles (Default)
  - h2: Global Styles
  - h2: CSS Custom Properties (Design Tokens)
  - h2: How the Theme Toggle Works
  - h2: Semantic Token Pattern
  - h2: Fonts
  - h2: Sources
- Crawl policy: same canonical content is exposed through HTML, Markdown, and llms-full; no crawler-specific content gate.

## Three Levels of CSS in Astro

This assumes you understand [components](/guide/astro-components/). For the design-token philosophy see the [mental model](/guide/astro-mental-model/). Companion entries: [.astro files](/guide/astro-files/) and [layouts](/guide/astro-layouts/) — the surfaces where styles get scoped.

| Level | Scope | Where | When to Use |
|---|---|---|---|
| **Scoped** | One component | `<style>` in `.astro` file | Component-specific styles |
| **Global** | Entire site | Imported `.css` file | Design tokens, typography, resets |
| **Inline** | One element | `style=""` attribute | Rare, dynamic values |

## Scoped Styles (Default)

A `<style>` tag in an `.astro` file is automatically scoped:

```astro
<!-- Component A -->
<h1>Title A</h1>
<style>
  h1 { color: red; }  /* Only affects THIS h1 */
</style>

<!-- Component B -->
<h1>Title B</h1>
<style>
  h1 { color: blue; }  /* Only affects THIS h1 */
</style>
```

No conflicts. Astro adds data attributes behind the scenes to isolate selectors. You write simple CSS, Astro handles namespacing.

## Global Styles

For site-wide styles (fonts, colors, resets), import a CSS file in a layout:

```astro
---
// src/layouts/Base.astro
import '../styles/global.css';  // applies to every page
---
```

krowdev's `global.css` contains:
1. **CSS custom properties** (design tokens) — Catppuccin color values
2. **Reset** — box-sizing, margins
3. **Typography** — heading sizes, paragraph max-width, link styles
4. **Code blocks** — syntax highlighting integration
5. **Tables** — border, padding, hover states
6. **Interactive elements** — callout boxes, challenge blocks (used in this course)

## CSS Custom Properties (Design Tokens)

Custom properties are variables that CSS can reference. krowdev uses them for theming:

```css
[data-theme='dark'] {
  --bg: #1e1e2e;          /* Catppuccin Mocha base */
  --text: #cdd6f4;         /* Catppuccin Mocha text */
  --accent: #cba6f7;       /* Catppuccin Mocha mauve */
}

[data-theme='light'] {
  --bg: #eff1f5;           /* Catppuccin Latte base */
  --text: #4c4f69;         /* Catppuccin Latte text */
  --accent: #8839ef;       /* Catppuccin Latte mauve */
}
```

Then everything references these variables:

```css
body { background: var(--bg); color: var(--text); }
a { color: var(--accent); }
```

:::analogy
CSS custom properties are like constants in a Python config file:

```python
# config.py
BG_COLOR = "#1e1e2e"
TEXT_COLOR = "#cdd6f4"
ACCENT_COLOR = "#cba6f7"

# usage.py
from config import BG_COLOR
set_background(BG_COLOR)
```

Change the config, everything updates. Same idea — change `--accent` and every link, button, and highlight changes.
:::

## How the Theme Toggle Works

The toggle script (in `ThemeToggle.astro`) does one thing:

```js
// Toggle data-theme attribute on <html>
const next = current === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', next);
localStorage.setItem('theme', next);
```

The CSS selector `[data-theme='dark']` or `[data-theme='light']` activates the right set of variables. Everything repaints instantly — no page reload.

:::key
The theme toggle is the *only* JavaScript on the site. Everything else — fonts, colors, layout — is pure CSS. The `is:inline` script in `Base.astro`'s `<head>` sets the theme before first paint to prevent a flash of wrong colors.
:::

## Semantic Token Pattern

krowdev uses a two-layer token system:

```
Layer 1: Raw palette         Layer 2: Semantic aliases
--ctp-base: #1e1e2e    →    --bg: var(--ctp-base)
--ctp-mauve: #cba6f7   →    --accent: var(--ctp-mauve)
--ctp-blue: #89b4fa    →    --link: var(--ctp-blue)
```

Why two layers? If you later want `--accent` to be blue instead of mauve, you change one line. Everything using `--accent` updates. The raw palette stays stable.

## Fonts

Astro 6's Fonts API downloads fonts at build time and creates CSS variables:

```js
// astro.config.mjs
fonts: [
  {
    name: 'Inter',
    cssVariable: '--font-body',       // use this in CSS
    provider: fontProviders.fontsource(),
    weights: [400, 500, 600, 700],
  },
]
```

Then in CSS:
```css
html { font-family: var(--font-body), system-ui, sans-serif; }
code { font-family: var(--font-mono), monospace; }
```

:::analogy
`fontsource` is like `conda install` for fonts. The files are downloaded at build time, bundled into your `dist/`, and served locally. No runtime dependency on Google's CDN. GDPR-friendly.
:::

**Challenge: Change the accent color**

1. Open `src/styles/global.css`
2. Find the line `--accent: var(--ctp-mauve);`
3. Change it to `--accent: var(--ctp-blue);`
4. Run `npm run dev` and see every accent (links, buttons, highlights, badges) turn blue
5. Change it back to mauve when you're done

This demonstrates the power of the token system — one variable controls the entire color story.

---
Previous: [Content Collections](/guide/astro-content-collections/) | Next: [Markdown & Code Blocks](/guide/astro-markdown-and-code/)

## Sources

- Astro Docs, [Styles and CSS](https://docs.astro.build/en/guides/styling/)
- MDN, [CSS custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties)
- Catppuccin, [Palette spec](https://github.com/catppuccin/catppuccin/blob/main/docs/style-guide.md)