要素指定の見本帳~順番など正しい指定で操作しよう~基礎編

技術備忘録

知って便利、使って便利、狙い通りの場所に、狙い通りの動作を。複雑なHTML構造を汚さず、CSSだけで『順番』を支配するための、【基礎】順番指定等の要素指定の一覧です。

最初だけ簡単な解説があります。

解説:書き慣れている人ほど陥りやすいターゲットの履き違え典型例

.test li a:first-child

かきがちであり、
これを書く時、心の中ではリストの一番最初のリンクを変えたいと思っているはずです。しかし、ブラウザの解釈は違います。

.testの中の、すべてのliを見て、その中にある最初の子要素であるaを全部連れてきて。

<ul class="test">
  <li><a href="#">ターゲット1</a></li> <!-- 1番目のa(最初の子)-->
  <li><a href="#">ターゲット2</a></li> <!-- ここも1番目のa(最初の子)-->
  <li><a href="#">ターゲット3</a></li> <!-- ここも1番目のa(最初の子)-->
</ul>

リスト項目(li)の中にリンク(a)が1つしかない場合、すべてのリンクが「最初の子」になってしまい、結局全部変わってしまいます。

正解の書き方.test li:first-child a
こう書くことで、「1番目の li に入っている a だけ」という、狙い通りの特別扱いが可能になります。

a:first-childが活躍する場面。
逆に、この書き方が「正解」になるのは、1つの li の中にリンクが複数並んでいる時です。

<li>
 <a href="#">【カテゴリ】</a> <!-- これが a:first-child -->
 <a href="#">記事タイトル</a>
</li>

解説:うっかり&打ち込みミスで陥ったターゲットの履き違え典型例

.test li :first-child a

書きなれてない人が陥る
liの後のわずかな半角スペースの有無が、CSSの支配力が及ぶ範囲を大きくに変えてしまいます。

意味:liの中にある「何らかのタグ」の、さらに中にあるaタグ

  • 構造のイメージ:li > div > a
  • ターゲット:li の直下にある最初の要素(divやspanなど)の中に閉じ込められたリンク

実務上の罠:liの直下に直接aがあっても、このセレクタは反応しません。なぜなら、半角スペースがあることで「aは、『liの最初の子供』の、さらに子供(子孫)であること」という二重の条件を求めてしまうからです。

数え方の原理が異なるセレクタ:nth-child と nth-of-type の使い分

この2つを知っておかないと、何故効かないんだ!なんてことに陥ることがあるのでほんの少しだけ説明します。まず順番などを指定するセレクタはnth-childとnth-of-typeがあります。

nth-child(n)

nth-childはタグを指定しない場合、上から順番に指定した数字分のタグを数えて反応します。

しかし、p:nth-childなどのタグを指定した場合、種類問わずにタグを上から数えてそこに指定したpがなければ反応しません。

nth-of-type(n)

p:nth-of-typeの様にタグを指定した場合、その指定したタグのみを正しく上から順番に指定した数字分だけ数えて反応します。

しかし、タグをしなかった場合、こいつがある意味最恐にやんちゃな挙動をします。

タグを指定しないnth-of-typeは「それぞれのタグごとに、1番目、2番目……」という数え方になります。

タグを指定しない :nth-of-type(1) の動き

<div>
 <h1>タイトル</h1>  <!-- h1の1番目 -->
  <p>文章A</p>      <!-- pの1番目 -->
  <p>文章Bリスト</ul>    <!-- ulの1番目 -->
</div>

もしCSSで div :nth-of-type(1)とタグの指定なしで書くと、

  • h1(h1の1番目)➔ 反応する
  • p(文章A:pの1番目)➔ 反応する
  • ul(ulの1番目)➔ 反応する

それぞれのタグの「1番目」がすべて選ばれてしまいます。もしも仮にその中にulがあったとしたら、ulの中のli全てが反応します。構造的には最初のulに反応してますが、見た目はulの中のliが全てが反応してるように見えます。

知って使って便利な疑似クラス(Pseudo-classes)

基本的には、タグを指定して使います
これらの擬似クラスは、単体(例::nth-child(2))でも動きます。
しかし、li:nth-child(2) や p:nth-of-type(2) のように、タグ名とセットで使うのが基本です。

理由は「予期せぬ暴発」を防ぐため。
タグを指定しないと、目に見えない script タグや広告の div まで数えてしまい、デザインが意図せず崩れる原因になります。「誰を数えるのか」を明確にすることが、精密な設計への第一歩です。

最初の要素:first-child・first-of-type

nth-childやnth-of-typeの他にも便利なセレクタがあります。

1. :first-child
説明:親要素から見て、とにかく一番最初の子要素。 もし1番目がpタグで、h3:first-childと書いたら、1番目だけどh3じゃないとなり、反応しません。これは一見融通が利かないように見えますが、厳格に順番を守るセレクタです。

2. :first-of-type
説明:一番最初に出てくる子要素。h3:first-of-typeと指定したら、とにかく最初のh3に反応します。

これらは最初の要素:firstなので、数による指定はエラーとなります。

最後の要素:last-child・last-of-type

これら:last-child:last-of-typeは最後の要素に反応します。基本的な考え方は最初の要素firstと同じです。視点が上からではなく、下からに変わるだけです。

ついでに紹介しましたが、これは使わない…かもしれません。

奇数の要素:nth-child(odd)・nth-of-type(odd)

1. :nth-child(odd)
説明:親要素から見て1, 3, 5…番目の子要素に反応。

活用例:リスト(li)の背景色を1行おきに薄いグレーにしてストライプデザインにするのに最適です。

2. :nth-of-type(odd)
説明:指定したタグの中で1, 3, 5…番目に出てくるものに反応。これは厄介に感じますが、動作としては至ってシンプルです。

p:nth-of-type(odd) の動き(シミュレーション)

例えば、記事本文にこんな順番で要素が並んでいたとします。

  1. <p>(文章1) ➔ 【ターゲット!】(pの中で1番目=奇数)
  2. <h3>(見出し) ➔ (スルー:pじゃないから数えない)
  3. <p>(文章2) ➔ (スルー:pの中で2番目=偶数)
  4. <img>(画像) ➔ (スルー:pじゃないから数えない)
  5. <p>(文章3) ➔ 【ターゲット!】(pの中で3番目=奇数)

nth-child(odd)
1番目(p)、3番目(p)、5番目(p)……と、全体の奇数番目のpタグだけに反応します。

nth-of-type(odd)
間に何が挟まっていようと関係ありません。pタグという仲間だけを呼び集めて、その列の中で「1、3、5……」と数えていきます。

偶数の要素:nth-child(even)・nth-of-type(even)

これら:nth-child(even):nth-of-type(even)は偶数に反応します。基本的な挙動は、奇数(odd)と変わりません。対象が「2, 4, 6…番目」にスライドするだけですので、細かな説明は致しません。

上からn番目の要素:nth-child(n)・nth-of-type(n)

1. :nth-child(n)
説明:上から何番目かだけを数えて反応。

活用例:リスト(li)のように、同じ種類のタグが綺麗に並んでいる場所で、純粋に順番だけを操作したいときに最適です。これはよく使いますし重宝します。

p:nth-child(3) の様な指定で上から3番目の子要素がpではなかった場合は何も反応しません。その時は自分の想定と実際のHTMLの構造にズレが生じていますし、そのズレを発見出来た瞬間でもあります。

2. :nth-of-type(n)
説明:指定したタグだけを上から数えて反応。間に別のタグが挟まっていても、それはカウント外として無視します。

特徴:指定したタグが何処にいようと確実に見つけ出します。

下からn番目の要素:nth-last-child(n) ・ nth-last-of-type(n)


上からではなく、単純に一番下からになっただけです。

  • :nth-last-child(1) ➔ 一番最後の要素(:last-childと同じ)
  • :nth-last-of-type(2) ➔ その種類のタグの中で、最後から2番目。

指定した要素以外:not

nth-childfirst-of-typeが特定のタグを指定するものであったのに対し、:not はそれ以外すべてに反応します。

main#main .article p:not(:first-child) {
    margin-top: 5px;
}

上記のCSSはまずmain#main .articleの中のpタグが対象としています。
そして:notは一番最初(:first-child)のp以外のpにmargin-top: 5px;の命令を下します。

こういった変則的な疑似クラスには:is()(どれか一つでも当てはまればOK)のものや、:is()とおなじだけど、力を持たない:where()もあります。

更に:has() など、(「〜を持っている」〇〇)といったものもあります。

例:li:has(a:first-child)
説明:最初の子要素『aタグ』を持っている li だけに反応。

基礎編を熟して装飾に色どりを

自分のWebサイトで試すのが少し嫌だと感じたら、以前に書いた記事検証画面で足掻くのはもう終わり?CodePenという『爆速実験場』に感動した話でも紹介したCodePenなんかで適当にリストのHTMLとCSSを書いて試したら良いと思います。

勿論、無理して使う必要は無いですが、リストなんかの背景色を奇数偶数で色付けしてあげると、それだけで雰囲気が変わって見えるのでおすすめではあります。

次にこのタイトルを引き継ぐときは応用編になります。

コメント