# đ
Styling
Styling in Astro is meant to be as flexible as youâd like it to be! The following options are all supported:
| Framework | Global CSS | Scoped CSS | CSS Modules |
| :--------------- | :--------: | :--------: | :---------: |
| `.astro` | â
| â
| N/Aš |
| `.jsx` \| `.tsx` | â
| â | â
|
| `.vue` | â
| â
| â
|
| `.svelte` | â
| â
| â |
š _`.astro` files have no runtime, therefore Scoped CSS takes the place of CSS Modules (styles are still scoped to components, but donât need dynamic values)_
All styles in Astro are automatically [**autoprefixed**](#-autoprefixer) and optimized, so you can just write CSS and weâll handle the rest â¨.
## đ Quick Start
Styling in an Astro component is done by adding a `
Iâm a scoped style and only apply to this component
I have both scoped and global styles
```
**Tips**
- `
```
_Note: all the examples here use `lang="scss"` which is a great convenience for nesting, and sharing [colors and variables][sass-use], but itâs entirely optional and you may use normal CSS if you wish._
That `.btn` class is scoped within that component, and wonât leak out. It means that you can **focus on styling and not naming.** Local-first approach fits in very well with Astroâs ESM-powered design, favoring encapsulation and reusability over global scope. While this is a simple example, it should be noted that **this scales incredibly well.** And if you need to share common values between components, [Sassâ module system][sass-use] also gets our recommendation for being easy to use, and a great fit with component-first design.
---
By contrast, Astro does allow global styles via the `:global()` escape hatch, however, this should be avoided if possible. To illustrate this: say you used your button in a ` ` component, and you wanted to style it differently there. You might be tempted to have something like:
```jsx
---
// src/components/Nav.astro
import Button from './Button.astro';
---
Menu
```
This is undesirable because now `` and `` fight over what the final button looks like. Now, whenever you edit one, youâll always have to edit the other, and they are no longer truly isolated as they once were (now coupled by a bidirectional styling dependency). Itâs easy to see how this pattern only has to repeated a couple times before being afraid that touching any styles _anywhere_ may break styling in a completely different part of the app (queue `peter-griffin-css-blinds.gif`).
Instead, let `` control its own styles, and try a prop:
```jsx
---
// src/components/Button.astro
const { theme } = Astro.props;
---
```
Elsewhere, you can use `` to set the type of button it is. This preserves the contract of _Button is in charge of its styles, and Nav is in charge of its styles_, and now you can edit one without affecting the other. The worst case scenario of using global styles is that the component is broken and unusable (itâs missing part of its core styles). But the worst case scenario of using props (e.g. typo) is that a component will only fall back to its default, but still usable, state.
đ **Why this works well in Astro**: Astro is inspired most by JavaScript modules: you only need to know about whatâs in one file at a time, and you never have to worry about something in a remote file affecting how this code runs. But weâre not alone in this; Vue and Svelte have both capitalized on and popularized the idea that styles and markup are natural fits in the same component file. [You can still have separation of concerns][peace-on-css] even with markup, styling, and logic contained in one file. In fact, thatâs what makes component design so powerful! So write CSS without fear that you picked a name thatâs used by some other component across your app.
#### Utility CSS
Recently there has been a debate of all-scoped component styles vs utility-only CSS. But we agree with people like Sarah Dayan who ask [why canât we have both][utility-css]? Truth is that while having scoped component styles are great, there are still hundreds of times when the websiteâs coming together when two components just donât line up _quite_ right, and one needs a nudge. Or different text treatment is needed in one component instance.
While the thought of having perfect, pristine components is nice, itâs unrealistic. No design system is absoutely perfect, and every design system has inconsistencies. And itâs in reconciling these inconsistencies where components can become a mess without utility CSS. Utility CSS is great for adding minor tweaks necessary to get the website out the door. But they also are incomplete on their ownâif youâve ever tried to manage responsive styles or accessible focus states with utility CSS it can quickly become a mess! **Utility CSS works best in partnership with component (scoped) CSS**. And in order to be as easy as possible to use, Utility CSS should be global (arguably should be your only global CSS, besides maybe reset.css) so you donât have to deal with imports all willy-nilly.
Some great problems best handled with Utility CSS are:
- [margin](https://github.com/drwpow/sass-utils#-margin--padding)
- [padding](https://github.com/drwpow/sass-utils#-margin--padding)
- [text/background color](https://github.com/drwpow/sass-utils#-color)
- [font size and family](https://github.com/drwpow/sass-utils#%F0%9F%85%B0%EF%B8%8F-font--text)
- [default element styling](https://github.com/kognise/water.css)
In Astro, we recommend the following setup for this:
```html
```
And in your local filesystem, you can even use Sassâ [@use][sass-use] to combine files together effortlessly:
```
âââ public/
â âââ styles/
â âââ _base.scss
â âââ _tokens.scss
â âââ _typography.scss
â âââ _utils.scss
â âââ global.scss
âââ src/
âââ (pages)
```
Whatâs in each file is up to you to determine, but start small, add utilities as you need them, and youâll keep your CSS weight incredibly low. And utilities you wrote to meet your real needs will always be better than anything off the shelf.
So to recap, think of scoped styles as the backbone of your styles that get you 80% of the way there, and utility CSS filling in the remaining 20%. They both work well in tandem, with each compensating for the otherâs weakness.
đ **Why this works well in Astro**: Astro was built around the idea of **Scoped CSS and Global Utility CSS living together in harmony** âĽď¸! Take full advantage of it.
### More suggestions
âBut wait!â you may ask, having read the previous section. âThat doesnât take care of [my usecase]!â If youâre looking for more pointers on some common styling problems, you may be interested in the following suggestions. These all are cohesive, and fit with the **Hybrid Scoped + Utility** philosphy:
1. Split your app into Layout Components and Base Components
1. Avoid Flexbox and Grid libraries (write your own!)
1. Avoid `margin` on a component wrapper
1. Avoid global media queries
#### Suggestion #1: Split your app into Layout Components and Base Components
While this guide will never be long enough to answer the question _âHow should a page be laid out?â_ (thatâs a [design problem!][cassie-evans-css]) there is a more specific question hiding within that we _can_ answer: _âGiven a layout, how should components/styles be organized?â_ The answer is **donât bake layout into components.** Have layout components that control layout, and base components (buttons, cards, etc.) that donât control layout. _What does that mean?_ Letâs walk through an example so itâs more clear. Pretend we have a page that looks like this (numbers for different components):
```
|---------------|
| 1 |
|-------+-------|
| 2 | 2 |
|---+---|---+---|
| 3 | 3 | 3 | 3 |
|---+---+---+---|
| 3 | 3 | 3 | 3 |
|---+---+---+---|
```
The layout consists of a big, giant, full-width post at top, followed by two half-width posts below it. And below that, we want a bunch of smaller posts to fill out the rest of the page. For simplicity, weâll just call these `` (1), `` (2), and `` (3). We add them to our page like so:
```jsx
---
// src/pages/index.astro
import Nav from '../components/Nav.astro';
import BigPost from '../components/BigPost.astro';
import Grid from '../components/Grid.astro';
import MediumPosts from '../components/MediumPosts.astro';
import SmallPosts from '../components/SmallPosts.astro';
import Footer from '../components/Footer.astro';
---
```
This _looks_ clean, but looks can be deceiving. At first glance, we may think that `` is controlling the layout, but thatâs an illusion. We actually have `` handling its own width, `` loading 2 components and controlling its width, and `` loading 4+ components and controlling its width. In total, including ``, that means **4 components** are all fighting over the same layout. Remove one post from ``, the layout breaks. Edit ``, the layout breaks. Edit ``, the layout breaks. If you think about it, none of these components are truly reusableâthey might as well just be one big file.
This is actually the **Global CSS Problem** in disguiseâmultiple components fight over how they all lay out together, without layout being one, central responsibility (kinda like global CSS)! Now that we identified the problem, one way to fix this is to hoist the entire layout to the top level, and load all components there, too:
```jsx
---
// src/pages/index.astro
import Nav from '../components/Nav.astro';
import BigPost from '../components/BigPost.astro';
import MediumPost from '../components/MediumPost.astro';
import SmallPost from '../components/SmallPost.astro';
import Footer from '../components/Footer.astro';
---
```
Getting over that this is more code, itâs actually a much cleaner separation. What was a four-component layout is now managed 100% within the top-level `index.astro` (which we can now consider a **Layout Component**, and if we wanted to reuse this we could extract this into its own file). Your layout is centralized, and now these components truly are reusable because they donât care one bit about whether theyâre in the same grid or not. You can edit styles in any of these files now without fear of styles breaking in another.
The basic rule is that when orchestrating multiple components, **thatâs a unique responsibility** that should live in one central place, rather than split between 4 components as we were doing. In fact, top-level pages are great at this, and should always be the starting point of your layout components. See how far you can take it, and only extract layout components when you absolutely have to.
To recap: **if you have to touch multiple files to manage one layout, you probably need to reorganize everything into a Layout Component.**
đ **Why this works well in Astro**: In Astro, anything can be a `.astro` component, and you never incur performance problems no matter how many components you add. But the main benefit to [Layout isolation][layout-isolated] is how much it cuts down on the amount of CSS you need.
#### Suggestion #2: Avoid Flexbox and Grid libraries (write your own!)
This may feel like a complete overreach to tell you not to use your favorite layout framework youâre familiar with. After all, itâs gotten you this far! But the days of [float madness](https://zellwk.com/blog/responsive-grid-system/) are gone, replaced by Flexbox and Grid. And the latter donât need libraries to manage them (often they can make it harder).
Many front-end developers experience the following train of thought:
1. I should reuse as much CSS as possible (_good!_)
2. Many pages reuse the same layout, ⌠(_hold upâ_)
3. ⌠therefore I can find an existing solution to manage all my duplicate layouts (_wait a minuteâ_)
While the logic is sound, the reality is that #2 isnât truth for many projects. Probably, many parts of the website werenât designed to fit into these nice, neat, 12 column grids. Even modest web apps can contain _hundreds_ of unique layouts when you factor in all the breakpoints. Ask yourself: _If the website Iâm building really contains so many unique layouts, why am I using a heavy grid library that only gives me generic layouts?_
A few well-written lines of CSS Grid here and there will not only be perfect in every occasion; itâs likely lighter and easier to manage than that heavy library youâve fought with for so long. Another way to look at it: if you have to spend a couple hours learning a proprietary styling framework, wrestling with it, filing issues, etc., why not just spend that time on Flexbox and Grid instead? For many people, learning the basics only takes an hour, and that can get you pretty far! There are great, free, learning resources that are worth your time:
- [Flexbox Froggy](https://flexboxfroggy.com/)
- [CSS Grid Garden](https://cssgridgarden.com/)
So in short: stop trying to deduplicate layouts when thereâs nothing to deduplicate! Youâll find your styles not only easier to manage, but your CSS payloads much lighter, and load times faster.
đ **Why this works well in Astro**: grid libraries are a quick path to stylesheet bloat, and a major contributor to people attempting to [treeshake their styles][css-treeshaking]. Astro does **not** treeshake unused CSS for you, because [that can cause problems][css-treeshaking]. Weâre not saying you have to be library free; weâre big fans of libraries like [Material UI][material-ui]. But if you can at least shed the thousands upon thousands of layouts youâre not using from your styling library, you probably donât need automatic treeshaking.
#### Suggestion #3: Avoid `margin` on a component wrapper
In other words, donât do this:
```jsx
```
If you remember the [CSS box model][box-model], `margin` extends beyond the boundaries of the box. This means that when you place `margin` on the outermost element, now that will push other components next to it. Even though the styles are scoped, itâs _technically_ affecting elements around it, so it [breaks the concept of style containment][layout-isolated].
When you have components that rearrage, or appear different when theyâre next to other components, thatâs a hard battle to win. **Components should look and act the same no matter where they are placed.** Thatâs what makes them components!
đ **Why this works well in Astro**: margins pushing other components around creeps into your styling architecture in sneaky ways, and can result in the creation of some wonky or brittle layout components. Avoiding it altogether will keep your layout components simpler, and youâll spend less time styling in general.
#### Suggestion #4: Avoid global media queries
The final point is a natural boundary of **Scoped Styles**. That extends to breakpoints, too! You know that one, weird breakpoint where your ` ` component wraps awkardly at a certain size? You should handle that within ` `, and not anywhere else.
Even if you end up with some random value like `@media (min-width: 732px) {`, thatâll probably work better than trying to create a global [magic number][magic-number] somewhere that only applies to one context (an arbitrary value may be âmagicâ to the rest of an app, but it does still have meaning within the context of a component that needs that specific value).
Granted, this has been near-impossible to achieve until Container Queries; fortunately [they are finally landing!][container-queries]
Also, a common complaint of this approach is when someone asks _âWhat if I have 2 components that need to do the same thing at the same breakpoint?â_ to which my answer is: youâll always have one or two of those; just handle those as edge cases. But if your entire app is made up of dozens of these cases, perhaps your component lines could be redrawn so that theyâre more [layout-isolated][layout-isolated] in general.
đ **Why this works well in Astro**: this is probably the least important point, which is why itâs saved for last. In fact, you could probably skip this if it doesnât work for you. But itâs something that people try to architect for at scale, and having a global system to manage this can often be unnecessary. Give _not_ architecting for global media queries a try, and see how far it takes you!
### đ Further Reading
This guide wouldnât be possible without the following blog posts, which expand on these topics and explain them in more detail. Please give them a read!
- [**Layout-isolated Components**][layout-isolated] by Emil SjĂślander
- [**In defense of utility-first CSS**][utility-css] by Sarah Dayan
Also please check out the [Stylelint][stylelint] project to whip your styles into shape. You lint your JS, why not your CSS?
[astro-syntax]: ./syntax.md
[autoprefixer]: https://github.com/postcss/autoprefixer
[bem]: http://getbem.com/introduction/
[box-model]: https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/The_box_model
[browserslist]: https://github.com/browserslist/browserslist
[browserslist-defaults]: https://github.com/browserslist/browserslist#queries
[cassie-evans-css]: https://twitter.com/cassiecodes/status/1392756828786790400?s=20
[container-queries]: https://ishadeed.com/article/say-hello-to-css-container-queries/
[css-modules]: https://github.com/css-modules/css-modules
[css-treeshaking]: https://css-tricks.com/how-do-you-remove-unused-css-from-a-site/
[fouc]: https://en.wikipedia.org/wiki/Flash_of_unstyled_content
[layout-isolated]: https://visly.app/blogposts/layout-isolated-components
[issues]: https://github.com/snowpackjs/astro/issues
[magic-number]: https://css-tricks.com/magic-numbers-in-css/
[material-ui]: https://material.io/components
[peace-on-css]: https://didoo.medium.com/let-there-be-peace-on-css-8b26829f1be0
[sass]: https://sass-lang.com/
[sass-use]: https://sass-lang.com/documentation/at-rules/use
[smacss]: http://smacss.com/
[styled-components]: https://styled-components.com/
[styled-jsx]: https://github.com/vercel/styled-jsx
[stylelint]: https://stylelint.io/
[svelte-style]: https://svelte.dev/docs#style
[tailwind]: https://tailwindcss.com
[tailwind-utilities]: https://tailwindcss.com/docs/adding-new-utilities#using-css
[utility-css]: https://frontstuff.io/in-defense-of-utility-first-css
[vue-css-modules]: https://vue-loader.vuejs.org/guide/css-modules.html
[vue-scoped]: https://vue-loader.vuejs.org/guide/scoped-css.html