この記事をおすすめしたい人
- Nuxt.jsでレイアウトを複数作ったらCSSが流用されまくって困った人
- app.jsでCSSがロードされてることが確認できたけど、削除方法が分からない人
- つまりオレ
何も知らない超初心者が脱WordPressしたくてNuxt.jsでサイト構築していくシリーズです。
今回はレイアウトを複数用意した場合、何故か全てのレイアウトのCSSが全てのページに適用されてしまう問題を解決したいと思います。
レイアウトを複数使うケースがそもそも希なのかな…。
テストサイトがトップ以下、カテゴリごとにガラッと内容が変わるサイトを作ろうとしていたもので、大きく詰まりました。
一応、解決までいったのでその流れをお話ししたいと思います。
WordPressの上でな!
※ このブログはWordPress製です
このページの目次
希望しているCSSの挙動
グローバル、レイアウト、ページ、コンポーネントと分けてCSSを定義することで、それぞれの範囲でしかCSSが適用されず、それぞれの範囲でしかCSSが読み込まれない(ファイルサイズ的に)ようにしたいです。
例えばレイアウトAで指定したCSSは、レイアウトAを使用するページでのみ反映されて、レイアウトBを使用する際には同じセレクタであってもレイアウトBのものを使用。 レイアウトAのスタイルは読み込みすらしないし、もちろんスタイルも適用されない。
こんな感じを希望していて、Nuxt.jsのCSS環境はそれができそうな感じに見えていました。
実際のNuxt.jsのCSSの動作
グローバル指定したい場合はnuxt.config.js、レイアウト・ページ・コンポーネントはそれぞれのファイル内の<style>タグに指定することで希望する動作になりました。
出力されたHTMLの<head>タグ内でそれが確認できます。
ガッ!!
レイアウトだけはデフォルトで読み込まれる「/_nuxt/app.js」に全レイアウトのCSSが紛れ込んでいるせいで、HTML上はCSSロードされてないにもかかわらず全部グローバルCSSとして、全ページに適用されてしまっています。
つまりレイアウトごとにCSSの使い分けができず、固有のIDやクラスを付けてきっちり使い分けないといけないんです。
構造的なメリットあるのかコレ…。
Scoped CSSとかいうのを使ってみる
レイアウトやコンポーネントで<style>指定する時に「<style scoped>」のように「scoped」とつける方法です。
scopedを付けると何が起こるかというと、
<span class"bold" data-v-XXXXXXXXX>
という感じに「data-v-XXXXXXXXX」という属性がつき、CSSの方にも
.bold[data-v-XXXXXXXXX] {
font-weight: bold;
}
といった感じに、属性が付与されるのでCSSの適用範囲を限定できます。
解決できそうな予感。
さみしーさーならー慣れてーいーるよー
Scoped CSSの良いところ
ページやコンポーネント限定のCSSを指定する場合にはとても便利だと思います。
でもそもそもページやコンポーネントのスタイルはグローバルと言いつつグローバルになっていないっぽいのであまり意味がありません。
Scoped CSSのダメなところ
ページやコンポーネントはいいんですが、レイアウト。
レイアウトは「そのレイアウトを読みこんだページ」にもCSS適用してほしいところなんですが…。
「data-v-XXXXXXXXX」はレイアウトファイル内に書かれたタグだけに付与されます。 当然CSSもその範囲だけに適用されます。
どういうことかと言うと、
<template>
<div>
<Header />
<Nuxt />
<div class="sidebar">
(略)
</div>
<Footer />
</div>
</template>
この↑ようにレイアウト内でサイドバーを定義していた場合、サイドバーにはscopedなCSSが適用されます。
ですが、コンポーネントや<Nuxt />の中へは一切影響しなくなります。
そこで、例えば<Nuxt />にクラスを付けて↓、
<template>
<div>
<Header />
<Nuxt class="layout-scoped" />
<div class="sidebar">
(略)
</div>
<Footer />
</div>
</template>
CSSをこの↓ように設定します。
.layout-scoped strong {
font-weight: bold;
}
こうやるとこのレイアウトを使用するページのstrongのスタイルを設定できそうですが、実際はこう↓なります。
.layout-scoped strong[data-v-XXXXXXXXX] {
font-weight: bold;
}
このレイアウトファイル内に書いたstrongにしか影響しません。
scopedが過ぎて汎用性がありません…。
あともうひとつは、仮にこれで期待する動作になっていたとしても、どっちみち全レイアウトのCSSが読み込まれてしまっているので、ファイルサイズ的なデメリットを抱えることになります。
結論、レイアウトCSSはグローバルになるよう設定されていた
Nuxt.js公式マニュアルを読みあさった結果、splitChunksというオプションがあり、デフォルトではレイアウトのCSSはapp.jsに統合されるように設定されていたようです。
{
layouts: false,
pages: true,
commons: true
}
これをtrueにしてやると、無事にレイアウトのCSSもレイアウトごとに適用されるようになりました。
これ、falseのメリットあるんでしょうか…?
わざわざレイアウトを別に用意するってことはスタイルも変えたい場合だと思うんですよね。
グローバルにしたいならグローバルCSSを設定する部分があるわけですし…。
頭おかしくなりそうなくらい調べてたので、とにかく解決してよかったです。
splitChunksのデメリット
splitChunksでlayoutsをtrueにすると、レイアウト用のJavaScriptが追加されます。
<script src="/_nuxt/layouts/default.js" defer></script>
内容的にはapp.jsに統合していたものを分離しただけですが、読み込むファイルがひとつ増えるため、PageSpeed Insightsのスコアがちょっと下がりました。
まとめ
レイアウトのCSS適用範囲を限定したい場合はscopedではなく、splitChunksをtrueにする!
export default {
build: {
splitChunks: {
layouts: true,
pages: true,
commons: true,
},
},
}
これはデフォルトでtrueでいい機能だと思うんだ…。
複数レイアウトを使うケースが希だからこんな仕様になってるのかな…。
以上、WordPressからお届けしました!
Nuxt.js HEADタグ操作編の目次
- 第1回 head内操作のまとめ
- 第2回 ページ毎にtitleを設定
- 第3回 ページ毎にdescriptionを設定
- 第4回 「lang="ja"」を設定
- 第5回 Faviconの設定を追加
- 第6回 SNS用OGPの設定を追加
- 第7回 canonicalの設定
- 第8回 jQueryなどのスクリプト追加(近日公開予定)
- 第9回 外部CSSファイルを読み込む
- 第10回 レイアウトのCSSを独立させる(このページ)
- 第11回 CSSの詳細設定(近日公開予定)
- 第12回 構造化データの設定(近日公開予定)
- 第13回 「data-n-head」などを削除