Styling in Astro
Scoped style blocks, global styles, and why Astro's default scoping avoids CSS collisions.
읽는 데 2분
Astro components can include a <style> tag directly in the template, and by default, those styles are scoped to that component alone — no build-tool configuration, CSS Modules import syntax, or naming convention required.
Scoped styles by default
---
const label = "Scoped Button";
---
<button class="btn">{label}</button>
<style>
.btn {
background: royalblue;
color: white;
padding: 0.5rem 1rem;
border-radius: 6px;
}
</style>Astro rewrites .btn behind the scenes into something like .btn[data-astro-cid-xxxxxx], and adds that same generated attribute to the matching HTML. The practical effect: a .btn class defined in one component can never accidentally leak into or collide with a .btn class defined in another. You get the ergonomics of writing plain, ordinary CSS — no styled.button template literals, no styles.btn object access — with the collision-safety normally associated with CSS Modules.
Opting into global styles
Sometimes you genuinely want a style to apply everywhere — a CSS reset, base typography, design tokens as custom properties. The is:global directive turns off scoping for a specific <style> block:
<style is:global>
:root {
--color-primary: #4f46e5;
--spacing-unit: 8px;
}
body {
margin: 0;
font-family: system-ui, sans-serif;
}
</style>Because global styles bypass Astro's collision protection, it's worth keeping them concentrated in one place — typically a root layout — rather than scattered across individual components, so it stays obvious where site-wide rules live.
Passing dynamic values into CSS
Frontmatter variables can flow into scoped styles through the define:vars directive, which exposes them as CSS custom properties:
---
const accentColor = "#e34c26";
---
<div class="banner">Astro-powered</div>
<style define:vars={{ accentColor }}>
.banner {
border-left: 4px solid var(--accentColor);
padding-left: 1rem;
}
</style>This keeps styling declarative and CSS-native — no inline style="..." string-building — while still letting server-computed values (a theme color from a CMS, say) reach the stylesheet.
Bringing your own tooling
None of this precludes using Tailwind, Sass, or a global stylesheet imported in a layout — Astro supports all of them via integrations or plain <link>/@import. Scoped <style> blocks are simply the built-in option that requires no setup, and they compose well with utility-first CSS: reach for a scoped block when a component needs a handful of rules that are awkward to express as utility classes, and lean on Tailwind (or similar) for everything else.