コンテンツにスキップ

CSSとスタイル

AstroはスタイリングやCSSの記述を簡単にするために設計されました。Astroコンポーネントの内部に直接CSSを記述したり、Tailwindなどのお気に入りのCSSライブラリをインポートできます。SassLessなどの高度なスタイリング言語もサポートされています。

Astroコンポーネントのスタイリングは、コンポーネントまたはページテンプレートに<style>タグを追加するだけで簡単です。Astroコンポーネント内に<style>タグを設置すると、AstroがCSSを検出し、スタイルを自動で処理します。

src/components/MyComponent.astro
<style>
h1 { color: red; }
</style>

Astroの<style>CSSルールは、デフォルトで自動的にスコープされます。スコープされたスタイルは、その同じコンポーネントの内部に書かれたHTMLにのみ適用されるように内部でコンパイルされます。Astroコンポーネント内に記述したCSSは、自動的にそのコンポーネントの中にカプセル化されます。

このCSSは、

src/pages/index.astro
<style>
h1 {
color: red;
}
.text {
color: blue;
}
</style>

このようにコンパイルします。

<style>
h1[data-astro-cid-hhnqfkh6] {
color: red;
}
.text[data-astro-cid-hhnqfkh6] {
color: blue;
}
</style>

スコープされたスタイルはリークしないので、サイトの他の部分に影響を与えることはありません。Astroでは、h1 {}p {}のようなユニークではないセレクタを使用しても問題ありません。なぜなら、最終的な出力ではスコープされてコンパイルされるからです。

また、スコープされたスタイルは、テンプレート内に含まれる他のAstroコンポーネントには適用されません。子コンポーネントにスタイルを設定する必要がある場合、そのコンポーネントを<div>(または他の要素)でラップしてからスタイルを付与するか検討してください。

スコープされたスタイルの詳細度は維持され、他のCSSファイルやCSSライブラリと一緒に一貫して動作でき、スタイルがコンポーネント外に適用されるのを防ぐ境界は維持されます。

ほとんどのコンポーネントではスコープされたスタイルを使うことをおすすめしますが、いずれはグローバルでスコープされていないCSSを書くまっとうな理由が見つかるかもしれません。この場合、<style is:global>属性を使って、CSSの自動的なスコープを無効にできます。

src/components/GlobalStyles.astro
<style is:global>
/* スコープされず、ブラウザにそのまま配信されます。
サイト内のすべての<h1>タグに適用されます。*/
h1 { color: red; }
</style>

また、:global()セレクタを使用すると、同じ<style>タグ内にグローバルなスタイルとスコープ付きのスタイルを混在させられます。これは、コンポーネントの子要素にスタイルを適用するための強力なパターンになります。

src/components/MixedStyles.astro
<style>
/* スコープされ、このコンポーネントに対してのみ適用される。 */
h1 { color: red; }
/* グローバルが混在、子要素の`h1`にのみ適用されます。*/
article :global(h1) {
color: blue;
}
</style>
<h1>Title</h1>
<article><slot /></article>

これは、ブログの投稿や、CMSを使用したドキュメントなど、コンテンツがAstroの外にあるものをスタイルするのに最適な方法です。ただし、特定の親コンポーネントを持つかどうかで外観が異なるコンポーネントは、トラブルシューティングが困難になる可能性があるので注意が必要です。

できるだけスコープされたスタイルを使用してください。グローバルなスタイルは、必要なときだけ使うべきです。

要素上のクラスを動的に組み合わせる必要がある場合、.astroファイルのclass:listユーティリティ属性を使用できます。

src/components/ClassList.astro
---
const { isRed } = Astro.props;
---
<!-- `isRed`がtrueであればclassは"box red"になる -->
<!-- `isRed`がfalseの場合classは"box"になる -->
<div class:list={['box', { red: isRed }]}><slot /></div>
<style>
.box { border: 1px solid blue; }
.red { border-color: red; }
</style>
class:listの詳細については、ディレクティブのリファレンスページを参照してください。

追加: astro@0.21.0

Astroの<style>は、ページ上で利用可能なあらゆるCSS変数を参照できます。また、define:varsディレクティブを使用して、コンポーネントのfrontmatterから直接CSS変数を渡せます。

src/components/DefineVars.astro
---
const foregroundColor = "rgb(221 243 228)";
const backgroundColor = "rgb(24 121 78)";
---
<style define:vars={{ foregroundColor, backgroundColor }}>
h1 {
background-color: var(--backgroundColor);
color: var(--foregroundColor);
}
</style>
<h1>こんにちは</h1>
define:varsについては、ディレクティブのリファレンスのページをご覧ください。

Astroでは、classのようなHTML属性は子コンポーネントには自動で伝わりません。

その代わり、子コンポーネントでclassプロパティを受け取り、それをルート要素に適用します。classはJavaScriptの予約語なので、分割代入を利用して名前を変更する必要があります。

src/components/MyComponent.astro
---
const { class: className } = Astro.props;
---
<div class={className}>
<slot/>
</div>
src/pages/index.astro
---
import MyComponent from "../components/MyComponent.astro"
---
<style>
.red {
color: red;
}
</style>
<MyComponent class="red">This will be red!</MyComponent>

このパターンでは、子コンポーネントに直接スタイルを設定できます。Astroは、親のスコープ付きクラス名(例:astro-hhnqfkh6)をclassプロパティを通して自動的に渡し、その子を親のスコープに含めます。

HTML要素は、style属性を使ってインラインでスタイルを設定できます。これは、CSS文字列またはCSSプロパティのオブジェクトで指定できます。

src/pages/index.astro
// これらは同じです
<p style={{ color: "brown", textDecoration: "underline" }}>テキスト</p>
<p style="color: brown; text-decoration: underline;">テキスト</p>

外部のグローバルなスタイルシートを参照する方法は2つあります。プロジェクトのソース内にあるファイルの場合はESMのインポート、public/ ディレクトリにあるファイルやプロジェクトの外部でホストされているファイルの場合は絶対URLリンクになります。

詳しくはpublic/src/にある静的アセットの使い方をご覧ください。

ESMのインポート構文を使用して、Astroコンポーネントのfrontmatterでスタイルシートをインポートできます。CSSのインポートは、Astroコンポーネント内の他のESMのインポートのように動作し、コンポーネントからの相対パスを、ほかのimportと同様にコンポーネントスクリプトの先頭に記述しなければなりません。

src/pages/index.astro
---
// AstroはこのCSSを自動的にバンドルし、最適化します。
// これは.scssや.stylなどのプリプロセッサーのファイルにも有効です。
import '../styles/utils.css';
---
<html><!-- ページの内容 --></html>

ESMによるCSSのimportは、ReactやPreactのようなJSXコンポーネントを含む、あらゆるJavaScriptファイル内でサポートされています。 これは、Reactコンポーネントに対して、コンポーネント単位できめ細かいスタイルを記述するのに便利です。

npmパッケージからスタイルシートをインポートする

セクションタイトル: npmパッケージからスタイルシートをインポートする

また、外部のnpmパッケージからスタイルシートを読み込む必要がある場合もあります。これは特にOpen Propsのようなユーティリティでよくあることです。パッケージがファイル拡張子の使用を推奨している場合(例:package-name/stylesの代わりに package-name/styles.css )、これは他のローカルスタイルシートと同様に動作するはずです。

src/pages/random-page.astro
---
import 'package-name/styles.css';
---
<html><!-- ページの内容 --></html>

パッケージがファイル拡張子の使用を推奨していない場合(例: package-name/styles)は、まずAstroの設定を更新する必要があります!

package-nameからnormalizeという名前のCSSファイルをインポートしているとします(ファイル拡張子は省略されています)。ページを正しくプリレンダリングするために、package-namevite.ssr.noExternal配列に追加してください。

astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
vite: {
ssr: {
noExternal: ['package-name'],
}
}
})

これで、package-name/normalizeを自由にインポートできるようになりました。これは、他のローカルスタイルシートと同様に、Astroによってバンドルされ、最適化されます。

src/pages/random-page.astro
---
import 'package-name/normalize';
---
<html><!-- ページに内容 --></html>

また、<link>要素を使用して、ページにスタイルシートを読み込めます。これは、/publicディレクトリにあるCSSファイルへの絶対URLパスか、外部のウェブサイトへのURLである必要があります。<link>のhref値を相対パスで指定することはサポートされていません。

src/pages/index.astro
<head>
<!-- ローカル: /public/styles/global.css -->
<link rel="stylesheet" href="/styles/global.css" />
<!-- 外部 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.24.1/themes/prism-tomorrow.css">
</head>

この方法ではpublic/ディレクトリを使用するため、Astro が提供する通常のCSS処理、バンドル、最適化はスキップされます。これらの変換が必要な場合は、上記のローカルスタイルシートのインポートの方法を使用してください。

Astroのコンポーネントは、複数のCSSのソースを評価しなければならないことがあります。たとえば、コンポーネントはCSSスタイルシートをインポートし、それ自身の<style>タグを含み、CSSをインポートするレイアウトの中でレンダリングされるかもしれません。

同じ要素に相反するCSSルールが適用される場合、ブラウザはまず詳細度、次に出現順のルールにしたがって、どちらの値を使って表示するか決定します。

あるルールが他のルールよりも詳細度が高い場合、CSSルールがどこに書かれていても、その値が優先されます。

src/components/MyComponent.astro
<style>
h1 { color: red }
div > h1 {
color: purple
}
</style>
<div>
<h1>
このヘッダーは紫(purple)になります!
</h1>
</div>

2つのルールが同じ詳細度を持つ場合、出現順序が評価され、最後のルールの値が優先されます。

src/components/MyComponent.astro
<style>
h1 { color: purple }
h1 { color: red }
</style>
<div>
<h1>
このヘッダーは赤(red)になります!
</h1>
</div>

Astro CSSのルールは、つぎの出現順で評価されます。

  • head内の<link>タグ (最も低い優先順位)
  • インポートされたスタイル
  • scoped styles (最優先)

スコープされたスタイルを使用しても、CSSの詳細度が高まるわけではありませんが、常に登場順が最後になります。したがって、同じ比重の他のスタイルよりも優先されます。たとえば、スコープされたスタイルと競合するスタイルシートをインポートした場合、スコープされたスタイルの値が適用されます。

src/components/make-it-purple.css
h1 {
color: purple;
}
src/components/MyComponent.astro
---
import "./make-it-purple.css"
---
<style>
h1 { color: red }
</style>
<div>
<h1>
このヘッダーは赤(red)になります!
</h1>
</div>

インポートされたスタイルの詳細度をあげると、スコープされたスタイルより優先されます。

src/components/make-it-purple.css
div > h1 {
color: purple;
}
src/components/MyComponent.astro
---
import "./make-it-purple.css"
---
<style>
h1 { color: red }
</style>
<div>
<h1>
このヘッダーは紫(purple)になります!
</h1>
</div>

Astroコンポーネントで複数のスタイルシートをインポートする場合、CSSルールはインポートされた順番に評価されます。CSSがいつ評価されるかにかかわらず、より高い詳細度によって、表示するスタイルが常に決定されます。しかし、競合するスタイルが同じ比重を持つ場合、最後にインポートされたものが優先されます。

src/components/make-it-purple.css
div > h1 {
color: purple;
}
src/components/make-it-green.css
div > h1 {
color: green;
}
src/components/MyComponent.astro
---
import "./make-it-green.css"
import "./make-it-purple.css"
---
<style>
h1 { color: red }
</style>
<div>
<h1>
このヘッダーは紫(purple)になります!
</h1>
</div>

<style>タグはスコープされ、それを宣言したコンポーネントにのみ適用されますが、インポートしたCSSは「リークする」ことがあります。コンポーネントをインポートすると、そのコンポーネントが使用されない場合でも、インポートしたCSSがすべて適用されます。

src/components/PurpleComponent.astro
---
import "./make-it-purple.css"
---
<div>
<h1>紫のCSSをインポートする</h1>
</div>
src/components/MyComponent.astro
---
import "./make-it-green.css"
import PurpleComponent from "./PurpleComponent.astro";
---
<style>
h1 { color: red }
</style>
<div>
<h1>
このヘッダーは紫(purple)になります!
</h1>
</div>

linkタグで読み込まれたスタイルシートは、Astroファイル内の他のどのスタイルよりも先に、順番に評価されます。したがって、これらのスタイルは、インポートされたスタイルシートやスコープされたスタイルよりも優先順位が低くなります。

src/pages/index.astro
---
import "../components/make-it-purple.css"
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Astro</title>
<link rel="stylesheet" href="/styles/make-it-blue.css" />
</head>
<body>
<div>
<h1>これは紫(purple)になります</h1>
</div>
</body>
</html>

Astroには、Tailwindなど、人気のCSSライブラリやツール、フレームワークをプロジェクトに追加するための仕組みがあります!

プロジェクトでTailwindを使用するには、公式のAstro Tailwindインテグレーションを、パッケージマネージャーのastro addコマンドを使ってインストールします。

Terminal window
npx astro add tailwind
Astroインテグレーションのインストール、インポート、設定の手順については、インテグレーションガイドを参照してください。

Astroは、Viteを通じて、SassStylusLessといったCSSプリプロセッサをサポートしています。

Terminal window
npm install sass

.astroファイルで<style lang="scss">または<style lang="sass">を使用します。

Terminal window
npm install stylus

.astroファイルで<style lang="styl">または<style lang="stylus">を使用します。

Terminal window
npm install less

.astroファイルで<style lang="less">を使用します。

Terminal window
npm install lightningcss

astro.config.mjsファイルでviteの設定を更新します。

astro.config.mjs
import { defineConfig } from 'astro/config'
export default defineConfig({
vite: {
css: {
transformer: "lightningcss",
},
},
})

上記のCSSプリプロセッサは、JSフレームワークの中でも使用できます。ただし、各フレームワークが推奨するパターンに従ってください。

  • React / Preact: import Styles from './styles.module.scss';
  • Vue: <style lang="scss">
  • Svelte: <style lang="scss">

Astroには、Viteの一部としてPostCSSが同梱されています。プロジェクトにPostCSSを設定するには、プロジェクトルートにpostcss.config.cjsファイルを作成します。プラグインはrequire()を使ってインポートできます。

postcss.config.cjs
module.exports = {
plugins: [
require('postcss-preset-env'),
require('autoprefixer'),
],
};

.jsxファイルはグローバルCSSとCSS Modulesの両方をサポートしています。後者を有効にするには、.module.css拡張子を使用します。(Sassを使用している場合は.module.scss/.module.sass)。

import './global.css'; // グローバルCSSを読み込む
import Styles from './styles.module.css'; // CSS Modulesを使う (`.module.css`, `.module.scss`, または`.module.sass`にしなければなりません!)

Astro内のVueは、vue-loaderと同じメソッドをサポートしています。

Astro内のSvelteも期待通りに動作します。Svelte Styling Docs

Astroのスタイル方法は、Markdownレイアウトコンポーネントで利用可能ですが、それぞれの方法には異なったスタイリングへの影響があります。

ページコンテンツを包むレイアウトにインポートしたスタイルシートを追加することで、Markdownコンテンツにグローバルスタイルを適用できます。 また、レイアウトコンポーネントに、<style is:global>タグがついたMarkdownでスタイルを追加することも可能です。追加されたスタイルは、アストロのカスケード順序 に沿っていることを確認し、スタイルが意図した通りに適用されているか慎重にチェックしてください。

加えて、Tailwindを含むCSSのインテグレーションの追加もできます。 Tailwindを使用している場合、Markdownのスタイリングにはtypographyプラグインが便利です。

Astroが本番環境向けにサイトをビルドする際、CSSはミニファイされチャンクへと結合されます。サイト上の各ページはそれぞれ独自のチャンクを取得し、さらに複数のページ間で共有されるCSSは、再利用のために独自のチャンクに分割されます。

しかし、複数のページでスタイルを共有している場合、共有される一部のチャンクが非常に小さくなる場合があります。それらがすべて別々に送信された場合、スタイルシートへのリクエストが増加し、サイトのパフォーマンスに影響を与える可能性があります。そのため、Astroはデフォルトでは、HTML内の4kB以上のスタイルシートのみを<link rel="stylesheet">タグとしてリンクし、それ以外のものは<style type="text/css">にインライン化します。このアプローチにより、追加のリクエストの数と、ページ間でキャッシュされるCSSの量のあいだのバランスをとることができます。

ViteのassetsInlineLimitビルドオプションを使用して、スタイルシートが外部にリンクされるサイズをバイト単位で設定できます。このオプションは、スクリプトと画像のインライン化にも影響することに注意してください。

astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
vite: {
build: {
assetsInlineLimit: 1024,
}
};
});

すべてのスタイルシートを外部リンクとしたい場合は、inlineStylesheetsビルドオプションを設定します。

astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
build: {
inlineStylesheets: 'never'
}
});

このオプションを'always'に設定すると、すべてのスタイルシートがインライン化されます。

高度なユースケースでは、Astroによってバンドルまたは最適化されることなく、CSSをsrcディレクトリ内から直接読み込めます。これは、CSSのスニペットを完全に制御する必要がある場合や、Astroの自動CSS処理をバイパスする必要がある場合に便利です。

これはほとんどユーザーにおすすめされません。

---
// 高度な例! ほとんどのユーザーにおすすめされません。
import rawStylesCSS from '../styles/main.css?raw';
---
<style is:inline set:html={rawStylesCSS}></style>

詳しくはViteのドキュメントをご覧ください。

高度な使い方をする場合、プロジェクトのsrc/ディレクトリ内にあるCSSファイルを直接のURL参照でインポートできます。これは、CSSファイルがどのようにページに読み込まれるかを完全に制御する必要がある場合に便利です。しかし、この場合、そのCSSファイルをページの残りのCSSと一緒に最適化することはできません。

これはほとんどのユーザーにはおすすめできません。代わりに、CSSファイルをpublic/内に配置し、一貫したURLの参照を得られるようにしましょう。

---
// 高度な例! ほとんどのユーザーにおすすめされません。
import stylesUrl from '../styles/main.css?url';
---
<link rel="preload" href={stylesUrl} as="style">
<link rel="stylesheet" href={stylesUrl}>

詳しくはViteのドキュメントをご覧ください。