本記事の対象読者と前提
本記事は、Headless CMS、Webメディア、記事本文表示、コンテンツ設計に関心を持つ
実務者や技術者を対象としている。
ただし、本記事はmicroCMSやAstroの実装手順を解説するものではない。
語り部の座の開発過程で生まれた Semantic Rendering Engine という考え方について、
その背景、目的、設計思想を整理することを目的としている。
本記事で述べる Semantic Rendering Engine は、特定のライブラリ名や一般的な業界標準用語ではない。
語り部の座における記事本文レンダリングの課題から生まれた、DataLiner独自の設計概念である。
はじめに
語り部の座を開発する上で、最も大きな課題の一つが記事本文の表現だった。
microCMS の Rich Editor は、記事本文を柔軟に入力できる。
見出し、段落、リスト、引用、画像、リンク、コードブロック。
記事を書くために必要な基本的な表現は十分に揃っている。
しかし、Rich Editor の入力内容がそのまま画面に表示されるわけではない。
実際にフロントエンドへ渡されるのは、HTMLとして表現された DOM 構造である。
この DOM 構造を、どのように画面上の表現へ変換するのか。
ここに、記事本文表示の難しさがあると考えた。
microCMSのRich Editorを採用した理由
語り部の座では、記事本文の入力手段として microCMS の Rich Editor を採用している。
microCMSのRich Editorは、見出し、段落、リスト、引用、画像、リンクなど、
記事執筆に必要な基本的な表現を備えている。
また、API経由で取得した本文データはHTML形式で提供される。
本記事執筆時点の仕様については、以下の公式ドキュメントを参照している。
- microCMS Rich Editor
https://document.microcms.io/manual/rich-editor-usage
- microCMS Contents API
https://document.microcms.io/content-api/get-list-contents
Semantic Rendering Engine は、このHTML出力を前提として設計されている。
重要なのは、microCMSを採用したことではない。
Rich Editorの出力がHTMLであれMarkdownであれJSONであれ、
「入力されたコンテンツを意味として解釈する」
という考え方そのものが中心にある。
CSSだけで解決できたのではないか
最初に考えられる方法はシンプルである。
microCMS から取得した HTML をそのまま表示し、CSSで見た目を整える。
例えば、次のような考え方である。
<article class="article-body">
<!-- microCMS RichTextEditor の HTML をそのまま描画 -->
</article>article-body h2 {
font-size: 1.75rem;
margin-top: 2rem;
}
.article-body blockquote {
border-left: 4px solid currentColor;
padding-left: 1rem;
}
.article-body img {
max-width: 100%;
height: auto;
} これは一見すると合理的である。
実際、小さなサイトや単純な記事表示であれば、この方法でも十分に成立する。
しかし、語り部の座ではこの方法を中心には据えなかった。
理由は、CSSは見た目を制御できても、意味を制御することは苦手だからである。
DOM構造をそのまま信用しない
Rich Editor の出力は DOM 構造である。
しかし、DOM構造は必ずしもそのままデザインシステムに適合するとは限らない。
例えば、同じ blockquote でも、記事内では複数の意味を持ち得る。
- 引用
- 補足
- 注意喚起
- 筆者の強調
- 読者への警告
これらをすべて同じ blockquote としてCSSで装飾すると、意味の違いが表現できない。
また、画像についても同じである。
- 中央寄せ画像
- 左寄せ画像
- 右寄せ画像
- 図版としての画像
- 補助説明としての画像
意味が違えば、必要なUIも変わる。
つまり、問題はHTMLタグそのものではない。
そのHTMLが何を意味しているのか である。
Semantic Rendering Engineとは何か
Semantic Rendering Engine とは、CMSから取得した本文HTMLをそのまま表示するのではなく、
一度「意味の単位」として解釈し、
その意味に対応するUIコンポーネントへ変換して描画する考え方である。
従来の単純なレンダリングは、次のような流れになる。
RichText
↓
HTML
↓
CSSで装飾
↓
表示一方で、Semantic Rendering Engine では次のように考える。
Rich Editor
↓
DOM構造
↓
意味解析
↓
Semantic Node
↓
Component Mapping
↓
UI Component
↓
表示ここで重要なのは、HTMLを否定しているわけではないという点である。
HTMLは入力元であり、意味を読み取るための材料である。
しかし、最終的な表示責務はHTMLそのものではなく、フロントエンド側のコンポーネントが担う。
Component Mappingという中核
語り部の座では、本文レンダリングの中心に Component Mapping を置いている。
これは、HTMLタグや意味クラスを、対応するコンポーネントへ変換して描画する考え方である。
例えば、次のような対応になる。
h2
→ ArticleHeading Component
blockquote
→ QuoteBlock Component
pre > code
→ CodeBlock Component
img.align-left
→ ArticleImage Component
div.callout.warning
→ WarningCallout Componentこの設計により、microCMS側は意味を入力する場所となり、Astro側は表現を制御する場所になる。
つまり、CMS編集者は
「これは注意喚起である」
「これは引用である」
「これはコードである」
という意味を入力する。
一方で、その見た目や余白、色、レスポンシブ対応、ダークモード対応は、
フロントエンド側のコンポーネントが責任を持つ。
セマンティクスとデザインを分離する
語り部の座では、記事本文設計において次の原則を採用している。
- microCMS側は意味を管理する
- Astro側は見た目を管理する
- CMSにデザイン責務を持たせない
- インラインスタイルを禁止する
- 許可した表現だけを安定して表示する
この分離により、記事本文の運用はかなり安定する。
記事編集者は、文字色や余白を調整する必要がない。
デザイン変更が発生しても、CMS側の記事本文を修正する必要がない。
UIコンポーネントを修正すれば、既存記事全体へ反映できる。
なぜ自由度を絞るのか
Rich Editor は自由度が高い。
しかし、自由度が高いことは常に良いことではない。
記事ごとに見た目がバラつく。
レスポンシブ表示が崩れる。
画像やテーブルがはみ出す。
HTML属性が不統一になる。
想定外の iframe や script が混入する。
こうした問題は短期的には見えにくい。
しかし記事数が増えるほど、確実に運用コストとして返ってくる。
そのため、語り部の座では自由度よりも一貫性と保守性を優先している。
表現力を高めることと、自由にHTMLを書けるようにすることは同じではない。
語り部の座では、意味に対応するコンポーネントを追加することで表現力を拡張する。
MVP時点での対応範囲
Semantic Rendering Engine は最初からあらゆるHTML表現を扱うことを目的としていない。
語り部の座のMVPでは、以下の表現のみを正式対応としている。
対応する表現
- 見出し(h2〜h4)
- 段落
- 箇条書きリスト
- 番号付きリスト
- リンク
- 画像
- 引用
- コードブロック
- テーブル
- Callout(推奨・注意・禁止)
非対応とする表現
- 任意JavaScript
- scriptタグ
- iframe埋め込み
- 独自HTML
- インラインスタイル
- 自由レイアウト用div
- カスタムCSS
フォールバック方針
未対応要素が出現した場合は、
- 安全に表示可能なものは標準HTMLとして表示
- 危険性があるものは除外
- 将来的に利用頻度が高いものは専用コンポーネントとして追加
する方針としている。
Calloutも意味で管理する
Semantic Rendering Engine の考え方が分かりやすく表れるのが Callout である。
Callout は色や装飾ではなく、意味で管理する。
語り部の座では、MVP時点で次の3種類を想定している。
recommendation
→ 推奨内容
warning
→ 注意内容
danger
→ 禁止内容CMS側では、次のような意味クラスを付与する。
<div class="callout recommendation">
<p>これは推奨される考え方です。</p>
</div>
<div class="callout warning">
<p>これは注意が必要な内容です。</p>
</div>
<div class="callout danger">
<p>これは避けるべき内容です。</p>
</div>しかし、どの色にするか、どの余白にするか、アイコンを付けるかどうかはCMS側では決めない。
それはコンポーネント側の責務である。
div.callout.recommendation
→ RecommendationCallout Component
div.callout.warning
→ WarningCallout Component
div.callout.danger
→ DangerCallout Componentこのように、CMSは意味を渡し、フロントエンドは意味に応じた表現を返す。
Semantic Rendering Engineがもたらしたもの
この設計により、語り部の座では記事本文の表現力を高めながら、統制も維持できるようになった。
特に大きいのは、表現を増やしたいときの拡張方法が明確になったことである。
例えば、
- 数式を扱いたい場合は数式用コンポーネント
- Mermaid図を扱いたい場合はMermaid用コンポーネント
- FAQを扱いたい場合はFAQ用コンポーネント
を追加すればよい。
重要なのは、CMS側の自由度を無制限に広げることではない。
意味の種類を増やし、それに対応するコンポーネントを追加することである。
DataLinerホームページ開発で見えていた課題
この考え方は、語り部の座だけのものではない。
実は、DataLinerホームページの開発時点でも課題は見えていた。
DataLinerホームページでは、Rich Editorの表現力を十分に扱いきれず、
カードの羅列によって情報を整理する形を取った。
それはMVPとしては妥当な判断だった。
しかし、カード中心のUIには課題もある。
- 情報が単調になりやすい
- 読者に読んでもらいにくい
- サムネイル画像の使用量が増える
- 画像最適化処理が増え、ビルド時間が重くなる
実際、表玄関ではビルド時間の多くを画像最適化処理が占める構造になっていた。
これは単なるパフォーマンス問題ではない。
表現上の制約を補うために、結果として画像への依存度が高くなっていたとも考えられる。
Semantic Rendering Engine によって、本文内の意味をUIとして表現できれば、
画像に頼りすぎずに情報を伝えられる。
これは、可読性、保守性、ビルド性能の改善にもつながると考えている。
Astro固有の話ではない
語り部の座ではAstroを使っている。
microCMSを使っている。
しかし、Semantic Rendering Engineという考え方はAstroやmicroCMSに閉じたものではない。
- Markdown
- Contentful
- WordPress
などでも成立する。
入力がHTMLであれ、Markdown ASTであれ、JSON構造であれ、本質は同じである。
重要なのは、入力されたコンテンツをそのまま表示するのではなく、
一度意味として解釈し、意味に応じた表現へ変換することである。
類似概念との違い
Semantic Rendering Engine は完全に新しい技術というわけではない。
既存の技術や設計思想と重なる部分も多い。
Markdown ASTとの違い
Markdown ASTは文書構造を木構造として扱う。
Semantic Rendering Engine は、その先にある
「どの意味をどのUIで表現するか」
までを対象としている。
Remark / Rehypeとの違い
RemarkやRehypeはMarkdownやHTMLを変換するためのツールチェーンである。
一方でSemantic Rendering Engineは、
どの意味をどのUIコンポーネントへ対応付けるかという設計上の責務分離を対象としている。
Semantic Rendering Engine は特定ライブラリではなく、
変換後の責務分離と表現戦略を定義する設計思想である。
Design Systemとの違い
Design System はUIコンポーネントの見た目や振る舞いを統一する。
Semantic Rendering Engine は、
どの意味をどのコンポーネントへ割り当てるか
という変換ルールを扱う。
コンテンツモデリングとの違い
コンテンツモデリングは情報構造を定義する。
Semantic Rendering Engine は、
定義された情報構造を最終的なUIへ変換する責務を持つ。
おわりに
Semantic Rendering Engine は、語り部の座の記事本文表示を作る過程で生まれた考え方である。
出発点は、microCMS の Rich Editor の入力データをどう扱うかという実装上の課題だった。
しかし、その課題を掘り下げていくと、単なるHTML表示の問題ではないことが見えてきた。
本当に必要だったのは、CMSの出力をそのまま表示することではなかった。
必要だったのは、コンテンツの意味を読み取り、意味に応じた表現へ変換する仕組みだった。
語り部の座では、これを Semantic Rendering Engine と呼んでいる。
HTMLを表示するのではない。
意味をUIへ変換する。
それが、語り部の座における記事本文表現の中核である。