プロフィール

arismmn timeline blog

← ブログ一覧に戻る

AstroでMarkdownから生成したHTMLにCSSが適用されない時の解決法

AstroCSSトラブルシューティング

📝 はじめに

Astroブログを構築していて、Markdownから生成されたテーブルやリストに「スタイルが全く適用されない!」という経験はありませんか?

私も今日、ブログ記事のテーブルにベージュのグラデーション背景やホバーエフェクトを適用しようとしたところ、何度CSSを書き直してもまったく反映されず、半日格闘することになりました。

この記事では、その原因と解決方法を共有します。

🔍 問題の症状

環境

  • フレームワーク: Astro 5.x
  • コンテンツ: Markdown (Content Collections)
  • ページ: 動的ルーティング [slug].astro

起きた問題

---
// src/pages/blog/[slug].astro
const { Content } = await post.render();
---

<style>
  .article-content table {
    background: #f5e8d8;
    border-collapse: collapse;
    /* ... 他にもたくさんスタイルを書いた */
  }
</style>

<div class="article-content">
  <Content />
</div>

このように書いても、ブラウザのデフォルトスタイルしか適用されない状態でした。

開発者ツールで確認すると:

  • border-collapse: separate (デフォルト値のまま)
  • 背景色も反映されていない
  • !importantを付けても効果なし

🤔 原因: Astroのスタイルスコープ

Astroのスコープ機能とは

Astroは、<style>タグ内に書いたCSSを自動的にスコープ化します。具体的には:

  1. コンポーネント内の各要素に data-astro-cid-xxxxx のような属性を付与
  2. CSSセレクタにも同じ属性を追加して、そのコンポーネント専用のスタイルにする

例:

<style>
  .article-content table { /* ... */ }
</style>

↓ ビルド時に変換される ↓

<style>
  .article-content[data-astro-cid-4on4a3jr] table[data-astro-cid-4on4a3jr] { /* ... */ }
</style>

なぜMarkdown由来のHTMLには効かないのか

Markdownから生成されたHTML<Content />コンポーネントの出力)には、スコープ属性が付きません

<!-- 実際の出力 -->
<div class="article-content" data-astro-cid-4on4a3jr>
  <table>  <!-- ← スコープ属性がない! -->
    <thead>
      <tr>
        <th>通信の方向</th>
        ...

そのため、以下のセレクタは:

.article-content[data-astro-cid-4on4a3jr] table[data-astro-cid-4on4a3jr]

この<table>にはマッチしないのです。

✅ 解決方法: is:globalを使う

シンプルな修正

- <style>
+ <style is:global>
    .article-content table {
      background: #f5e8d8;
      border-collapse: collapse;
    }
  </style>

たった1行の変更です!

is:globalの効果

is:global属性を付けると、そのスタイルはグローバルスコープになります。つまり:

  • スコープ属性が付与されない
  • Markdown生成要素にも適用される
  • 他のページには影響しない(そのページ内でのみ有効)

🎨 実装例: テーブルスタイリング

私が実際に適用したテーブルスタイルの例です:

<style is:global>
  :root {
    --color-primary: #d4a574;
    --color-border: #e8dfd5;
    --color-shadow: rgba(0, 0, 0, 0.08);
  }

  /* テーブル全体 */
  .article-content table {
    width: 100% !important;
    border-collapse: collapse !important;
    margin: 30px 0 !important;
    background: white !important;
    border-radius: 8px !important;
    overflow: hidden !important;
    box-shadow: 0 2px 8px var(--color-shadow) !important;
    border: 1px solid var(--color-border) !important;
  }

  /* ヘッダー行 */
  .article-content thead {
    background: linear-gradient(135deg, #f5e8d8 0%, #efe4d5 100%) !important;
  }

  .article-content th {
    padding: 16px 20px !important;
    text-align: left !important;
    font-weight: 700 !important;
    color: #4a4a4a !important;
    border-bottom: 2px solid var(--color-primary) !important;
    font-size: 0.95rem !important;
  }

  /* データセル */
  .article-content td {
    padding: 14px 20px !important;
    border-bottom: 1px solid var(--color-border) !important;
    color: #4a4a4a !important;
    font-size: 0.95rem !important;
    background: white !important;
  }

  /* ホバーエフェクト */
  .article-content tbody tr:hover td {
    background: #faf8f5 !important;
  }

  /* 最後の行は下線なし */
  .article-content tbody tr:last-child td {
    border-bottom: none !important;
  }
</style>

!importantを使った理由

is:globalにしても、ブラウザのデフォルトスタイルが優先されるケースがあったため、確実に適用させるために!importantを使用しました。

🔍 トラブルシューティングのプロセス

今回の問題解決までの流れを共有します。

1. 最初の仮説: セレクタが間違っている?

/* 詳細度を上げてみた */
.article-content table { }          /* 効かない */
div.article-content table { }       /* 効かない */
.article > .article-content table { /* 効かない */
}

結果: すべて効果なし

2. 次の仮説: CSSの読み込みタイミング?

開発サーバーを再起動してみましたが、変化なし。

3. ブラウザの開発者ツールで確認

Elementsタブ:

<div class="article-content" data-astro-cid-4on4a3jr>
  <table>  <!-- ← 属性が付いていない! -->

Stylesタブ:

  • 自分が書いたCSSルールが見当たらない
  • border-collapse: separate (デフォルト値)

気づき: テーブルにスコープ属性が付いていない

4. Astroのドキュメントを確認

Astro公式ドキュメント - Scoped Styles

Astro's scoped styles are implemented by adding a data-astro-* attribute to styled elements. However, content rendered by framework components or Content Collections may not receive this attribute.

つまり、Content Collectionsの出力には属性が付かない!

5. is:globalで解決

ドキュメントに書いてあった通り、<style is:global>に変更したところ、即座に解決しました。

💡 is:global を使う時の注意点

1. グローバル汚染のリスク

is:globalを使うと、そのページ以外にも影響する可能性があります。

対策: クラス名を具体的にする

/* ❌ 他のページにも影響する可能性 */
table { }

/* ✅ 特定のコンテキストに限定 */
.article-content table { }
.blog-post-table { }

2. 詳細度のコントロール

グローバルスコープでは、他のCSSとの競合が発生しやすくなります。

対策: 必要に応じて!importantを使う

.article-content table {
  border-collapse: collapse !important;
}

3. レスポンシブ対応も忘れずに

@media (max-width: 768px) {
  .article-content table {
    display: block;
    overflow-x: auto;
    white-space: nowrap;
  }
}

🆚 他の解決方法との比較

方法1: インラインスタイル

<div style="background: #f5e8d8;">
  <Content />
</div>
  • ❌ Content内部の要素にはアクセスできない
  • ❌ 保守性が低い

方法2: グローバルCSS

// src/styles/global.css
table { /* ... */ }
  • ❌ プロジェクト全体に影響する
  • ❌ 他のテーブルと競合する可能性

方法3: is:global ✅ 推奨

<style is:global>
  .article-content table { /* ... */ }
</style>
  • ✅ ページ単位でスコープ可能
  • ✅ Markdown生成要素にも適用される
  • ✅ 保守性が高い

📊 ビフォー・アフター

実際のテーブルで比較してみましょう。

Before: スタイルが適用されていない状態

通信の方向 必要な認証情報 用途
🚀 Slackへ送信 SLACK_BOT_TOKEN Slack API呼び出し認証
🔒 Slackから受信 SLACK_SIGNING_SECRET リクエスト署名検証

問題点:

  • ❌ 背景色がない(白のまま)
  • ❌ 境界線が太くて野暮ったい(border-collapse: separate
  • ❌ パディングが狭くて窮屈
  • ❌ ヘッダー行と通常行の区別がつきにくい
  • ❌ ホバー時の反応なし
  • ❌ ブランドカラーとの統一感なし

After: is:globalでカスタムスタイル適用

通信の方向 必要な認証情報 用途
🚀 Slackへ送信 SLACK_BOT_TOKEN Slack API呼び出し認証
🔒 Slackから受信 SLACK_SIGNING_SECRET リクエスト署名検証

改善点:

  • ✅ ヘッダー行: ベージュ (#f5e8d8 → #efe4d5) のグラデーション背景
  • ✅ 境界線: 1px solid #e8dfd5 の繊細なライン + border-collapse: collapse
  • ✅ パディング: 上下14-16px、左右20pxでゆったり
  • ✅ 影効果: box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08)
  • ✅ 角丸: border-radius: 8px
  • ✅ ホバー: マウスを乗せると行の背景が #faf8f5 に変化(試してみてください!)
  • ✅ ヘッダー下線: 2px solid #d4a574 で強調

一目瞭然ですね!<style is:global>を追加するだけで、ブラウザのデフォルトスタイルからブランドカラーに統一された美しいテーブルに変わります。

🎓 まとめ

覚えておくべき3つのポイント

  1. Astroはデフォルトでスタイルをスコープ化する

    • data-astro-cid-xxxxx属性を使用
  2. Markdown生成HTMLにはスコープ属性が付かない

    • <Content />の出力要素には属性なし
  3. is:globalで解決できる

    • グローバルスコープになるため、Markdown要素にも適用される

いつis:globalを使うべきか

  • ✅ Content CollectionsのMarkdown/MDXをスタイリングする時
  • ✅ 外部ライブラリが生成するHTMLをスタイリングする時
  • ✅ 動的に生成される要素をスタイリングする時

いつ使わないべきか

  • ❌ 通常のAstroコンポーネント内の要素(スコープスタイルで十分)
  • ❌ プロジェクト全体で使いたいスタイル(グローバルCSSを使う)

🔗 参考リンク


関連記事:

更新履歴:

  • 2026-02-21: 初版作成
Gemini
Powered by
Gemini
← ブログ一覧に戻る