Адаптивні таблиці для технічної документації, які не ламаються в продакшені

Було корисно?

Ви публікуєте акуратну таблицю довідки API. Вона ідеально виглядає на вашому 32-дюймовому моніторі. Потім служба підтримки надсилає скріншот з телефона, де таблиця
вирвалася зі сторінки, відсуваючи вашу навігацію за межі екрану і роблячи кнопки «Copy» неклікабельними.

Таблиці — це прихований режим відмов технічної документації: вони працюють, поки раптом не перестають, і коли це трапляється, вони тягнуть за собою решту макета.
Це практичний, експлуатаційний підхід до побудови адаптивних таблиць: контейнер скролу, який поводиться правильно, липкі заголовки без деренчання та код-ячейки, які лишаються читабельними.

Обов’язкові принципи: що насправді означає «адаптивна таблиця»

«Адаптивна таблиця» — це не «зменшити все, поки не влізе». У технічній документації таблиці несуть щільну, критичну інформацію:
параметри, значення за замовчуванням, матриці сумісності, коди помилок, обмеження сховища та такі сноски, що рятують вихідні сторінки у вихідні.
Ваше завдання — зберегти правдивість і придатність таблиці в різних вікнах перегляду та методах введення.

Принцип 1: Не перетворюйте правду на вигадку

Багато рецептів «адаптивної таблиці» згортають колонки в стопки-картки. Це може працювати для маркетингових сторінок.
У документації це часто перетворює порівняння на квест. Якщо читачеві потрібно порівняти значення між колонками — збережіть сітку.
Горизонтальний скрол допустимий, коли він свідомий і не ламає все інше.

Принцип 2: Таблиця не має права вириватися з контейнера

Головний режим відмов — переповнення: нерозривні рядки (UUID, base64, SHA256, шляхи до файлів, команди) змушують таблицю бути ширшою за вікно.
Як тільки це трапляється, макет починає «креативити». Виправляйте на рівні контейнера й на рівні ячейки. Обоє.

Принцип 3: Липкі заголовки мають бути вирівняні з колонками

Липкі заголовки — це функція підвищення продуктивності, доки вони не зміщуються через нерівномірні ширини, моделі бордерів або вкладені скрол-контексти.
Липкий заголовок, який не відповідає колонці, гірший за його відсутність. Він перетворює читання на здогадки.

Принцип 4: Код-ячейки — не прозовий текст

Інлайн-код часто довгий, копіюється й переглядається шляхом сканування. Він потребує моноширинного шрифту, розумних правил переносу та фону, що працює в темній темі.
«Просто нехай він переноситься» — не стратегія; так ви отримуєте зламані токени (і зіпсовані деплоями).

Принцип 5: Якщо це недоступно з клавіатури — це не зроблено

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

Цитата, якою користуюся, коли хтось пропонує «випустити й подивитися»: Надія — не стратегія. — генерал Gordon R. Sullivan

Жарт №1: Липкі заголовки як графік чергувань на дзвінках: добре, поки не змістяться, тоді всі звинувачують одне одного.

Декілька фактів і історія (бо веб має докази)

  • HTML-таблиці передували CSS-розкладкам і використовувалися для верстки сторінок у 1990-х; відлуння цього робить стиль таблиць примхливим у крайніх випадках.
  • position: sticky створювався, щоб зменшити JavaScript-обробники скролу — виграш у продуктивності, що став критичним для липких заголовків таблиць і бічних панелей.
  • Мобільні браузери історично по-різному обробляли переповнення і ланцюжки скролу, тому «працює на десктопі» ніколи не гарантувало «працює на телефоні».
  • Довгі токени стали поширеними в документації через сучасну інфраструктуру: дайджести контейнерів, ідентифікатори ресурсів у хмарі, JWT, контрольні суми й ID трасування — це нерозривні рядки.
  • UI «копіювати в буфер» став популярним у документації з ростом DevOps-інструментів; це очікувана поведінка для команд і фрагментів конфігурацій — навіть всередині таблиць.
  • Хитрість з table-layout: fixed старша за багато дизайн-систем і залишається одним із найкращих важелів для передбачуваних ширин колонок під навантаженням.
  • CLS (Cumulative Layout Shift) став формальним показником у Core Web Vitals; таблиці з веб-шрифтами і пізньо-підвантаженим контентом часто провокують CLS.
  • Багато сайтів документації — статичні збірки (SSG), але таблиці все ще можуть «повільно рендеритися» через гідратацію на клієнті, підсвічування синтаксису і важкий CSS.

Базовий шаблон: контейнер скролу + стійка таблиця

Найбезпечніший дефолт для таблиць технічної документації — нудний:
загорніть таблицю в контейнер скролу, який відповідає за горизонтальне переповнення, тримайте ширину таблиці стабільною і застосуйте правила переносу на рівні ячейки,
щоб уникнути «детонації» макета одним токеном.

HTML-структура, яку можна впровадити

Обгортка не опційна. Встановлювати overflow-x: auto безпосередньо на таблицю ненадійно й може зламати липкі заголовки і розміри.
Зробіть обгортку контейнером скролу; тримайте таблицю таблицею.

cr0x@server:~$ cat responsive-table.html
<div class="table-wrap" role="region" aria-label="API parameters table">
  <table class="doc-table">
    <thead>
      <tr>
        <th scope="col">Parameter</th>
        <th scope="col">Type</th>
        <th scope="col">Default</th>
        <th scope="col">Example</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <th scope="row">timeout</th>
        <td>integer</td>
        <td>30</td>
        <td><code>timeout=60</code></td>
      </tr>
    </tbody>
  </table>
</div>

CSS, який працює під навантаженням

Суть — стабільність: передбачуване визначення ширин колонок, чисте переповнення і контейнер скролу, що не захоплює сторінку.
Також: видимий підказник. Якщо користувачі не помічають, що таблиця скролиться, вони думають, що документація зламана.

cr0x@server:~$ cat responsive-table.css
.table-wrap {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  border: 1px solid color-mix(in srgb, CanvasText 20%, transparent);
  border-radius: 10px;
  background: Canvas;
  max-width: 100%;
}

.doc-table {
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
  min-width: 720px;
  table-layout: fixed;
}

.doc-table th,
.doc-table td {
  padding: 0.75rem 0.9rem;
  vertical-align: top;
  border-bottom: 1px solid color-mix(in srgb, CanvasText 15%, transparent);
}

.doc-table thead th {
  background: color-mix(in srgb, Canvas 92%, CanvasText 8%);
  font-weight: 650;
}

.doc-table tbody tr:hover td,
.doc-table tbody tr:hover th[scope="row"] {
  background: color-mix(in srgb, Canvas 94%, CanvasText 6%);
}

.doc-table th[scope="row"] {
  font-weight: 600;
  text-align: left;
}

.doc-table td {
  overflow: hidden;
  text-overflow: ellipsis;
}

.doc-table code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  font-size: 0.95em;
  background: color-mix(in srgb, Canvas 88%, CanvasText 12%);
  padding: 0.12em 0.35em;
  border-radius: 6px;
  white-space: normal;
  overflow-wrap: anywhere;
}

Ключові вибори, які слід робити свідомо:

  • min-width на таблиці запобігає «всі колонки зминаються в нечитаємий суп». На маленьких екранах обгортка скролиться замість цього.
  • table-layout: fixed зменшує вартість рефлоу й робить ширини колонок передбачуваними. Це також робить ellipsis консистентним.
  • Політика переповнення на рівні ячеїки: прозовий текст може переноситися; код і ідентифікатори повинні використовувати overflow-wrap: anywhere і не вимагати ширини.
  • Ellipsis — інструмент, а не брехня. Використовуйте його, коли колонка другорядна, і ви даєте спосіб побачити повне значення (атрибут title, розгортання або кнопка копіювання).

Липкі заголовки, що не мерехтять, не розмиваються і не брешуть

Липкі заголовки варто застосовувати для довгих таблиць — матриці сумісності, переліку параметрів, списків кодів помилок.
Але у липких заголовків є три класичні проблеми: (1) вони перестають «липнути», бо неправильно вказано елемент скролу,
(2) перекривають контент і ховають фокус, або (3) не вирівнюються з колонками.

Зробіть обгортку контейнером скролу, а потім прилипаюче всередині неї

position: sticky прилипає відносно найближчого прокручуваного предка. Якщо ви поставите overflow на якийсь батьківський елемент, про який забули,
ваш заголовок буде прилипатись до неправильного елемента — або взагалі не прилипатиме.

cr0x@server:~$ cat sticky-header.css
.table-wrap {
  max-height: 60vh;
  overflow: auto;
}

.doc-table thead th {
  position: sticky;
  top: 0;
  z-index: 2;
}

.doc-table thead th::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: color-mix(in srgb, CanvasText 18%, transparent);
}

.doc-table thead th {
  box-shadow: 0 2px 0 color-mix(in srgb, CanvasText 10%, transparent);
}

z-index і легка тінь — це не декор. Це ясність. Без них користувачам важко зрозуміти, де закінчується заголовок,
особливо в темному режимі і коли фон заголовка близький до фону тіла.

Вирівнювання липких заголовків: уникайте дробових ширин і хаосу бордерів

Невідповідність часто походить від змішування режимів border-collapse, вкладених елементів з різним box-sizing або контенту, що викликає зміну ширин колонок.
Якщо ви хочете липкі заголовки — вам потрібні стабільні ширини. Тут table-layout: fixed виправдовує себе.

Якщо ваш перший стовпець — це «Ім’я параметра» і має залишатися читабельним, зафіксуйте його ширину:

cr0x@server:~$ cat column-widths.css
.doc-table th[scope="row"] {
  width: 14rem;
}

.doc-table td:nth-child(2) {
  width: 10rem;
}

.doc-table td:nth-child(3) {
  width: 8rem;
}

Липкий перший стовпець: можливо, але не робіть це легковажно

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

cr0x@server:~$ cat sticky-first-column.css
.doc-table th[scope="row"] {
  position: sticky;
  left: 0;
  z-index: 1;
  background: Canvas;
}

.doc-table thead th:first-child {
  left: 0;
  z-index: 3;
  background: color-mix(in srgb, Canvas 92%, CanvasText 8%);
}

Останнє правило (клітинка у верхньому лівому куті має найвищий z-index) — це «податок за уникнення дивного артефакту перекриття».
Заплатіть його наперед. Інакше заплатите більше пізніше.

Читабельні код-ячейки: довгі токени, копіювання та переноси

У документації в таблицях часто з’являються: команди, прапорці, фрагменти JSON, змінні оточення, дайджести, регулярні вирази та шляхи.
Ці значення не призначені для читання як абзац; їх копіюють, порівнюють і сканують.
Код-ячейка, що випадково переноситься, може створити невидиму корупцію. Так виникають тикети «працювало в staging».

Вирішіть: переносити, скролити чи обрізати код?

У вас є три розумні варіанти для кодоподібних значень:

  • Переносити будь-де для ідентифікаторів, де розриви рядків не змінюють значення (ID ресурсів, хеші). Це зберігає макет.
  • Горизонтальний скрол всередині ячейки для команд і конфігурацій, де перенос може ввести в оману. Це зберігає можливість копіювання та семантику.
  • Обрізати з ellipsis коли значення другорядне і є підказка «скопіювати повне значення».

Чого не слід робити: дозволяти таблиці ставати ширшою за обгортку через те, що токен відмовляється переноситися.
Це не «адаптивність», це «ворожість».

Шаблон: прокручуваний код всередині ячейки

Простий підхід: рендерити код у блочному елементі всередині ячейки з власним скролом.
Це не примушує всю таблицю скролитися через одну довгу ячейку.

cr0x@server:~$ cat code-cell.css
.doc-table td .cell-code {
  display: block;
  max-width: 100%;
  overflow-x: auto;
  white-space: nowrap;
  padding: 0.35rem 0.5rem;
  border-radius: 8px;
  background: color-mix(in srgb, Canvas 88%, CanvasText 12%);
  border: 1px solid color-mix(in srgb, CanvasText 12%, transparent);
}

.doc-table td .cell-code code {
  white-space: inherit;
  background: transparent;
  padding: 0;
}

Шаблон: зберегти копіюваність і показати намір

Якщо ви рендерите розриви рядків у клітинці з командою, користувачі скопіюють розриви. Потім вставлять у shell, і shell зробить shell-дії.
Не завжди те, що вони очікували.

Використовуйте white-space: nowrap для однорядкових команд; явні переноси — лише коли ви показуєте багаторядковий скрипт і хочете, щоб його копіювали як такий.

Запобігайте багам «виглядає як мінус» у коді

Деякі шрифти по-різному відображають hyphen-minus, en-dash і em-dash. Якщо ваш процес документації «розумніє» пунктуацію,
ви можете отримати прапорці типу —help, які виглядають нормально, але не працюють. Виправлення переважно редакційне (відключити smart punctuation у коді),
але й рендеринг важливий: тримайте код у code елементах, щоб типографічні рушії не ставили творчості.

Жарт №2: Єдине, небезпечніше за довгий нерозривний рядок — той самий рядок, розбитий точно в неправильному місці.

Доступність і UX: не карайте користувачів клавіатури

Контейнер скролу — це маленька модель взаємодії. Якщо ви її не спроектуєте, користувачі відкриють її жорстоким способом.
Це означає: помітність, поведінка фокусу, читабельна контрастність і передбачуваний скрол.

Дайте обгортці роль і мітку

Якщо таблиця переповнюється, користувачі з допоміжними технологіями повинні розуміти, що вони в області з окремим скролом.
Позначте її: «API parameters table», «Error codes table», а не просто «table» (вони і так знають, що це таблиця).

Видимий фокус: не дозволяйте липким заголовкам ховати його

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

cr0x@server:~$ cat focus.css
.table-wrap {
  scroll-padding-top: 3rem;
}

.doc-table a:focus-visible,
.doc-table button:focus-visible,
.doc-table code:focus-visible {
  outline: 2px solid color-mix(in srgb, Highlight 80%, CanvasText 20%);
  outline-offset: 2px;
}

Не покладайтеся на hover заради змісту

Підсвічування рядків при наведені приємне на десктопі. На сенсорних пристроях воно нічого не дає, і небагато — користувачам клавіатури.
Використовуйте послідовні бордери, смугастість за потреби і тримайте заголовки рядків/стовпців явними (scope атрибути).

Поважайте зменшення анімації і уникайте гальм скролу

Липкі заголовки й тіні — ок. Паралакс всередині контейнера таблиці — ні.
Будь-яка анімація, прив’язана до скролу, робить: «мобільний телефон нагрівається і таблиця все одно не скролиться».

Продуктивність і режими відмов: коли таблиці стають інцидентом рендерингу

Таблиці оманливо дорогі. Браузеру потрібно обчислити ширини колонок по всіх рядках, намалювати бордери, обробити липкі стек-контексти
і зробити рефлоу при завантаженні шрифтів або коли клієнтський JavaScript «поліпшує» розмітку.
Якщо ваша платформа документації виконує гідратацію на клієнті, велика таблиця може спричинити помітну блокировку головного потоку.

Що зазвичай шкодить

  • Великі таблиці з сотнями рядків і складним вмістом ячеєк (іконки, вкладені блоки, підсвічування синтаксису).
  • Пізньо-підвантажені веб-шрифти, що змінюють метрики і змушують робити повторний лейаут, особливо з position: sticky.
  • JS «плагіни для таблиць», що переписують DOM, вимірюють ширини на скролі або підключають обробники скролу без тротлінгу.
  • Важкі тіні і фільтри, застосовані до багатьох ячеєк.
  • Кнопки копіювання в кожній ячейці, відрендерені як інтерактивні контролі в кожному рядку без віртуалізації.

Що зазвичай допомагає

  • Тримайте HTML простим. Таблиці вже мають складні правила розмітки; не вкладайте в них інтерактивні панелі.
  • Використовуйте table-layout: fixed для передбачуваних розмірів і менше перерахунків лейауту.
  • Переважайте CSS sticky над JS. Обробники скролу — це шлях зробити «сторінку документації» схожою на «майнер криптовалют».
  • Будьте обачні з підсвічуванням синтаксису. Якщо ви підсвічуєте тисячі токенів у таблицях на боці клієнта — ви вибираєте біль.
  • Обріжте висоту для монстр-таблиць, щоб прокрутка сторінки лишалася розумною, а прокрутка таблиці — локалізованою.

Якщо у вашого сайту документації є бюджет продуктивності (має бути) — таблиці входять у нього. Ніхто не відкриває інцидент через «список параметрів повільний»,
але відкривають, коли втрачається релізний поїзд через те, що люди не можуть читати документацію.

Три корпоративні міні-історії з передової

Інцидент: хибне припущення «мобільні користувачі не читають таблиць»

Внутрішня платформа випустила нову тему документації з «спрощенням для мобайлу». На екранах нижче певного брейкпоінта таблиці конвертувалися в картки.
Кожен рядок ставав карткою; кожна колонка — парою мітка/значення. Виглядало акуратно. Продукт підписався. Ніхто не перевірив порівняння двох колонок поруч.

Перші реальні користувачі були інженерами на дзвінках, які відкрили матрицю сумісності під час оновлення.
Їм потрібно було порівняти «версію клієнта», «версію сервера» і «підтримувані cipher suites». Вид карток вимагав нескінченного скролу і пам’яті.
Люди почали робити скріншоти десктопної версії і відправляти їх на телефони, бо це було швидше за мобільний вигляд.

Потім з’явився другорядний збій: конвертер карток позбувся scope="row" заголовків і сплющив HTML.
Користувачі скрінрідерів отримали невідмічені значення. Команда дізналася про це не з аудиту доступності, а з ескалації в підтримку.

Виправлення було грубим і правильним: зберегти сітку таблиці на мобайлі, використовуючи контейнер скролу, додати видиму підказку «Прокрутіть по горизонталі»,
і тримати заголовок липким. Конвертація у картки залишилась лише для малої підгрупи таблиць, явно позначених як «не для порівняння».

Оптимізація, що влетіла в голову: «давайте автопідганяти ширини через JavaScript»

Команда документації хотіла ідеальні ширини колонок: вузький «Type», ширший «Description», а «Example» — достатньо великий. Вони впровадили скрипт, який заміряв
найширшу ячейку для колонки після рендеру, а потім встановлював явні ширини на заголовках. На їхніх тестових сторінках це працювало.

У продакшені сайт використовував клієнтську навігацію і відкладене завантаження шрифтів. Кожна навігація запускала повторні вимірювання.
Коли шрифт підмінявся, ширини змінювалися знову. Липкі заголовки почали деренчати, бо ширини оновлювалися під час прокрутки.
На слабких пристроях цикл вимірювань спричиняв помітне пригальмовування — якраз там, де потрібен плавний скрол.

Особливо гидкий баг з’явився, коли код-ячейки містили горизонтально прокручувані блоки.
Скрипт вимірював scroll width, а не видиму ширину, і розширював колонки до повної довжини команди.
Обгортка перестала містити переповнення. Таблиця «вирвалася», знову.

Остаточне виправлення було дивовижно непоказним: прибрати JS-розміри, прийняти table-layout: fixed, задати кілька ширин колонок,
і використовувати ellipsis + копіювання для наддовгих прикладів. Досконалість була обміняна на передбачуваність, і всі спали краще.

Сумно, але правильно: тестувати таблиці на найгіршому контенті

Інша організація запускала документацію як частину регульованого продукту. Їхній процес рев’ю не був гламурним, але дисциплінованим.
Кожна велика зміна теми мала «сторінку тортур для таблиць»: величезні ідентифікатори, багаторядковий JSON, довгі шляхи, сценарії пунктуації на зразок RTL,
і змішані скрипти. Нічого модного. Просто найгірше, що вони коли-небудь бачили в продакшені.

Під час редизайну нове правило CSS встановило white-space: nowrap для всіх td, щоб «тримати все охайним».
Сторінка тортур відразу показала горизонтальне переповнення по всьому сайту, не лише в обгортках таблиць.
Регресія була спіймана до мерджу.

Вони також мали одну перевірку доступності: табувати крізь область таблиці, поки не дійдеш до останнього посилання в останньому рядку.
Якщо фокус пропадав за липким заголовком — зміна не відправлялася в реліз.

Нудна, але правильна практика — тримати сторінку з найгіршим контентом і використовувати її як набір тестів — запобігла релізу, який зламав би всі таблиці API.
Ніхто не писав постмортем, бо нічого не зламалось. Це найкращий тип роботи над надійністю.

Швидка діагностика: що перевіряти спочатку/другим/третім

Коли таблиця «зламана» (переповнюється, гальмує, не вирівнюється, нечитаема), ви хочете уникнути випадкового CSS whack-a-mole.
Виконуйте цей список по порядку. Він розроблений, щоб швидко знайти вузьке місце.

1) Визначте власника скролу

  • Чи є обгортка елементом з overflow-x/overflow?
  • Чи якийсь батьківський елемент випадково створює контекст прокрутки?
  • Чи таблиця ширша за обгортку через нерозривний токен?

2) Знайдіть найширшу ячейку (звичний підозрюваний)

  • Шукайте довгі ідентифікатори, base64, мінімізований JSON або команди без розривів.
  • Перевірте, чи white-space: nowrap застосований занадто широко.
  • Перевірте наявність min-width на ячейках або дочірніх елементах, що примушує ширину.

3) Перевірте липку поведінку у фактичному контексті скролу

  • Липкі заголовки потребують position: sticky; top: 0 на th і визначеного контейнера скролу.
  • Перевірте стек-контексти (z-index), щоб заголовок малювався над рядками тіла.
  • Підтвердьте, що фон заголовка непрозорий; інакше текст тіла просвічує під час прокрутки.

4) Перевірте стабільність лейауту та вартість рендерингу

  • Якщо є пригальмовування, перевірте, чи JavaScript вимірює ширини або реагує на скрол.
  • Перевірте підміни шрифтів (FOIT/FOUT) і чи змушують вони перерахунок таблиці.
  • Перевірте, чи підсвічування синтаксису виконується на клієнті для сотень ячейок.

5) Підтвердіть юзабіліті клавіатурою/дотиком

  • Чи можна сфокусуватися в регіоні і побачити кільце фокусу?
  • Чи працює горизонтальний скрол сенсорно без тригеру жестів навігації сторінки?
  • Чи липкий заголовок перекриває сфокусовані елементи?

Практичні завдання: команди, виводи та рішення (12+)

Це «зроби справу» завдання, які можна виконати в репозиторії документації або на зібраному сайті. Кожне містить: команду, приклад виводу, що це означає,
і рішення, яке потрібно прийняти. Вони припускають типовий статичний збірник сайту з артефактами HTML/CSS/JS.

Завдання 1: Знайдіть таблиці без обгортки (корінь більшості багів з overflow)

cr0x@server:~$ rg -n "

Що це означає: У вас кілька варіантів таблиць; деякі можуть не мати обгортки.

Рішення: Стандартизувати одну компоненту обгортки (.table-wrap) і робити збірку з помилкою, якщо гола таблиця з’являється в контенті.

Завдання 2: Виявити необгорнуті таблиці через парсинг HTML

cr0x@server:~$ python3 - <<'PY'
from bs4 import BeautifulSoup
import glob, sys
bad=[]
for f in glob.glob("public/**/*.html", recursive=True):
    html=open(f,encoding="utf-8").read()
    s=BeautifulSoup(html,"html.parser")
    for t in s.find_all("table"):
        p=t.parent
        if not (p and p.name=="div" and "table-wrap" in (p.get("class") or [])):
            bad.append((f, t.get("class")))
            break
print("unwrapped_files", len(set(x[0] for x in bad)))
for f,_ in bad[:10]:
    print(f)
PY
unwrapped_files 2
public/errors.html
public/compat.html

Що це означає: Дві сторінки мають таблиці без очікуваного контейнера скролу.

Рішення: Виправити шаблони/контент негайно; інакше будь-який довгий токен може зламати весь макет сторінки.

Завдання 3: Виявити регресії «nowrap повсюди» у CSS

cr0x@server:~$ rg -n "white-space:\s*nowrap" public/assets/*.css | head -n 20
public/assets/app.css:1132:.doc-table td { white-space: nowrap; }
public/assets/app.css:1180:.cell-code { white-space: nowrap; }

Що це означає: Перше правило небезпечне; воно змушує кожну ячейку відмовлятися від переносу.

Рішення: Прибрати nowrap з генералізованого td; зберегти nowrap лише для явних контейнерів коду.

Завдання 4: Підтвердити наявність правил для липкого заголовка і їх ціль

cr0x@server:~$ rg -n "position:\s*sticky" public/assets/*.css
public/assets/app.css:1202:.doc-table thead th { position: sticky; top: 0; z-index: 2; }

Що це означає: Sticky застосовано до thead th, що є правильною ціллю.

Рішення: Залишити. Якщо sticky відмовляє під час виконання — проблема, ймовірно, у предку скролу або обрізанні overflow, а не в відсутності CSS.

Завдання 5: Знайти предків з overflow, що ламають sticky

cr0x@server:~$ rg -n "overflow:\s*(hidden|clip)" public/assets/*.css | head
public/assets/theme.css:221:.content { overflow: hidden; }
public/assets/theme.css:418:.doc-container { overflow: clip; }

Що це означає: Правила overflow на зовнішніх контейнерах можуть обрізати липкі заголовки або смуги прокрутки.

Рішення: Приберіть або обмежте scope обрізання overflow. Якщо потрібно обрізати — забезпечте, щоб обгортка таблиці не була всередині обрізаного контексту.

Завдання 6: Виявити мінні поля довгих токенів у контенті

cr0x@server:~$ rg -n "[A-Za-z0-9+/]{120,}={0,2}" content/ | head
content/auth.md:77:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....
content/trace.md:54:Zm9vYmFyYmF6cXV4cXV1eGJhc2U2NA==...

Що це означає: Присутні base64/JWT-рядки. Вони зіпсують таблиці, якщо ви не дозволите перенос або локальний скрол.

Рішення: Забезпечити для код-ячейок overflow-wrap: anywhere або внутрішній скрол; додати можливості копіювання, якщо потрібно.

Завдання 7: Перевірити політику table-layout (fixed проти auto)

cr0x@server:~$ rg -n "table-layout" public/assets/*.css
public/assets/app.css:1099:.doc-table { table-layout: fixed; }
public/assets/app.css:2055:.matrix { table-layout: auto; }

Що це означає: У вас змішані режими лейауту. auto може викликати витратний рефлоу і сюрпризи з ширинами.

Рішення: Для таблиць документації за замовчуванням використовувати fixed. Залишати auto лише там, де потрібне внутрішнє визначення розміру (рідко).

Завдання 8: Зміряти, скільки таблиць є (масштаб важливий для продуктивності)

cr0x@server:~$ find public -name "*.html" -print0 | xargs -0 rg -c "

Що це означає: 47 таблиць по зібраному сайту. Не дуже багато, але достатньо, щоб глобальні JS-покращення шкодили.

Рішення: Уникати важких скриптів на кожну таблицю; віддавати перевагу поведінці на CSS з progressive enhancement.

Завдання 9: Виявити клієнтські поліпшення таблиць (JS-плагіни, цикли вимірювань)

cr0x@server:~$ rg -n "(getBoundingClientRect|offsetWidth|scrollWidth).*(table|thead|th)" public/assets/*.js | head
public/assets/app.js:8812:const w = th.getBoundingClientRect().width;
public/assets/app.js:8820:table.style.width = table.scrollWidth + "px";

Що це означає: JavaScript вимірює ширини заголовків і, можливо, змушує таблицю мати width = scrollWidth. Це тривожний знак.

Рішення: Прибрати або обмежити цю логіку. Замінити на CSS-розмітку. Якщо зберігаєте її — виконувати один раз, а не у циклах на scroll/resize.

Завдання 10: Перевірити, чи таблиці лишаються в межах вікна у headless-перевірці

cr0x@server:~$ node - <<'NODE'
const fs = require("fs");
const { JSDOM } = require("jsdom");
const html = fs.readFileSync("public/api.html","utf8");
const dom = new JSDOM(html);
const tables = [...dom.window.document.querySelectorAll("table")];
console.log("tables", tables.length);
console.log("wrapped", [...dom.window.document.querySelectorAll(".table-wrap table")].length);
NODE
tables 3
wrapped 2

Що це означає: Одна таблиця в api.html не обгорнута.

Рішення: Виправити генерацію HTML. Ви хочете «wrapped equals tables» для таблиць документації, якщо не вказано інакше.

Завдання 11: Перевірити ризик CLS від пізнього завантаження шрифтів у зібраному HTML

cr0x@server:~$ rg -n "rel=\"preload\" as=\"font\"" public/*.html | head
public/index.html:18:<link rel="preload" as="font" href="/assets/fonts/Inter.woff2" type="font/woff2" crossorigin>

Що це означає: Шрифти прелоудяться на index.html, але не обов’язково на сторінках документації.

Рішення: Перелічити критичні шрифти на сторінках з великими таблицями або використовувати стек шрифтів із стабільними метриками.

Завдання 12: Аудит недостатньої контрастності фонів заголовків таблиць

cr0x@server:~$ rg -n "thead th.*background" public/assets/*.css
public/assets/app.css:1110:.doc-table thead th { background: #f7f7f7; }
public/assets/dark.css:90:.doc-table thead th { background: #151515; }

Що це означає: Ви маєте явні кольори; контраст залежить від кольору тексту і оточуючих поверхонь.

Рішення: Перевірити контраст у обох темах; віддати перевагу системним кольорам (Canvas, CanvasText) або color-mix з гарантіями.

Завдання 13: Відловити таблиці всередині контейнерів, що відключають горизонтальний скрол

cr0x@server:~$ rg -n "\.table-wrap\s*\{[^}]*overflow-x:\s*(hidden|clip)" public/assets/*.css

Що це означає: Збігів немає. Добре: обгортка має можливість скролу.

Рішення: Тримайте це так. Якщо рефактор додасть обрізання overflow тут — вважайте це регресією.

Завдання 14: Переконатися, що обгортка таблиці має політику max-width

cr0x@server:~$ rg -n "\.table-wrap\s*\{[^}]*max-width" public/assets/*.css
public/assets/app.css:1072:.table-wrap { max-width: 100%; }

Що це означає: Обгортка обмежує ширину до вікна/контейнера.

Рішення: Залишити max-width: 100%. Без нього вкладені макети можуть розтягуватися несподівано.

Типові помилки: симптом → корінь → виправлення

1) Симптом: Таблиця штовхає всю сторінку вбік

Корінь: Необгорнута таблиця або відсутня обгортка з overflow-x: auto; нерозривні токени або глобальний nowrap.

Виправлення: Загорніть таблиці в спеціальний контейнер скролу. Додайте політику переносу для кодів/ID (overflow-wrap: anywhere) і приберіть глобальний nowrap.

2) Симптом: Липкий заголовок не прилипає

Корінь: Липкий елемент всередині не-прокручуваного контексту; предок має overflow: hidden/clip; або заголовки не є липкими елементами.

Виправлення: Зробіть контейнер таблиці власником скролу (overflow: auto) і встановіть position: sticky на thead th. Приберіть обрізання overflow з предків.

3) Симптом: Липкий заголовок прилипає, але колонки не вирівняні

Корінь: Ширини колонок змінюються через внутрішнє визначення; змішані моделі бордерів; JS вимірює і встановлює ширини непослідовно.

Виправлення: Використовуйте table-layout: fixed, задати явні ширини для ключових колонок і припинити JS-маніпуляції ширинами.

4) Симптом: Довгі команди переносяться і стають оманливими

Корінь: Код відрендерено з white-space: normal і без внутрішньої політики скролу; м’який перенос вставляється всередині прапорця.

Виправлення: Використовуйте блок .cell-code з white-space: nowrap і overflow-x: auto, плюс кнопку копіювання за потреби.

5) Симптом: Копіювання з ячеєк дає дивні пробіли/переноси

Корінь: Стилі додають псевдо-елементи, переноси рядків або «розумну» пунктуацію; вкладені елементи додають прихований текст.

Виправлення: Тримайте код у <code>/<pre> з мінімальним декором; уникайте псевдо-контенту всередині коду; відключіть типографські підстановки в пайплайні рендерингу коду.

6) Симптом: На iOS горизонтальний скрол бореться зі скролом сторінки

Корінь: Ланцюжок скролу; обгортка не використовує momentum scrolling; контейнер занадто малий або вкладений у інший скролер.

Виправлення: Додайте -webkit-overflow-scrolling: touch і overscroll-behavior-x: contain. Уникайте вкладених скрол-контейнерів, коли можливо.

7) Симптом: Контур фокусу зникає за липким заголовком

Корінь: Липкий заголовок перекриває; немає scroll-padding; заголовок має вищий z-index і непрозорий фон.

Виправлення: Додайте scroll-padding-top на обгортці і забезпечте видимий стиль фокусованих елементів.

8) Симптом: Сторінка гірчить при прокрутці довгої таблиці

Корінь: JS-обробники скролу; важкі тіні на багатьох ячейках; підсвічування/гідратація великого DOM.

Виправлення: Прибрати обробники скролу; спростити вміст ячейок; підсвічувати на стадії збірки; обмежити висоту обгортки і тримати layout фіксованим.

9) Симптом: Текст заголовка просвічує з текстом тіла під час прокрутки

Корінь: Фон липкого заголовка прозорий; артефакти GPU/композитингу.

Виправлення: Використовуйте непрозорий фон на thead th і тонкий роздільник (бордер або тінь).

10) Симптом: Таблиця виглядає нормально, але користувачі не здогадуються, що її можна скролити

Корінь: Немає візуального підказника; смуги прокрутки приховані ОС; обгортка зливається з фоном сторінки.

Виправлення: Додати бордер і легку відмінність фону для обгортки; опціонально — маленьку підказку «Прокрутити» для вузьких екранів.

Чеклісти / покроковий план

Покроково: випустіть компонент адаптивної таблиці

  1. Створіть один компонент обгортки таблиці, який рендерить <div class="table-wrap" role="region" aria-label="..."> навколо таблиці.
  2. Зробіть обгортку власником скролу: overflow-x: auto, max-width: 100%, і розгляньте max-height для довгих таблиць.
  3. Використовуйте стабільне визначення розмірів таблиці: table-layout: fixed, width: 100% і реалістичний min-width для читабельності.
  4. Реалізуйте липкі заголовки на thead th з top: 0, правильним z-index і непрозорим фоном.
  5. Встановіть політику переповнення ячейок:
    • Колонки з прозою: переносити нормально.
    • Колонки з ID/хешами: overflow-wrap: anywhere.
    • Колонки з командами/конфігом: використовувати вкладений .cell-code скролер з nowrap.
  6. Зберігайте семантику: th scope="col" і th scope="row" для заголовків рядків.
  7. Тест клавіатурою: табуйте в таблицю, прокрутіть обгортку і переконайтеся, що фокус видно під липким заголовком.
  8. Мобільний тест: перевірте, що свайп по горизонталі скролить таблицю без відтягування сторінки.
  9. Тест продуктивності: відкрийте найвелику сторінку з таблицею; переконайтеся, що прокрутка плавна і немає смикань після завантаження шрифтів.
  10. Закріпіть це: додайте CI-перевірку, яка відхиляє необгорнуті таблиці і глобальні правила nowrap для ячейок таблиць.

Чеклист релізу (версія «не змушуйте мене дзвонити»)

  • Усі таблиці обгорнуті в .table-wrap, якщо явно не виключені.
  • Липкі заголовки працюють у контексті прокрутки обгортки і лишаються вирівняними.
  • Довгі токени не розширюють макет; вони переносяться або скроляться всередині ячеек.
  • Контури фокусу видимі; липкий заголовок не ховає сфокусовані елементи.
  • Кольори темної теми зберігають контраст для заголовків і код-чіпів.
  • Немає JavaScript, що вимірює ширини на скролі.
  • «Сторінка тортур для таблиць» коректно рендериться на вузькому вікні.

FAQ

1) Чи прийнятний горизонтальний скрол у технічній документації?

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

2) Чому не просто використовувати JS-бібліотеку таблиць?

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

3) Чи ставити overflow-x: auto на сам <table>?

Не ставте. Поставте overflow на обгортку. Таблиці мають спеціальну поведінку лейауту; липкі заголовки і розрахунки ширин поводяться передбачуваніше,
коли таблиця залишається звичайним елементом всередині контейнера скролу.

4) Який найкращий спосіб обробки довгих команд у ячейці?

Використовуйте внутрішній прокручуваний блок коду (.cell-code) з white-space: nowrap. Якщо команда критична — додайте кнопку копіювання.
Уникайте переносу команд, якщо ви явно не показуєте багаторядковий скрипт.

5) Чому table-layout: fixed? Хіба це не робить колонки дивними?

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

6) Як тримати липкий заголовок читабельним у темній темі?

Дайте йому непрозорий фон і легкий роздільник (бордер або тінь). Прозорі заголовки в темній темі часто розмиваються під час прокрутки.
Віддавайте перевагу системним кольорам (Canvas/CanvasText) або обережним змішанням кольорів.

7) А як щодо друку?

Стилі для друку повинні відключати липку позиціювання і прибирати обмеження висоти, щоб контент вільно тек. Якщо таблиці широкі, розгляньте можливість масштабування або чистого розриву сторінок.
Додайте print stylesheet, що встановлює .table-wrap { overflow: visible; max-height: none; }.

8) Як показати повне значення, коли використовується ellipsis?

Забезпечте явну підказку: кнопку копіювання, перемикач «Expand» або drawer з деталями. Не покладайтеся лише на атрибут title;
він непослідовний на мобільних і не найкращий для доступності.

9) Чи потрібні липкі заголовки для кожної таблиці?

Ні. Використовуйте їх для довгих таблиць, де заголовок несе зміст (колонки параметрів, матриці сумісності). Для невеликих таблиць липкі заголовки
можуть бути візуальним шумом і додавати непотрібну складність.

Висновок: що змінити в понеділок вранці

Якщо ви запам’ятаєте одне: таблиці не «стануть адаптивними» самі собою. Ви робите їх адаптивними, контролюючи переповнення і стабілізуючи лейаут.
Загорніть таблиці в контейнер скролу, зробіть заголовки липкими в цьому контексті скролу, і розглядайте код-ячейки як окрему проблему рендерингу.

Практичні наступні кроки:

  • Реалізувати стандартний компонент .table-wrap і мігрувати всі таблиці документації до нього.
  • Прийняти table-layout: fixed для таблиць документації і задати ширини для ключових колонок.
  • Впровадити політики для код-ячейок: перенос-anywhere для ID, внутрішній скрол для команд/конфігів.
  • Створити «сторінку тортур для таблиць» і запускати її при кожній зміні теми перед релізом.
  • Прибрати JS-заміри ширин і будь-яку поведінку, прив’язану до скролу таблиць, якщо ви не можете довести її необхідність.

Ваша документація — частина виробничої системи. Трактуйте компонент таблиці як критичну залежність: передбачувану, тестовану і нудну у найкращому сенсі.

← Попередня
Debian 13: /etc/pve виглядає порожнім після перезавантаження — чому монтування не вдається та як відновити
Наступна →
PostgreSQL vs Redis: як зупинити шторм запитів по кешу, щоб база даних не «згоріла»

Залишити коментар