Earlier this yr, I self-published an e book referred to as Understanding JavaScript Guarantees (free for obtain). Regardless that I didn’t have any intention of turning it right into a print guide, sufficient folks reached out inquiring a few print model that I made a decision to self-publish that as effectively .I believed it could be a straightforward train utilizing HTML and CSS to generate a PDF after which ship it off to the printer. What I didn’t notice was that I didn’t have a solution to an essential a part of a print guide: the desk of contents.
The make-up of a desk of contents
At its core, a desk of contents is pretty easy. Every line represents part of a guide or webpage and signifies the place you’ll find that content material. Sometimes, the traces comprise three components:
The title of the chapter or sectionLeaders (i.e. these dots, dashes, or traces) that visually join the title to the web page numberThe web page quantity
A desk of contents is simple to generate within phrase processing instruments like Microsoft Phrase or Google Docs, however as a result of my content material was in Markdown after which remodeled into HTML, that wasn’t an excellent choice for me. I needed one thing automated that may work with HTML to generate the desk of contents in a format that was appropriate for print. I additionally needed every line to be a hyperlink so it may very well be utilized in webpages and PDFs to navigate across the doc. I additionally needed dot leaders between the title and web page quantity.
And so I started researching.
I got here throughout two wonderful weblog posts on making a desk of contents with HTML and CSS. The primary was “Construct a Desk of Contents out of your HTML” by Julie Blanc. Julie labored on PagedJS, a polyfill for lacking paged media options in internet browsers that correctly codecs paperwork for print. I began with Julie’s instance, however discovered that it didn’t fairly work for me. Subsequent, I discovered Christoph Grabo’s “Responsive TOC chief traces with CSS” submit, which launched the idea of utilizing CSS Grid (versus Julie’s float-based strategy) to make alignment simpler. As soon as once more, although, his strategy wasn’t fairly proper for my functions.
After studying these two posts, although, I felt I had a adequate understanding of the structure points to embark alone. I used items from each weblog posts in addition to including some new HTML and CSS ideas into the strategy to provide you with a consequence I’m proud of.
Selecting the proper markup
When deciding on the proper markup for a desk of contents, I believed primarily in regards to the appropriate semantics. Basically, a desk of contents is a few title (chapter or subsection) being tied to a web page quantity, nearly like a key-value pair. That led me to 2 choices:
One choice is to make use of a desk (<desk>) with one column for the title and one column for the web page.Then there’s the customarily unused and forgotten definition record (<dl>) component. It additionally acts as a key-value map. So, as soon as once more, the connection between the title and the web page quantity can be apparent.
Both of those appeared like good choices till I noticed that they actually solely work for single-level tables of contents, particularly, provided that I needed to have a desk of contents with simply chapter names. If I needed to point out subsections within the desk of contents, although, I didn’t have any good choices. Desk components aren’t nice for hierarchical information, and whereas definition lists can technically be nested, the semantics didn’t appear appropriate. So, I went again to the drafting board.
I made a decision to construct off of Julie’s strategy and use an inventory; nonetheless, I opted for an ordered record (<ol>) as a substitute of an unordered record (<ul>). I feel an ordered record is extra acceptable on this case. A desk of contents represents an inventory of chapters and subheadings within the order wherein they seem within the content material. The order issues and shouldn’t get misplaced within the markup.
Sadly, utilizing an ordered record means dropping the semantic relationship between the title and the web page quantity, so my subsequent step was to re-establish that relationship inside every record merchandise. The simplest solution to remedy that is to easily insert the phrase “web page” earlier than the web page quantity. That approach, the connection of the quantity relative to the textual content is obvious, even with out every other visible distinction.
Right here’s a easy HTML skeleton that fashioned the idea of my markup:
<ol class=”toc-list”>
<li>
<a href=”#link_to_heading”>
<span class=”title”>Chapter or subsection title</span>
<span class=”web page”>Web page 1</span>
</a>
<ol>
<!– subsection gadgets –>
</ol>
</li>
</ol>
Making use of kinds to the desk of contents
As soon as I had established the markup I deliberate to make use of, the following step was to use some kinds.
First, I eliminated the autogenerated numbers. You possibly can select to maintain the autogenerated numbers in your personal mission when you’d like, nevertheless it’s frequent for books to have unnumbered forewords and afterwords included within the record of chapters, which makes the autogenerated numbers incorrect.
For my objective, I might fill within the chapter numbers manually then alter the structure so the top-level record doesn’t have any padding (thus aligning it with paragraphs) and every embedded record is indented by two areas. I selected to make use of a 2ch padding worth as a result of I nonetheless wasn’t fairly positive which font I might use. The ch size unit permits the padding to be relative to the width of a personality — it doesn’t matter what font is used — reasonably than an absolute pixel measurement that might wind up trying inconsistent.
Right here’s the CSS I ended up with:
.toc-list, .toc-list ol {
list-style-type: none;
}
.toc-list {
padding: 0;
}
.toc-list ol {
padding-inline-start: 2ch;
}
Sara Soueidan identified to me that WebKit browsers take away record semantics when list-style-type is none, so I wanted so as to add function=”record” into the HTML to protect it:
<ol class=”toc-list” function=”record”>
<li>
<a href=”#link_to_heading”>
<span class=”title”>Chapter or subsection title</span>
<span class=”web page”>Web page 1</span>
</a>
<ol function=”record”>
<!– subsection gadgets –>
</ol>
</li>
</ol>
Styling the title and web page quantity
With the record styled to my liking, it was time to maneuver on to styling a person record merchandise. For every merchandise within the desk of contents, the title and web page quantity should be on the identical line, with the title to the left and the web page quantity aligned to the appropriate.
You is likely to be pondering, “No drawback, that’s what flexbox is for!” You aren’t mistaken! Flexbox can certainly obtain the proper title-page alignment. However there are some difficult alignment points when the leaders are added, so I as a substitute opted to go together with Christoph’s strategy utilizing a grid, which as a bonus because it additionally helps with multiline titles. Right here is the CSS for a person merchandise:
.toc-list li > a {
text-decoration: none;
show: grid;
grid-template-columns: auto max-content;
align-items: finish;
}
.toc-list li > a > .web page {
text-align: proper;
}
The grid has two columns, the primary of which is auto-sized to replenish your entire width of the container, minus the second column, which is sized to max-content. The web page quantity is aligned to the appropriate, as is conventional in a desk of contents.
The one different change I made at this level was to cover the “Web page” textual content. That is useful for display screen readers however pointless visually, so I used a conventional visually-hidden class to cover it from view:
.visually-hidden {
clip: rect(0 0 0 0);
clip-path: inset(100%);
peak: 1px;
overflow: hidden;
place: absolute;
width: 1px;
white-space: nowrap;
}
And, in fact, the HTML must be up to date to make use of that class:
<ol class=”toc-list” function=”record”>
<li>
<a href=”#link_to_heading”>
<span class=”title”>Chapter or subsection title</span>
<span class=”web page”><span class=”visually-hidden”>Web page</span> 1</span>
</a>
<ol function=”record”>
<!– subsection gadgets –>
</ol>
</li>
</ol>
With this basis in place, I moved on to deal with the leaders between the title and the web page.
Creating dot leaders
Leaders are so frequent in print media that you simply is likely to be questioning, why doesn’t CSS already help that? The reply is: it does. Properly, form of.
There’s truly a pacesetter() operate outlined within the CSS Generated Content material for Paged Media specification. Nonetheless, as with a lot of the paged media specs, this operate isn’t applied in any browsers, due to this fact excluding it as an choice (no less than on the time I’m penning this). It’s not even listed on caniuse.com, presumably as a result of nobody has applied it and there are not any plans or indicators that they may.
Thankfully, each Julie and Christoph already addressed this drawback of their respective posts. To insert the dot leaders, they each used a ::after pseudo-element with its content material property set to a really lengthy string of dots, like this:
.toc-list li > a > .title {
place: relative;
overflow: hidden;
}
.toc-list li > a .title::after {
place: absolute;
padding-left: .25ch;
content material: ” . . . . . . . . . . . . . . . . . . . “
“. . . . . . . . . . . . . . . . . . . . . . . “
“. . . . . . . . . . . . . . . . . . . . . . . “
“. . . . . . . . . . . . . . . . . . . . . . . “
“. . . . . . . . . . . . . . . . . . . . . . . “
“. . . . . . . . . . . . . . . . . . . . . . . “
“. . . . . . . . . . . . . . . . . . . . . . . “;
text-align: proper;
}
The ::after pseudo-element is ready to an absolute place to take it out of the movement of the web page and keep away from wrapping to different traces. The textual content is aligned to the appropriate as a result of we wish the final dots of every line flush to the quantity on the finish of the road. (Extra on the complexities of this later.) The .title component is ready to have a relative place so the ::after pseudo-element doesn’t escape of its field. In the meantime, the overflow is hidden so all these further dots invisible. The result’s a fairly desk of contents with dot leaders.
Nonetheless, there’s one thing else that wants consideration.
Sara additionally identified to me that each one of these dots depend as textual content to display screen readers. So what do you hear? “Introduction dot dot dot dot…” till the entire dots are introduced. That’s an terrible expertise for display screen reader customers.
The answer is to insert an extra component with aria-hidden set to true after which use that component to insert the dots. So the HTML turns into:
<ol class=”toc-list” function=”record”>
<li>
<a href=”#link_to_heading”>
<span class=”title”>Chapter or subsection title<span class=”leaders” area-hidden=”true”></span></span>
<span class=”web page”><span class=”visually-hidden”>Web page</span> 1</span>
</a>
<ol function=”record”>
<!– subsection gadgets –>
</ol>
</li>
</ol>
And the CSS turns into:
.toc-list li > a > .title {
place: relative;
overflow: hidden;
}
.toc-list li > a .leaders::after {
place: absolute;
padding-left: .25ch;
content material: ” . . . . . . . . . . . . . . . . . . . “
“. . . . . . . . . . . . . . . . . . . . . . . “
“. . . . . . . . . . . . . . . . . . . . . . . “
“. . . . . . . . . . . . . . . . . . . . . . . “
“. . . . . . . . . . . . . . . . . . . . . . . “
“. . . . . . . . . . . . . . . . . . . . . . . “
“. . . . . . . . . . . . . . . . . . . . . . . “;
text-align: proper;
}
Now display screen readers will ignore the dots and spare customers the frustration of listening to a number of dots being introduced.
Ending touches
At this level, the desk of contents element seems fairly good, nevertheless it might use some minor element work. To begin, most books visually offset chapter titles from subsection titles, so I made the top-level gadgets daring and launched a margin to separate subsections from the chapters that adopted:
.toc-list > li > a {
font-weight: daring;
margin-block-start: 1em;
}
Subsequent, I needed to wash up the alignment of the web page numbers. The whole lot seemed okay after I was utilizing a fixed-width font, however for variable-width fonts, the chief dots might find yourself forming a zigzag sample as they alter to the width of a web page quantity. As an example, any web page quantity with a 1 can be narrower than others, leading to chief dots which might be misaligned with the dots on earlier or following traces.
To repair this drawback, I set font-variant-numeric to tabular-nums so all numbers are handled with the identical width. By additionally setting the minimal width to 2ch, I ensured that each one numbers with one or two digits are completely aligned. (Chances are you’ll wish to set this to 3ch in case your mission has greater than 100 pages.) Right here is the ultimate CSS for the web page quantity:
.toc-list li > a > .web page {
min-width: 2ch;
font-variant-numeric: tabular-nums;
text-align: proper;
}
And with that, the desk of contents is full!
Conclusion
Making a desk of contents with nothing however HTML and CSS was extra of a problem than I anticipated, however I’m very proud of the consequence. Not solely is that this strategy versatile sufficient to accommodate chapters and subsections, nevertheless it handles sub-subsections properly with out updating the CSS. The general strategy works on internet pages the place you wish to hyperlink to the assorted places of content material, in addition to PDFs the place you need the desk of contents to hyperlink to totally different pages. And naturally, it additionally seems nice in print when you’re ever inclined to make use of it in a brochure or guide.
I’d prefer to thank Julie Blanc and Christoph Grabo for his or her wonderful weblog posts on making a desk of contents, as each of these had been invaluable after I was getting began. I’d additionally prefer to thank Sara Soueidan for her accessibility suggestions as I labored on this mission.
A Excellent Desk of Contents With HTML + CSS initially revealed on CSS-Methods. It is best to get the publication.
Subscribe to MarketingSolution.
Receive web development discounts & web design tutorials.
Now! Lets GROW Together!