Ідеальний зміст із HTML + CSS PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.

Ідеальний зміст із HTML + CSS

На початку цього року я самостійно видав електронну книгу під назвою Розуміння обіцянок JavaScript (безкоштовно для скачування). Незважаючи на те, що я не мав наміру перетворювати її на друковану книгу, достатньо людей поцікавилися друкованою версією, яку я також вирішив опублікувати самостійно. Я думав, що це буде легкою вправою з використанням HTML і CSS для створіть PDF-файл, а потім відправте його на принтер. Чого я не розумів, так це того, що не мав відповіді на важливу частину друкованої книги: на зміст.

Склад змісту

По суті, зміст є досить простим. Кожен рядок представляє частину книги або веб-сторінки та вказує, де можна знайти цей вміст. Зазвичай рядки містять три частини:

  1. Назва розділу або розділу
  2. Лідери (тобто точки, тире або лінії), які візуально пов’язують заголовок з номером сторінки
  3. Номер сторінки

Зміст легко створити в таких інструментах обробки текстів, як Microsoft Word або Google Docs, але оскільки мій вміст був у Markdown, а потім перетворений у HTML, це був не найкращий варіант для мене. Я хотів чогось автоматизованого, що працювало б із HTML, щоб генерувати зміст у форматі, придатному для друку. Я також хотів, щоб кожен рядок був посиланням, щоб його можна було використовувати на веб-сторінках і PDF-файлах для навігації по документу. Я також хотів розташовувати точки між заголовком і номером сторінки.

І ось я почав досліджувати.

Я натрапив на дві чудові публікації в блозі про створення змісту за допомогою HTML і CSS. Перший був «Створіть зміст із вашого HTML» від Джулі Блан. Джулі працювала далі PagedJS, полізаповнення для відсутніх сторінкових мультимедійних функцій у веб-браузерах, які правильно форматують документи для друку. Я почав з прикладу Джулі, але виявив, що це не зовсім спрацювало для мене. Далі я знайшов Крістофа Грабо «Чувні лінії лідерів TOC із CSS» пост, який представив концепцію використання CSS Grid (на відміну від підходу Джулі на основі float) для полегшення вирівнювання. Але знову ж таки, його підхід не зовсім відповідав моїм цілям.

Проте, прочитавши ці дві публікації, я відчув, що досить добре розумію проблеми з макетом, щоб почати самостійно. Я використав фрагменти з обох дописів у блозі, а також додав деякі нові концепції HTML і CSS у підхід, щоб отримати результат, яким я задоволений.

Вибір правильної розмітки

Вибираючи правильну розмітку для змісту, я думав насамперед про правильну семантику. По суті, зміст стосується заголовка (розділу чи підрозділу), який прив’язаний до номера сторінки, майже як пара ключ-значення. Це привело мене до двох варіантів:

  • Одним з варіантів є використання таблиці (<table>) з одним стовпцем для заголовка та одним стовпцем для сторінки.
  • Потім є часто невикористовуваний і забутий список визначень (<dl>) елемент. Він також діє як карта "ключ-значення". Отже, знову ж таки, зв’язок між заголовком і номером сторінки буде очевидним.

Будь-який з цих варіантів здавався хорошим, доки я не зрозумів, що вони справді працюють лише для однорівневих змістів, а саме, якщо я хочу мати зміст лише з назвами розділів. Але якщо я хотів показати підрозділи в змісті, у мене не було жодних хороших варіантів. Елементи таблиці не дуже підходять для ієрархічних даних, і хоча списки визначень технічно можуть бути вкладеними, семантика здається неправильною. Отже, я повернувся до креслярської дошки.

Я вирішив використати підхід Джулі та використати список; однак я вибрав упорядкований список (<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>

Застосування стилів до змісту

Як тільки я встановив розмітку, яку планував використовувати, наступним кроком було застосування деяких стилів.

Спочатку я видалив автоматично згенеровані числа. Ви можете зберегти автоматично згенеровані числа у своєму власному проекті, якщо хочете, але зазвичай книги мають ненумеровані передмови та післямови, включені в список розділів, що робить автоматично згенеровані числа неправильними.

Для моєї мети я б заповнював номери розділів вручну, а потім налаштував макет, щоб у списку верхнього рівня не було жодних відступів (таким чином, вирівнюючи його з абзацами), і кожен вбудований список має відступ на два пробіли. Я вирішив використовувати a 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!» Ви не помиляєтесь! 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;
}

Сітка має два стовпці, перший з яких є auto-sized, щоб заповнити всю ширину контейнера, мінус другий стовпець, розмір якого дорівнює max-content. Номер сторінки вирівнюється праворуч, як це традиційно в змісті.

Єдина інша зміна, яку я зробив на цьому етапі, — це приховати текст «Сторінка». Це корисно для програм зчитування з екрана, але непотрібно візуально, тому я використав a традиційний visually-hidden клас щоб приховати його від очей:

.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, мабуть, тому, що ніхто цього не реалізував і немає планів чи сигналів, що вони це зроблять.

На щастя, і Джулі, і Крістоф вже розглянули цю проблему у своїх відповідних публікаціях. Щоб вставити виноски точок, вони обидва використовували a ::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 приховано, тому всі ці додаткові точки невидимі. У результаті виходить гарний зміст з точковими лідерами.

Однак є ще щось, що потребує розгляду.

Сара також вказала мені, що всі ці точки враховуються як текст для програми зчитування з екрана. Так що ти чуєш? «Введення дот dot dot dot…», доки не будуть оголошені всі крапки. Це жахливий досвід для користувачів програми зчитування з екрана.

Рішення – вставити додатковий елемент с 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, я переконався, що всі числа з однією або двома цифрами ідеально вирівняні. (Ви можете встановити для цього значення 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. Загальний підхід працює на веб-сторінках, де потрібно посилатися на різні місця розміщення вмісту, а також на PDF-файлах, де зміст містить посилання на різні сторінки. І, звичайно, він також чудово виглядає у друкованому вигляді, якщо ви коли-небудь схильні використовувати його в брошурі чи книзі.

Я хотів би подякувати Джулі Блан і Крістофу Грабо за їхні чудові публікації в блозі щодо створення змісту, оскільки обидва вони були безцінними, коли я починав роботу. Я також хотів би подякувати Сарі Соуейдан за її відгук про доступність, коли я працював над цим проектом.


Ідеальний зміст із HTML + CSS спочатку опубліковано на CSS-трюки. Ти повинен отримати інформаційний бюлетень.

Часова мітка:

Більше від CSS-хитрощі