共通レイアウトはslotにお任せ!Astroでサイト全体の統一感を保つ方法

#Astro
共通レイアウトはslotにお任せ!Astroでサイト全体の統一感を保つ方法

slotを知りたい

多数のページを抱えたサイトを構築していく際に、デザインの課題として上がるものの一つが統一感だと思う。サイトのコンセプトに合わせたデザインとしての一貫性が、サイトとしての完成度を押し上げる。しかしページ数が増えれば増えるほど、機能が増えれば増えるほど、その統一感を守ることは難しくなってくる。

そこで出てくる解決策の一つが共通部品を切り出しての管理であり、そこで便利になってくるのが <slot> である。Astro特有のものではなく、Vue.jsなどでも用意されている機能になるが、本サイトを構築するにあたり、改めてその便利さに気付いたため <slot> について整理したい。

まずは公式ドキュメントの記載について確認したい。以下はスロットの章からの引用である。

<slot />要素は外部HTMLコンテンツのプレースホルダーで、他のファイルからコンポーネントテンプレートに子要素を注入(はめ込む=スロット)できます。

これだけで <slot> の利便性というものを一から十まで理解するのは難しい。まして「これからサイト構築を頑張ろうと思います!」というフレッシュな新人に <slot> の有用性は伝わらない。実際に本サイトで作成したレイアウトコンポーネントのコードベースで解説していきたい。

レイアウトコンポーネント

src/
  layouts/
    PageLayout.astro

layoutsフォルダ配下には、ヘッダーやフッター、SEO用の <head> タグなど、全ページで共通して使いたい「外枠(レイアウト)」を定義したコンポーネントを配置している。以下はそのソースの全容である。

---  
import (省略)
  
interface Props {  
  title: string;  
  description?: string;  
  currentPath?: string;  
}  
  
const { title, description, currentPath = Astro.url.pathname } = Astro.props;  
---  
<BaseLayout title={title} description={description}>  
  <Header currentPath={currentPath} />  
  <main id="main" class="flex-1" tabindex="-1">  
    <slot />
  </main>  
  <Footer />
</BaseLayout>    

ページのレイアウトとして <Header> と <Footer> という基本的な枠組みを定義している。ページごとに変わってくる中身のコンテンツについては、<slot> と入れ替わる形で入ってくる。公式ドキュメントで言う「プレースホルダー」とは、まさにこの「後からコンテンツを入れるための空き枠(穴)」のことを指している。

こうして作成したPageLayoutコンポーネントを全ページで使うことで、それぞれで共通した枠組みが反映されることとなる。

呼び出し側での使われ方

実際にPageLayoutコンポーネントを使っているコードを見ていく。下記は「ゲーム一覧」ページの実際のコードであり、先頭部分でPageLayoutコンポーネントをインポートしている。

---  
import PageLayout from '~/layouts/PageLayout.astro';  

(省略)
---  
  
<PageLayout  
  title="ゲーム一覧"  
  description="制作したゲームの一覧です。使用技術・制作期間・リンクを掲載しています。"  
>  
  <div class="container-narrow py-12 pb-0">  
    <Breadcrumbs items={breadcrumbs} class="mb-6" />  
    <PageHeading title="ゲーム一覧" class="mb-8" />  
  
    <p class="text-main-muted mb-10">  
      完成品と開発過程をブログ形式で掲載。GitHub・プレイ動画などへのリンクも用意しています。  
    </p>  
  </div>  
  <GameList client:load />  
</PageLayout>

見てもらえば分かる通り、PageLayoutコンポーネント内で定義してあるHeaderやFooterについては、ページ内で改めて定義するようなことはしていない。ページごとのコンテンツについては、<PageLayout> タグで囲んだ内側の要素(<div> や <GameList> など)として記載しており、それらがそのまま PageLayout.astro 側の <slot /> が置いてある場所へとがっちゃんこ(注入)される。

さて、こうして実際に使っている <slot /> がなかった場合を想像してみよう。

slotがなかった場合

slotがなかった場合、各ページの共通的なレイアウトについてはコピペして対応することとなる。ページ追加する度に同じものをコピペしていくのは、あまりに手間でミスの温床である。また開発途中で「やっぱりヘッダーのデザインを変えたい」ということも起こりうる。そうなった場合、これまでコピペした内容を全て書き換えるということをしなければいけなくなる。

10ページくらいであれば、その対応は容易であろう。もしもそのページが100ページあったら……想像するだけでも恐ろしい。そういったことが積み重なって、ページのレイアウトがバラバラなホームページが誕生する。そういったサイト全体に共通する枠組みを作り、サイト全体の統一感を出すことが自動的にできるようになり、さらに柔軟に変更しやすくする運用を実現させてくれるのが <slot /> なのである。

また、新ページを追加する際に枠組みの部分を考える必要がなく、中身のコンテンツを充実させることにのみ集中できるというのも大きなメリットといえるだろう。そんな良いことずくめの <slot /> を使わないなどという選択肢は存在しない。

まとめ

<slot /> 自体はVueなどの他のフレームワークにも存在する。それらは膨大なページ数になることが当たり前になりつつある昨今のWeb開発において、統一感や運用の課題、コンテンツを充実させることに集中させるためなど、非常に役に立つものだ。

プレースホルダーだとか注入だとか、少し難しそうなフレーズに惑わされずに使いこなすことこそが、サイト開発における初歩の初歩なのではないだろうか。

関連記事