第6章 - 0003 後で困らない要素間のmarginの設定方法を練習問題を通して理解しよう

この節のはじめに

モジュールの再利用をするときや、プログラムによって表示要素を出し分けるとき、隣接する要素の組み合わせは変化し、その組み合わせが変化したときは、2つの要素間のmarginも変更したいときがあります。

この節では、隣接する要素の組み合わせが変化する具体例をもとに、後で困ることのないmarginの設定方法について学習していきましょう。

margin設定についての練習問題の基礎となるHTML

前の節で作成したmargin-tutorial.htmlの、以下の箇所を基礎として、少し変更しながら説明していきます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<ul class="mod-margin-tutorial-0001">
<li class="mod-margin-tutorial-0001__item-basic">
item-basic
</li>
<li class="mod-margin-tutorial-0001__item-1">
item-1
</li>
<li class="mod-margin-tutorial-0001__item-2">
item-2
</li>
<li class="mod-margin-tutorial-0001__item-3">
item-3
</li>
</ul>

margin設定についての練習問題の基礎となるSCSS

前の節で以下の通り記述した_mod-margin-tutorial-0001.scssを基礎として、少し変更しながら説明していきます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.mod-margin-tutorial-0001 {
display: flex;
flex-direction: column;
.mod-margin-tutorial-0001__item-basic {
background: #dddddd;
}
.mod-margin-tutorial-0001__item-1 {
background: #ffdddd;
}
.mod-margin-tutorial-0001__item-2 {
background: #ddffdd;
}
.mod-margin-tutorial-0001__item-3 {
background: #ddddff;
}
}

margin設定についての練習問題を始める前に

「基礎となるHTML」では、以下の4つのElementクラスが付与されたli要素をul要素が包括しています。

  • mod-margin-tutorial-0001__item-basic
  • mod-margin-tutorial-0001__item-1
  • mod-margin-tutorial-0001__item-2
  • mod-margin-tutorial-0001__item-3

練習問題の説明をするにあたって、上記のElementクラスが付与されたli要素をそれぞれ以下のように表現します。

  • item-basic
  • item-1
  • item-2
  • item-3

margin設定についての練習問題で想定する条件

このmargin設定についての練習問題では、以下の条件を満たせるようなmarginをElementクラスに設定していきましょう。

  • ul要素の中には、item-basic、item-1、item-2、item-3がランダムで1つまたは2つ表示されるものとします。
  • item-1とitem-1など、同じ要素が2つ表示される場合もあるものとします。
  • いずれか1つだけが表示される場合のmarginは0とします。
  • 隣接要素の無い方向、つまり最初のli要素のmargin-top、最後のli要素のmargin-bottomは設定しないものとします。
  • item-basicとitem-1、item-2、item-3のいずれかが隣接する場合、2つの要素間のmarginは20pxとします。
  • item-1、item-2、item-3のいずれか2つが隣接する場合は、2つの要素間のmarginは、item番号×item番号×10の式で算出した値を設定するものとします。例えばitem-1とitem-2が隣接する場合のmarginは、1×2×10=20pxとします。

この条件を満たすSCSSを書いてみてください

余裕があれば、_mod-margin-tutorial-0001.scssを編集して、この条件を満たすSCSSをご自身で書いてみてください。

正しい答えの例はこの後に掲載します。

正しい答えの例

表示されるパターンを整理する

まずは表示されるパターンを整理してみます。
表示されるパターンさえ整理されればあとは簡単です。

いずれか1つ表示されるパターン

以下のパターンがありますが、いずれもmarginは0です。

  • item-basic
  • item-1
  • item-2
  • item-3

いずれか2つ表示されるパターン

以下のパターンがあります。

item-basicが前にくるパターン

  • item-basic、item-basicの順に表示 margin-top: 20px;
  • item-basic、item-1の順に表示 margin-top: 20px;
  • item-basic、item-2の順に表示 margin-top: 20px;
  • item-basic、item-3の順に表示 margin-top: 20px;

item-1が前にくるパターン

  • item-1、item-basicの順に表示 margin-top: 20px;
  • item-1、item-1の順に表示 margin-top: 10px;
  • item-1、item-2の順に表示 margin-top: 20px;
  • item-1、item-3の順に表示 margin-top: 30px;

item-2が前にくるパターン

  • item-2、item-basicの順に表示 margin-top: 20px;
  • item-2、item-1の順に表示 margin-top: 20px;
  • item-2、item-2の順に表示 margin-top: 40px;
  • item-2、item-3の順に表示 margin-top: 60px;

item-3が前にくるパターン

  • item-3、item-basicの順に表示 margin-top: 20px;
  • item-3、item-1の順に表示 margin-top: 30px;
  • item-3、item-2の順に表示 margin-top: 60px;
  • item-3、item-3の順に表示 margin-top: 90px;

全ての条件を満たせるSCSS

答えはとても簡単です。

第3章 - 0014 mod-container-0001のコードからポイントを読み取ろう」で学習した「隣接する兄弟要素が変化する可能性のある箇所は隣接兄弟要素セレクタでmarginを制御する」というポイントの通り、以下の通り隣接兄弟要素セレクタでmarginを制御します。

以下のように書くのが誰もが思いつく最も基本的な方法だと思います。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
.mod-margin-tutorial-0001 {
display: flex;
flex-direction: column;
.mod-margin-tutorial-0001__item-basic {
background: #dddddd;
& + .mod-margin-tutorial-0001__item-basic,
& + .mod-margin-tutorial-0001__item-1,
& + .mod-margin-tutorial-0001__item-2,
& + .mod-margin-tutorial-0001__item-3 {
margin-top: 20px;
}
}
.mod-margin-tutorial-0001__item-1 {
background: #ffdddd;
& + .mod-margin-tutorial-0001__item-basic,
& + .mod-margin-tutorial-0001__item-2 {
margin-top: 20px;
}
& + .mod-margin-tutorial-0001__item-1 {
margin-top: 10px;
}
& + .mod-margin-tutorial-0001__item-3 {
margin-top: 30px;
}
}
.mod-margin-tutorial-0001__item-2 {
background: #ddffdd;
& + .mod-margin-tutorial-0001__item-basic,
& + .mod-margin-tutorial-0001__item-1 {
margin-top: 20px;
}
& + .mod-margin-tutorial-0001__item-2 {
margin-top: 40px;
}
& + .mod-margin-tutorial-0001__item-3 {
margin-top: 60px;
}
}
.mod-margin-tutorial-0001__item-3 {
background: #ddddff;
& + .mod-margin-tutorial-0001__item-basic {
margin-top: 20px;
}
& + .mod-margin-tutorial-0001__item-1 {
margin-top: 30px;
}
& + .mod-margin-tutorial-0001__item-2 {
margin-top: 60px;
}
& + .mod-margin-tutorial-0001__item-3 {
margin-top: 90px;
}
}
}

同じく「第3章 - 0014 mod-container-0001のコードからポイントを読み取ろう」で学習した、first-childを使用する方法を利用して、以下のように書き換えることもできます。Elementクラス同士の隣接する組み合わせが今後増えることが無いのであれば以下のようにする必要はないと思いますが、復習も兼ねて書いておきます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
.mod-margin-tutorial-0001 {
display: flex;
flex-direction: column;
.mod-margin-tutorial-0001__item-basic {
margin-top: 20px;
background: #dddddd;
&:first-child {
margin-top: 0;
}
}
.mod-margin-tutorial-0001__item-1 {
margin-top: 20px;
background: #ffdddd;
&:first-child {
margin-top: 0;
}
& + .mod-margin-tutorial-0001__item-1 {
margin-top: 10px;
}
& + .mod-margin-tutorial-0001__item-3 {
margin-top: 30px;
}
}
.mod-margin-tutorial-0001__item-2 {
margin-top: 20px;
background: #ddffdd;
&:first-child {
margin-top: 0;
}
& + .mod-margin-tutorial-0001__item-2 {
margin-top: 40px;
}
& + .mod-margin-tutorial-0001__item-3 {
margin-top: 60px;
}
}
.mod-margin-tutorial-0001__item-3 {
background: #ddddff;
& + .mod-margin-tutorial-0001__item-basic {
margin-top: 20px;
}
& + .mod-margin-tutorial-0001__item-1 {
margin-top: 30px;
}
& + .mod-margin-tutorial-0001__item-2 {
margin-top: 60px;
}
& + .mod-margin-tutorial-0001__item-3 {
margin-top: 90px;
}
}
}

margin-topの初期値を設定してfirst-childセレクタで打ち消しておく方法について

この方法は「第3章 - 0014 mod-container-0001のコードからポイントを読み取ろう」で紹介した例のように、Blockクラスのmargin-topで使用するのが非常に効果的です。

というのも、Webサイトの運用が続くにしたがって、モジュールの種類は増え続けていくことが多く、それらのモジュールは至る所で再利用され、多くの隣接兄弟要素の組み合わせが新たに生まれます。

その組み合わせが増える度に毎回セレクタを追加し、マージンを設定するのは少し面倒なので、一番よく使用されるmarginの値がわかってきたところで初期値を設定します。
また、隣接要素が無いパターンではもともとmarginは設定されていなかったため、初期値を設定するのと同時にfirst-childでmargin:0;にしておく必要があるということも理解していただければと思います。

marginの方向について

この練習問題では、margin-topを使用しました。
実際margin-topを設定する機会が一番多くなると思います。

少し補足説明をしておきますが、以下の場合はmargin-bottomを設定することになります。

1
2
3
4
5
.mod-margin-tutorial-0001 {
display: flex;
flex-direction: column-reverse;
〜略〜
}

以下の場合はmargin-leftを設定することになります。

1
2
3
4
5
.mod-margin-tutorial-0001 {
display: flex;
flex-direction: row;
〜略〜
}

以下の場合はmargin-rightを設定することになります。

1
2
3
4
5
.mod-margin-tutorial-0001 {
display: flex;
flex-direction: row-reverse;
〜略〜
}

この節のおわりに

このmargin設定についての練習問題をやってみることで、「第3章 - 0004 mod-heading-0001のコードからポイントを読み取ろう」で学習した「2つの要素間のmarginを設定するときは後の要素に設定する」というポイントのメリットや、逆に前の要素にmarginを使用してしまうと、隣接要素の組み合わせが変化した場合に困ることになるということがわかったと思います。

一応補足しておくと、「隣接する2つの要素の組み合わせが変化しない」または「隣接する2つの要素の組み合わせが変化したとしてもmarginは変化しない」ということが決まっているのであれば、前の要素にmarginを設定しても問題は起こりませんが、こういうときは前の要素にmarginを設定する。ああいうときは後の要素にmarginを設定する。とルールを細かく分けてしまうと、チームの人数が多い場合や、新しいチームメンバーを迎えた場合、自分が担当していた仕事を引き継ぐ場合などにわかり難くなってしまうため、できるだけルールを少なく抑えてシンプルに保つ意味で「2つの要素間のmarginを設定するときは後の要素に設定する」というルールを徹底することを推奨しています。

続きはこちら

とてもやさしいCSS設計チュートリアルの目次へ戻る