💦

CSS設計の大切さについて学びました(汗

2022/01/14に公開

前提

使用技術: vue

背景

表出しているモーダルコンポーネントのCSSが別のモーダルコンポーネントに上書きされ、レイアウト崩れが発生した。

原因

表出しているモーダルコンポーネントよりあとに、別のモーダルコンポーネントが読み込まれていて、同じCSSが適応されており上書きが発生した。

原因の解像度を上げてみる

表出しているモーダルコンポーネントと上書きしているモーダルコンポーネントファイルのスタイルがglobal指定になっていた。

なぜglobalになっていたのか

使用したリポジトリがcss-moduleを使用できない設定にしているのに、vueコンポーネント内のスタイル指定がmoduleになっていた。
そのため、css-moduleがうまく適応されず、グローバルスタイルに変換されていた。

上書きさせないためには

3点方法があります

1. 両方のモーダルコンポーネントのスタイルをscoped指定する

scoped CSSを有効に活用すれば、スタイルの影響範囲をコンポーネント内に留めることが出来ます。

scoped CSS

ビルド時に、コンポーネント毎にユニークなカスタムデータ属性を生成し、スタイルの影響範囲を1コンポーネントに留める事ができます。

(引用:ice Media https://ics.media/entry/200515/)

ただし、注意点が2つあります。

  1. グローバルのスタイルは上書きしてしまう
    ユニークなカスタムデータ属性は要素に追加されるため、クラス単体で見た時にクラス名がユニークになっているわけではない。
    したがって、グローバルスタイルの上書きの対象になってしまう。

    (引用:ice Media https://ics.media/entry/200515/)

  2. 親コンポーネントのスタイルは子コンポーネントのルート要素に適応できてしまう(仕様)
    カスタムデータ属性が要素に付与されるため、子コンポーネントのルート要素には、子と親の両方のカスタムデータ属性が付与されてしまい、親コンポーネントのスタイルが適応される。

    (引用:ice Media https://ics.media/entry/200515/)

一言でいうと、scoped CSSは外部のCSSの影響を受けやすいので注意しましょう、ということです。

それでも、コンポーネント毎にスタイルの影響範囲を絞れるのはいいことですね。

2. css-moduleを使用する

css-moduleを有効に活用できれば、スタイルの影響範囲をコンポーネントに留めることが出来ます。
開発リポジトリの環境が、css-module使用出来ない環境だったのでここに適応するのは難しいですが、vueのプロダクトであれば通常使用できるので説明します。

css-module

ビルド時に、コンポーネント毎にユニークなハッシュ値が生成され、各クラスにハッシュが追加されます。
それにより、クラスが各コンポーネント固有のものとなり、スタイルの影響範囲を1コンポーネントに留めることができます。

scoped CSSもcss-moduleも、「スタイルの影響範囲を1コンポーネントに留めることができます」この点が似ていますね。
しかし、css-moduleは、scoped CSSと違って、外部のCSSに上書きされる心配はありません。
理由は、css-moduleは、クラス自体にコンポーネント固有のハッシュ値がつくため、ユニークなクラスになるからです。

例)
コンポーネント構造↓
App.vue
└ HolloWorld.vue
└SeeYouWorld.vue

// HolloWorld.vue
<template>
 <div :class="$style.hello">
   <h1>{{ msg }}</h1>
 </div>
</template>

<script>

export default {
 props: {
   msg: String
 }
}
</script>

<style module>
.hello {
 background-color: pink;
}
</style>
// SeeYouWorld.vue
<template>
 <div :class="$style.hello">
   <h1>{{ msg }}</h1>
 </div>
</template>

<script>
export default {
 props: {
   msg: String
 }
}
</script>

<style module>
.hello {
 background-color: lightskyblue;
}
</style>


各コンポーネントに.helloを追加しているが、class="HelloWorld_hello_1ae9Gclass="SeeYouWorld_hello_qRY6hとなり、ユニークなクラスになっています。

scoped CSSとの違いとしては、コンポーネント固有の生成される値が 「要素」 につくのではなく、「クラス」 につく事です。
そもそものクラスをコンポーネント固有のものにしているため別コンポーネントのクラスに上書きされる心配がない、という訳になります。

3. CSSの詳細度を上げる

上書きしているCSSより、詳細度の高いCSSを付与する(modifierをつける等)事で、上書きを防ぐ事が出来ます。

今回は、既存のモーダルコンポーネントの修正のため、修正による影響範囲を最小にするため、
表出するモーダルのCSSの詳細度を上げる事で、レイアウト崩れを防ぐようにしました。

最後に

今回のレイアウト崩れの原因等を調査していく中で、CSS設計の大切さを実感し、
プロダクトスタートさせる時の技術選定や設計次第で今後の開発のしやすさ、保守性の高さが左右される事を学びました。
今後、設計など考えていくときは今回の教訓を生かしていけたらいいなと思います。

参考

  1. https://vue-loader-v14.vuejs.org/ja/
  2. https://ics.media/entry/200515/

Discussion