Перейти к содержимому
Плотность
Тема

Агентный слой

История проверок

Ряд дискретных исходов: одна проверка — один штрих, свежие справа. Аптайм монитора, прогоны ночной сборки, попытки повтора.

Компонент
Разметка
<div class="inst-history" role="img" aria-label="Последние 24 проверки: 22 успешны, 2 с ошибкой">
  <span class="inst-history-tick" data-tone="ok"></span>
  <span class="inst-history-tick" data-tone="ok"></span>
  <span class="inst-history-tick" data-tone="error"></span>
  <span class="inst-history-tick" data-tone="ok"></span>
  <span class="inst-history-tick" data-tone="ok"></span>
  <span class="inst-history-tick" data-tone="ok"></span>
  <span class="inst-history-tick" data-tone="ok"></span>
  <span class="inst-history-tick" data-tone="warn"></span>
  <span class="inst-history-tick" data-tone="ok"></span>
  <span class="inst-history-tick" data-tone="ok"></span>
  <span class="inst-history-tick" data-tone="ok"></span>
  <span class="inst-history-tick" data-tone="ok"></span>
</div>

Использование

<div class="inst-history" role="img" aria-label="Последние 24 проверки: 22 успешны">
  <span class="inst-history-tick" data-tone="ok"></span>
  <span class="inst-history-tick" data-tone="error"></span>
</div>
Что Обязательно Почему
role="img" и aria-label с итогом словами да Двести пустых <span> для скринридера — двести пустых <span>. Итог обязан быть текстом: «22 из 24 успешны»
Свежие справа да Полоса читается как время, а время в этой письменности идёт вправо
Тон из словаря да ok · warn · error · running · neutral. Шестого исхода не бывает
Штрих без тона нет Проверка была, результат неизвестен: штрих остаётся цветом дорожки

Когда использовать

Используйте Возьмите другое
Ряд равных событий с перечислимым исходом Величина во времениспарклайн: там важно значение, а не исход
Аптайм, прогоны, попытки повтора Отрезки разной длины на общей осидорожки
Один показатель против предела Долямера или кольцо

Устройство

Ширина штриха фиксирована (--size-tick), а не доля. Доля сделала бы полосу из двадцати проверок неотличимой от полосы из двухсот, хотя означают они разное: короткая история и длинная.

Полоса прижата к концу, поэтому лишнее уходит за начало и обрезается там: старое исчезает первым, а последняя проверка видна всегда. Разметка при этом обычная — от старых к свежим, как в массиве, который отдаёт сервер.

Высота — --size-icon, ростом с глиф. Полоса стоит в одном ряду с подписью и бейджем, и на полную высоту строки она перестаёт быть отметкой рядом с ними: становится блоком и перетягивает ряд на себя.

Варианты

Группы

Час, день, прогон: пачка проверок, у которой есть общее имя.

Полоса без групп отвечает на «что было». С группами она отвечает ещё и на «сколько за этим стоит»: час с одной проверкой — один кирпич, час с семью — семь.

Пример
Разметка
<div class="inst-history" style="inline-size:26rem" role="img" aria-label="Шесть часов: 19 проверок, две с ошибкой">
  <span class="inst-history-group" style="--n:1"><span class="inst-history-tick" data-tone="ok"></span></span>
  <span class="inst-history-group" style="--n:7"
    ><span class="inst-history-tick" data-tone="ok"></span
    ><span class="inst-history-tick" data-tone="ok"></span
    ><span class="inst-history-tick" data-tone="error"></span
    ><span class="inst-history-tick" data-tone="error"></span
    ><span class="inst-history-tick" data-tone="ok"></span
    ><span class="inst-history-tick" data-tone="ok"></span
    ><span class="inst-history-tick" data-tone="ok"></span
  ></span>
  <span class="inst-history-group" style="--n:1"><span class="inst-history-tick" data-empty></span></span>
  <span class="inst-history-group" style="--n:4"
    ><span class="inst-history-tick" data-tone="ok"></span
    ><span class="inst-history-tick" data-tone="ok"></span
    ><span class="inst-history-tick" data-tone="ok"></span
    ><span class="inst-history-tick" data-tone="ok"></span
  ></span>
  <span class="inst-history-group" style="--n:6"
    ><span class="inst-history-tick" data-tone="ok"></span
    ><span class="inst-history-tick" data-tone="ok"></span
    ><span class="inst-history-tick" data-tone="ok"></span
    ><span class="inst-history-tick" data-tone="ok"></span
    ><span class="inst-history-tick" data-tone="ok"></span
    ><span class="inst-history-tick" data-tone="ok"></span
  ></span>
</div>

Ширина группы пропорциональна числу штрихов в ней — --n в разметке. Ширину полосе даёт контейнер: группы делят то, что им дали.

Равные слоты не годятся, и это меряется: полоса в 520px, разбитая на 24 часа, даёт 14px на час, а в 14px помещается три штриха. Пропорция, наоборот, всегда занимает ровно ширину полосы, сколько бы проверок ни было — густой монитор выглядит густым, редкий редким.

Полоса с группами не обрезает содержимое: обрезка ради «старое уходит первым» здесь не нужна, всё уместилось по построению. Заодно это и позволяет повесить на штрих тултип — под overflow: hidden его срезало бы.

Без групп С группами
Ширина штриха фиксирована — длина полосы говорит, сколько было проверок Ширина полосы фиксирована — длина группы говорит, сколько проверок в этом часе
Лишнее обрезается началом Не обрезается: доли считаются от того, что есть
Одна строка списка рядом с другой Один объект крупно, на своём экране

Состояния

Пример
Разметка
<div class="inst-stack" style="max-inline-size:22rem">
  <div class="inst-history" role="img" aria-label="Всё успешно">
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-tone="ok"></span>
  </div>
  <div class="inst-history" role="img" aria-label="Падало дважды, сейчас работает">
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-tone="error"></span>
    <span class="inst-history-tick" data-tone="error"></span>
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-tone="ok"></span>
  </div>
  <div class="inst-history" role="img" aria-label="Проверок ещё не было">
    <span class="inst-history-tick"></span>
    <span class="inst-history-tick"></span>
    <span class="inst-history-tick"></span>
    <span class="inst-history-tick"></span>
    <span class="inst-history-tick"></span>
    <span class="inst-history-tick"></span>
  </div>
  <div class="inst-history" role="img" aria-label="Два часа без проверок">
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-empty></span>
    <span class="inst-history-tick" data-empty></span>
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-tone="error"></span>
  </div>
</div>
Состояние Как ставится Что значит
исход известен data-tone Проверка была и вот чем кончилась
исход неизвестен без атрибутов Проверка была, результата у нас нет
проверки не было data-empty Никто не смотрел. Место остаётся, метки нет

Разница между двумя последними важнее, чем кажется. «Не знаем результат» — про проверку, «не было проверки» — про нас.

Пропуск не красится и не обводится, и то и другое пробовалось. Рамка сбивает плотность ряда: глаз читает смену текстуры как смену ритма, а не как смену значения, и полоса «плывёт». Цвет обещает оценку — а на реальных данных пропуск бывает не исключением, а нормой: в приложении, где история пришла из импорта, тоном закрасилось бы 288 штрихов из 336, и исключением перестало бы быть всё.

Если пропуск заслуживает тревоги, её место — в строке рядом: «проверок нет с 07:14». Одно утверждение — одно место.

Композиции

В карточке монитора

В контексте
absalyamov.ru работает
https://absalyamov.ru/ · http
Разметка
<div class="inst-card" style="max-inline-size:24rem">
  <div class="inst-card-head">
    <span class="inst-card-title">absalyamov.ru</span>
    <span class="inst-badge" data-tone="ok"><span class="inst-dot"></span>работает</span>
  </div>
  <div class="inst-card-sub">https://absalyamov.ru/ · http</div>
  <div class="inst-history" role="img" aria-label="Последние 20 проверок: одна с ошибкой">
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-tone="error"></span>
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-tone="ok"></span>
    <span class="inst-history-tick" data-tone="ok"></span>
  </div>
</div>

Правила

Так Итог словами в aria-label

«22 из 24 проверок успешны, последняя с ошибкой». Полоса без имени для скринридера не существует.

Не так Штрих на каждую секунду

Полоса показывает последние события, а не весь журнал. Двести штрихов по три пикселя — это шестьсот пикселей ряби, в которой ничего не видно.

Так Пустая история — серые штрихи

Проверок не было — это тоже состояние, и его видно.

Не так Цвет как единственный признак

Рядом с полосой стоит статус словом: бейдж или подпись. Полоса уточняет, а не сообщает.

Доступность

Имя role="img" плюс aria-label с итогом словами. Штрихи пусты и скринридеру не читаются — читается имя полосы
Цвет не единственный носитель Полоса стоит рядом со статусом словом. Сама по себе она уточнение: «падало дважды за сутки», а не «сейчас упало»
Контраст Тон берёт --tone-mark — порог 3:1 против поверхности, тот же, что у метки состояния
Движение Анимации нет: история — это состояние, а не процесс
Печать Печатается как есть: штрихи различаются тоном и на бумаге остаются серыми ступенями

API

ИмяЗначениеЧто делает
класс
inst-historyПолоса. Свежие исходы справа
inst-history-tickОдин исход: одна проверка, один прогон
inst-history-groupПачка штрихов с общим именем: час, день, прогон
атрибут
data-toneok · warn · error · running · neutralИсход штриха. Без атрибута штрих серый: проверка была, результат неизвестен
data-emptyПроверки не было. Место остаётся, метки нет
roleimgПолоса — картинка данных, и у неё обязано быть имя
токен
--nЧисло штрихов в группе. Задаёт её долю от полосы
--size-tick3px
--space-12px
--space-36px
--radius-xs3px
--tracklight-dark(oklch(0 0 0 / 0.10), oklch(1 0 0 / 0.16))
--size-icon16px

Почему кит устроен именно так — конституция · Открытый код под MIT, github.com/keshon/instrument