HTML +CSSPlatoBlockchainデータインテリジェンスを備えた完璧な目次。 垂直検索。 愛。

HTML+CSSを使用した完璧な目次

今年の初めに、私はという電子ブックを自費出版しました JavaScriptの約束を理解する (無料でダウンロード)。 印刷本にするつもりはなかったのですが、印刷版について問い合わせがあったので、自費出版することにしました。HTMLやCSSを使って簡単に作れると思いました。 PDFを生成し、それをプリンターに送信します。 私が気づかなかったのは、印刷物の重要な部分である目次に対する答えがなかったということでした。

目次の構成

基本的に、目次はかなり単純です。 各行は、本またはWebページの一部を表し、そのコンテンツを見つけることができる場所を示します。 通常、行には次のXNUMXつの部分が含まれます。

  1. 章またはセクションのタイトル
  2. タイトルをページ番号に視覚的に接続するリーダー(つまり、点、破線、または線)
  3. ページ番号

目次は、MicrosoftWordやGoogleDocsなどのワードプロセッシングツール内で簡単に生成できますが、コンテンツがMarkdownにあり、HTMLに変換されたため、これは適切なオプションではありませんでした。 HTMLと連携して、印刷に適した形式で目次を生成する自動化されたものが必要でした。 また、各行をリンクにして、WebページやPDFでドキュメント内を移動できるようにしたかったのです。 また、タイトルとページ番号の間にドットリーダーが必要でした。

それで私は研究を始めました。

HTMLとCSSを使用した目次の作成に関するXNUMXつの優れたブログ投稿に出くわしました。 最初は 「HTMLから目次を作成する」 ジュリー・ブラン著。 ジュリーは PagedJS、印刷用にドキュメントを適切にフォーマットするWebブラウザで欠落しているページメディア機能のポリフィル。 ジュリーの例から始めましたが、うまくいかなかったことがわかりました。 次に、クリストフ・グラボの 「CSSを使用したレスポンシブTOCリーダーライン」 投稿。CSSグリッドを使用して(ジュリーのフロートベースのアプローチとは対照的に)位置合わせを簡単にするという概念を紹介しました。 しかし、繰り返しになりますが、彼のアプローチは私の目的には完全に適切ではありませんでした。

しかし、これらXNUMXつの投稿を読んだ後、私は自分で着手するのに十分なレイアウトの問題を理解していると感じました。 私は両方のブログ投稿の一部を使用し、アプローチにいくつかの新しいHTMLとCSSの概念を追加して、満足のいく結果を出しました。

正しいマークアップの選択

目次の正しいマークアップを決定するとき、私は主に正しいセマンティクスについて考えました。 基本的に、目次は、ほとんどキーと値のペアのように、ページ番号に関連付けられたタイトル(章またはサブセクション)に関するものです。 それは私をXNUMXつの選択肢に導きました:

  • XNUMXつのオプションは、テーブルを使用することです(<table>)タイトル用にXNUMX列、ページ用にXNUMX列。
  • 次に、よく使用されない、忘れられる定義リストがあります(<dl>) エレメント。 また、Key-Valueマップとしても機能します。 したがって、ここでも、タイトルとページ番号の関係は明らかです。

これらのいずれも、実際には単一レベルの目次でのみ機能することに気付くまで、つまり、章名だけの目次が必要な場合にのみ、適切なオプションのように見えました。 ただし、目次にサブセクションを表示したい場合は、適切なオプションがありませんでした。 テーブル要素は階層データには適していません、および定義リストは技術的にネストできますが、セマンティクスは正しくないようです。 それで、私は製図板に戻りました。

私はジュリーのアプローチを基にしてリストを使用することにしました。 しかし、私は順序付きリストを選びました(<ol>)順序付けられていないリストの代わりに(<ul>)。 この場合、順序付きリストの方が適切だと思います。 目次は、章と小見出しのリストを、コンテンツに表示される順序で表しています。 順序は重要であり、マークアップで失われるべきではありません。

残念ながら、順序付きリストを使用すると、タイトルとページ番号の間の意味的な関係が失われるため、次のステップは、各リストアイテム内でその関係を再確立することでした。 これを解決する最も簡単な方法は、ページ番号の前に「ページ」という単語を挿入することです。 そうすれば、他の視覚的な区別がなくても、テキストに対する数字の関係が明確になります。

これが私のマークアップの基礎を形成した単純なHTMLスケルトンです:

<ol class="toc-list"> <li> <a href="#link_to_heading"> <span class="title">Chapter or subsection title</span> <span class="page">Page 1</span> </a> <ol> <!-- subsection items --> </ol> </li>
</ol>

目次にスタイルを適用する

使用する予定のマークアップを確立したら、次のステップはいくつかのスタイルを適用することでした。

まず、自動生成された番号を削除しました。 必要に応じて、自動生成された番号を独自のプロジェクトに保持することもできますが、本の章のリストに番号のない序文と後語が含まれているのが一般的であり、自動生成された番号が正しくありません。

私の目的では、章番号を手動で入力してからレイアウトを調整し、最上位のリストにパディングがなく(したがって、段落に揃えて)、埋め込まれた各リストがXNUMXつのスペースでインデントされるようにします。 私は使用することを選択しました 2ch どのフォントを使用するかまだよくわからなかったため、値をパディングします。 The ch 長さの単位を使用すると、使用するフォントに関係なく、一貫性のないように見える絶対ピクセルサイズではなく、文字の幅を基準にしてパディングを行うことができます。

これが私が最終的に得たCSSです:

.toc-list, .toc-list ol { list-style-type: none;
} .toc-list { padding: 0;
} .toc-list ol { padding-inline-start: 2ch;
}

サラ・スエイダン WebKitブラウザは次の場合にリストのセマンティクスを削除することを私に指摘しました list-style-type is none、追加する必要がありました role="list" それを保存するためにHTMLに:

<ol class="toc-list" role="list"> <li> <a href="#link_to_heading"> <span class="title">Chapter or subsection title</span> <span class="page">Page 1</span> </a> <ol role="list"> <!-- subsection items --> </ol> </li>
</ol>
CodePen埋め込みフォールバック

タイトルとページ番号のスタイリング

リストのスタイルを自分の好みに合わせて、個々のリストアイテムのスタイルに移りましょう。 目次の各項目について、タイトルとページ番号は同じ行にあり、タイトルは左側に、ページ番号は右側に配置されている必要があります。

「問題ありません、それがフレックスボックスの目的です!」とお考えかもしれません。 あなたは間違っていません! Flexboxは確かに正しいタイトルページの配置を実現できます。 しかし、リーダーが追加されるときにいくつかのトリッキーな配置の問題があるので、代わりにグリッドを使用するクリストフのアプローチを選択しました。これは、複数行のタイトルにも役立つので、ボーナスとして使用します。 個々のアイテムのCSSは次のとおりです。

.toc-list li > a { text-decoration: none; display: grid; grid-template-columns: auto max-content; align-items: end;
} .toc-list li > a > .page { text-align: right;
}

グリッドにはXNUMXつの列があり、最初の列は auto-コンテナの幅全体を埋めるサイズからXNUMX番目の列を引いたサイズ。 max-content。 ページ番号は、目次によくあるように、右側に配置されます。

この時点で私が行った他の唯一の変更は、「ページ」テキストを非表示にすることでした。 これはスクリーンリーダーには役立ちますが、視覚的には不要なので、 伝統的な visually-hidden class ビューから非表示にするには:

.visually-hidden { clip: rect(0 0 0 0); clip-path: inset(100%); height: 1px; overflow: hidden; position: absolute; width: 1px; white-space: nowrap;
}

そしてもちろん、そのクラスを使用するにはHTMLを更新する必要があります。

<ol class="toc-list" role="list"> <li> <a href="#link_to_heading"> <span class="title">Chapter or subsection title</span> <span class="page"><span class="visually-hidden">Page</span> 1</span> </a> <ol role="list"> <!-- subsection items --> </ol> </li>
</ol>

この基盤が整ったので、私はタイトルとページの間のリーダーに話しかけることに移りました。

CodePen埋め込みフォールバック

ドットリーダーの作成

リーダーは印刷媒体では非常に一般的であるため、疑問に思われるかもしれませんが、CSSがすでにそれをサポートしていないのはなぜですか? 答えは次のとおりです。 します。 まあ、一種。

実際にあります leader() で定義された関数 ページメディア仕様のCSS生成コンテンツ。 ただし、多くのページメディア仕様と同様に、この関数はどのブラウザーにも実装されていないため、オプションとして除外されています(少なくともこれを書いている時点では)。 それもリストされていません caniuse.comおそらく、誰もそれを実装しておらず、実行する計画やシグナルがないためです。

幸いなことに、ジュリーとクリストフはそれぞれの投稿ですでにこの問題に取り組んでいます。 ドットリーダーを挿入するために、両方とも ::after その疑似要素 content 次のように、プロパティを非常に長いドットの文字列に設定します。

.toc-list li > a > .title { position: relative; overflow: hidden;
} .toc-list li > a .title::after { position: absolute; padding-left: .25ch; content: " . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . "; text-align: right;
}

  ::after 疑似要素は絶対位置に設定され、ページのフローから外れ、他の行への折り返しを回避します。 各行の最後のドットを行末の数字と同じ高さにするため、テキストは右揃えになります。 (これの複雑さについては後で詳しく説明します。) .title 要素は相対位置を持つように設定されているため、 ::after 疑似要素は、その箱から出ることはありません。 一方、 overflow は非表示になっているため、余分なドットはすべて非表示になります。 結果は、ドットリーダーを含むきれいな目次です。

ただし、他にも考慮が必要なことがあります。

サラはまた、これらのドットはすべてスクリーンリーダーへのテキストとしてカウントされることを私に指摘しました。 それで、あなたは何を聞きますか? すべてのドットが発表されるまで「はじめにドットドットドットドット…」。 これは、スクリーンリーダーのユーザーにとってはひどい体験です。

解決策は、次の要素を追加で挿入することです。 aria-hidden に設定 true 次に、その要素を使用してドットを挿入します。 したがって、HTMLは次のようになります。

<ol class="toc-list" role="list"> <li> <a href="#link_to_heading"> <span class="title">Chapter or subsection title<span class="leaders" aria-hidden="true"></span></span> <span class="page"><span class="visually-hidden">Page</span> 1</span> </a> <ol role="list"> <!-- subsection items --> </ol> </li>
</ol>

そしてCSSは次のようになります。

.toc-list li > a > .title { position: relative; overflow: hidden;
} .toc-list li > a .leaders::after { position: absolute; padding-left: .25ch; content: " . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . "; text-align: right;
}

これで、スクリーンリーダーはドットを無視し、アナウンスされている複数のドットを聞くことへのフラストレーションをユーザーに与えないようになります。

CodePen埋め込みフォールバック

仕上げ

この時点で、目次コンポーネントはかなり見栄えがしますが、細かい作業が必要になる可能性があります。 まず、ほとんどの本は章のタイトルをサブセクションのタイトルから視覚的にオフセットしているので、トップレベルの項目を太字にし、サブセクションを後続の章から分離するためのマージンを導入しました。

.toc-list > li > a { font-weight: bold; margin-block-start: 1em;
}

次に、ページ番号の配置をクリーンアップしたいと思いました。 固定幅フォントを使用しているときはすべて問題ないように見えましたが、可変幅フォントの場合、ページ番号の幅に合わせてリーダードットがジグザグパターンを形成する可能性があります。 たとえば、1のページ番号は他のページ番号よりも狭くなり、リーダーのドットが前の行または次の行のドットとずれてしまいます。

目次内の数字とドットの位置がずれている。
HTML+CSSを使用した完璧な目次

この問題を解決するために、私は font-variant-numeric 〜へ tabular-nums したがって、すべての数値は同じ幅で扱われます。 最小幅もに設定することにより 2ch、XNUMX桁またはXNUMX桁のすべての数字が完全に整列していることを確認しました。 (これをに設定することをお勧めします 3ch プロジェクトに100ページを超える場合。)ページ番号の最終的なCSSは次のとおりです。

.toc-list li > a > .page { min-width: 2ch; font-variant-numeric: tabular-nums; text-align: right;
}
目次のリーダードットを揃えます。
HTML+CSSを使用した完璧な目次

これで目次が完成しました!

CodePen埋め込みフォールバック

まとめ

HTMLとCSSだけで目次を作成することは、私が予想していたよりも困難でしたが、結果には非常に満足しています。 このアプローチは、チャプターとサブセクションに対応するのに十分な柔軟性があるだけでなく、CSSを更新せずにサブサブセクションを適切に処理します。 全体的なアプローチは、コンテンツのさまざまな場所にリンクするWebページ、および目次をさまざまなページにリンクするPDFで機能します。 そしてもちろん、パンフレットや本で使用したい場合は、印刷物でも見栄えがします。

JulieBlancとChristophGraboの目次の作成に関する優れたブログ投稿に感謝します。どちらも、私が始めたときは非常に貴重でした。 また、このプロジェクトに取り組んでいるときに、アクセシビリティに関するフィードバックを寄せてくれたSaraSoueidanにも感謝します。


HTML+CSSを使用した完璧な目次 最初に公開された CSSトリック。 あなたがすべき ニュースレターを入手する.

タイムスタンプ:

より多くの CSSトリック