【実務・中級編】リストのネスト構造とインデントの制御 – HTML実践ガイド

はい、承知いたしました。HTMLのリスト構造、特にネスト構造とそのインデント制御について、実務経験豊富なシニアフロントエンドエンジニアの視点から、現場で役立つ実践的な解説とコード例を交えてブログ記事を執筆します。

—

HTMLリストのネスト構造とインデント制御:見た目と意味論を両立させる実践テクニック

やあ、みんな!フロントエンド開発の現場で日々格闘している君たちへ。今日は、一見地味だけど、実はWebサイトの構造と見た目を大きく左右する「リスト」の話をしよう。特に、`

    ` や `

      ` の中にさらにリストを入れ子にする「ネスト構造」と、それに伴う「インデント」の制御について、実務で役立つポイントを掘り下げていくよ。

      公式マニュアルをなぞるだけじゃ、現場の「なぜ?」には答えられない。ブラウザが裏側で何をやっているのか、そしてどうすれば「綺麗で意味のある」リストが作れるのか。そんな、ちょっと踏み込んだ話を、いつものように泥臭く、でも頼りがいのある感じで解説していくから、コーヒーでも片手にリラックスして読んでほしい。

      リストのネスト構造:DOMツリーで何が起こっているのか?

      まずは基本から。HTMLでリストをネストするというのは、単純に `

        ` の中に `

          ` を、あるいは `

            ` の中に `

              ` を配置することだ。例えば、こんな感じだね。

              • 親リスト項目1
              • 親リスト項目2

                • 子リスト項目2-1
                • 子リスト項目2-2
              • 親リスト項目3

              このコードを見て、ブラウザがどうやってDOM(Document Object Model)ツリーを構築しているか想像できるかな?

              1. `

                ` 要素の出現: ブラウザは、最初の `

                  ` を発見し、それをDOMツリーのノードとして認識します。
                  2. `

                • ` 要素の出現: その中の `
                • ` 要素は、親の `
                    ` の子ノードとして追加されます。
                    3. ネストされた `

                      ` の出現: 2番目の `

                    • ` の中に、さらに `
                        ` が現れる。ここでブラウザは「おや?」となります。これは、親の `

                          ` の子ノードではなく、現在の `

                        • ` 要素の子ノードとして、新しい `
                            ` を認識するのです。
                            4. 子 `

                              ` の `

                            • `: その子 `
                                ` の中の `

                              • ` は、その子 `
                                  ` の子ノードとしてツリーに組み込まれます。

                                  つまり、DOMツリー上では、ネストされたリストは親リスト項目の「中」にぶら下がる形になる。これが、見た目のインデントにどう影響するかは、後でCSSの話で詳しく触れるとして、まずはこの「親子関係」が重要だということを頭に入れておいてほしい。

                                  ブラウザのデフォルト挙動:インデントとマーカーの謎

                                  さて、このネスト構造をブラウザにそのまま描画させると、どうなるだろうか?

                                  多くのブラウザでは、デフォルトで以下のような挙動をする。

                                  • インデント: ネストが深くなるにつれて、自動的に右にインデントされる。
                                  • マーカー:
                                  • `
                                      ` の場合:外側は「●」、内側は「○」、さらに内側は「■」… のように、階層ごとに異なるマーカー(ディスク、サークル、スクエアなど)が自動的に割り当てられることが多い。
                                    • `
                                        ` の場合:外側は「1.」、内側は「a.」、さらに内側は「i.」… のように、階層ごとに番号や記号が変わる。

                                    これは、ユーザーがリストの階層構造を視覚的に理解しやすくするための、ブラウザの親切な配慮なんだ。HTMLのセマンティクス(意味論)を、視覚表現で補ってくれているわけだね。

                                    しかし、ここで現場のエンジニアとして「ちょっと待った!」と言いたくなるポイントがいくつかある。

                                    1. デザインとの乖離: デザインカンプ通りにしたいのに、デフォルトのインデントやマーカーが邪魔になることがある。
                                    2. マーカーの統一性: サイト全体でマーカーのスタイルを統一したいのに、ネストによって勝手に変わってしまうのは困る。
                                    3. セマンティクスと見た目の不一致: ブラウザのデフォルト挙動は便利だけど、必ずしもデザインの意図と合致するとは限らない。

                                    だからこそ、僕たちはCSSを使って、このデフォルト挙動を「制御」する必要があるんだ。

                                    CSSによるインデントとマーカーの制御:現場で使えるテクニック集

                                    ここからが本番だ。CSSを使って、リストの見た目を自在に操る方法を見ていこう。

                                    1. インデントの制御 (`padding` と `margin`)

                                    インデントの基本は、`padding` と `margin` を使うことだ。特に、リスト項目(`

                                  • `)に適用されるブラウザのデフォルトの `padding-left` を調整するのが一般的だ。

                                    例えば、すべてのリストのインデントをリセットし、自分で好きなように設定したい場合。

                                    / 全てのリスト要素のデフォルトスタイルをリセット(注意:サイト全体に適用する場合は慎重に) /
                                    ul, ol {
                                    margin: 0;
                                    padding: 0;
                                    list-style: none; / マーカーも一旦リセット /
                                    }

                                    / リスト項目(li)のインデントを自分で設定 /
                                    li {
                                    / 例:左に20pxのパディングを追加 /
                                    padding-left: 20px;
                                    / 必要に応じてマージンも調整 /
                                    margin-bottom: 5px;
                                    }

                                    / ネストされたリスト(ul > ul, ol > ol)には、さらにインデントを追加 /
                                    / 最初のネストレベル /
                                    ul ul,
                                    ol ol {
                                    padding-left: 20px; / 親のliのpadding-leftとは別に、さらにインデント /
                                    margin-top: 5px; / 親項目との区切り /
                                    }

                                    / さらにネストが深くなった場合(例:3階層目) /
                                    ul ul ul,
                                    ol ol ol {
                                    padding-left: 20px; / さらにインデント /
                                    }

                                    / 特定のリスト(例:class=”no-indent”)のインデントをなくす場合 /
                                    .no-indent li {
                                    padding-left: 0;
                                    }
                                    .no-indent ul,
                                    .no-indent ol {
                                    padding-left: 0;
                                    }

                                    ポイント:

                                    • `list-style: none;` でデフォルトのマーカーを消してから、`padding` でインデントを確保するのが定石。
                                    • ネストされたリスト (`ul ul`, `ol ol`) に対して、さらに `padding-left` を追加することで、階層ごとのインデントを表現する。
                                    • `margin-top` を使って、親リスト項目と子リスト項目の間に適切なスペースを設けることも重要。

                                    2. マーカーの制御 (`list-style`, `::before` 疑似要素)

                                    デフォルトのマーカーが気に入らない、あるいは自分でデザインしたい場合は、`list-style` プロパティを使うか、`::before` 疑似要素で自作するのが一般的だ。

                                    a. `list-style` プロパティを使った方法

                                    `list-style` プロパティには、`list-style-type`(マーカーの種類)、`list-style-position`(マーカーの位置)、`list-style-image`(画像)などのショートハンドがあります。

                                    / 基本的なリストのマーカーを円にする /
                                    ul {
                                    list-style-type: disc; / デフォルト /
                                    }

                                    / ネストされたリストのマーカーを四角にする /
                                    ul ul {
                                    list-style-type: square;
                                    }

                                    / さらにネストが深くなったら、円に戻す(例) /
                                    ul ul ul {
                                    list-style-type: disc;
                                    }

                                    / 番号付きリストの場合 /
                                    ol {
                                    list-style-type: decimal; / 1, 2, 3… /
                                    }

                                    ol ol {
                                    list-style-type: lower-alpha; / a, b, c… /
                                    }

                                    ol ol ol {
                                    list-style-type: lower-roman; / i, ii, iii… /
                                    }

                                    / マーカーをリスト項目の内側に配置 /
                                    ul, ol {
                                    list-style-position: inside;
                                    }

                                    `list-style-position: inside;` の注意点:
                                    これはマーカーを `

                                  • ` のテキストと同じ行に表示する。`padding-left` でインデントを確保している場合、マーカーがテキストの直前に来てしまうため、見た目の調整が難しくなることがある。通常は `outside` (デフォルト) のまま、`padding` でインデントを確保するのが扱いやすい。

                                    b. `::before` 疑似要素を使ったカスタムマーカー

                                    より自由なデザインを実現したいなら、`::before` 疑似要素で自作するのが最強だ。

                                    • 親項目1
                                    • 親項目2

                                      • 子項目2-1
                                      • 子項目2-2
                                    • 親項目3

                                    この `::before` 疑似要素を使う方法のメリット:

                                    • 自由なデザイン: 文字、記号、アイコン(Font Awesomeなど)、SVGまで、何でもマーカーとして配置できる。
                                    • 階層ごとの制御が容易: セレクタ (`.custom-list > li`, `.custom-list ul li` など) を使って、階層ごとに異なるマーカーやスタイルを適用しやすい。
                                    • インデントとの分離: `padding-left` でインデントを確保し、`::before` でマーカーを配置することで、見た目の調整がしやすい。`position: absolute;` を使うのがコツ。

                                    `::before` を使う上での注意点:

                                    • セマンティクス: `::before` で表示される内容は、あくまで装飾(視覚情報)であり、HTMLの構造的な意味論には影響しない。スクリーンリーダーなどは、この `::before` の内容を読み上げない場合がある。もし、マーカー自体が重要な意味を持つ場合は、HTML要素(例えば `` など)でマークアップし、それを `::before` の代わりに使うなどの工夫が必要になることもある。
                                    • セレクタの複雑化: ネストが深くなるほど、セレクタが複雑になりがち。BEMなどの命名規則や、CSS設計思想を意識して、管理しやすいコードを心がけよう。

                                    実践的なサンプルコード:よくある「目次」のようなリスト

                                    例えば、Webサイトの「目次」や「ナビゲーションメニュー」のように、階層構造を持ちつつ、見た目も整えたいケースは多い。

                                    このサンプルでは、`::before` を `` タグに直接適用し、`position: absolute;` を使ってインデントとマーカーを分離しています。こうすることで、リンクテキストの横にマーカーが綺麗に配置され、さらにインデントも確保されるという、見た目と使いやすさを両立した構造になっています。

                                    まとめ:意味論と見た目のバランスを考える

                                    リストのネスト構造とインデント制御は、単に見た目を整えるだけでなく、HTMLのセマンティクスを正しく理解し、それをCSSでどう表現するか、というフロントエンド開発の根幹に関わるテーマです。

                                    • HTMLで構造と意味を: まずは、`
                                        ` と `

                                          ` を適切に使って、情報の階層構造を正しくマークアップすること。
                                        1. CSSで見た目を: 次に、CSSを使って、デフォルトのインデントやマーカーを必要に応じて調整し、デザイン要件とブラウザの挙動をコントロールする。
                                        2. `padding` と `::before` を使いこなす: インデントには `padding`、カスタムマーカーには `::before` 疑似要素が強力な味方になる。
                                        3. セマンティクスを忘れずに: 特に `::before` を使う際は、それが単なる装飾なのか、それとも意味を持つ情報なのかを意識することが重要。

                                      現場では、デザインの要求、アクセシビリティ、そしてメンテナンス性… 様々な要素を考慮しながら、最適なバランスを見つける必要があります。今回紹介したテクニックが、君たちの開発の一助となれば嬉しいよ。

                                      質問や「こんなケースはどうする?」なんてことがあれば、いつでも気軽に聞いてくれ。また次の記事で会おう!

コメント

タイトルとURLをコピーしました