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

Графики

Спарклайн

Форма изменения рядом с числом. Намеренно без осей, сетки и подписей: это не график, а вторая строка метрики. SVG, без JS.

Компонент
Разметка
<svg class="inst-sparkline" viewBox="0 0 120 32" preserveAspectRatio="none" aria-hidden="true">
  <path class="inst-sparkline-area" d="M0,26 12,22 24,24 36,16 48,18 60,10 72,13 84,7 96,9 108,4 120,6 120,32 0,32Z"/>
  <path class="inst-sparkline-line" d="M0,26 12,22 24,24 36,16 48,18 60,10 72,13 84,7 96,9 108,4 120,6"/>
</svg>

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

Путь приходит с сервера или из шаблона. Кит отвечает за тона и толщины и ничего не считает: d — это данные, ровно как ширина заливки у меры.

<svg class="inst-sparkline" viewBox="0 0 120 32" preserveAspectRatio="none" aria-hidden="true">
  <path class="inst-sparkline-line" d="M0,26 12,22 24,24 36,16 48,18 60,10 72,13 84,7 96,9 108,4 120,6"/>
</svg>
Что Обязательно Почему
viewBox да Без него SVG не масштабируется, и путь уезжает за границы
aria-hidden="true" или role="img" с aria-label да Третьего не дано: либо картинка декоративна и число рядом несёт значение, либо у неё есть имя
Прямые дети <svg> да Правила кита написаны через & >: узел, завёрнутый в <g>, потеряет тон и толщину
inst-sparkline-area и -last нет Заливка и точка последнего значения необязательны

preserveAspectRatio="none" — намеренно: спарклайн тянется по ширине контейнера, а высоту держит фиксированной. Именно поэтому штрих объявлен немасштабируемым — иначе растянутая линия становилась бы толще слева направо.

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

Используйте Возьмите другое
Тренд одного ряда под числом — направление, а не значения График, у которого спрашивают значения — как только понадобились оси, это уже полноценный график и он заслуживает своего места, а не строки под метрикой
Ряд из десятка-другого точек за понятный период Доля от целогомера или кольцо: у спарклайна нет потолка
Одна линия Два и более рядов — им нужна легенда, а легенде нужен график с осями
Число уже показано рядом — метрика Ряд, который читают по строкамтаблица: точные значения читаются цифрами, а не формой

Устройство

Узел Обязателен Работа
inst-sparkline да <svg> с viewBox. Ширина 100%, высота — четверть сверх контрола
inst-sparkline-line да Линия. vector-effect: non-scaling-stroke, поэтому растяжение по ширине не утолщает штрих
inst-sparkline-area нет Заливка под линией. Тот же путь, замкнутый вниз до нижнего края
inst-sparkline-last нет Точка последнего значения
Пример
Разметка
<svg class="inst-sparkline" viewBox="0 0 120 32" preserveAspectRatio="none" aria-hidden="true">
  <path class="inst-sparkline-area" d="M0,26 12,22 24,24 36,16 48,18 60,10 72,13 84,7 96,9 108,4 120,6 120,32 0,32Z"/>
  <path class="inst-sparkline-line" d="M0,26 12,22 24,24 36,16 48,18 60,10 72,13 84,7 96,9 108,4 120,6"/>
  <circle class="inst-sparkline-last" cx="120" cy="6" r="2.5"/>
</svg>

Порядок узлов внутри SVG — порядок отрисовки: заливка первой, линия поверх, точка последней. Поменяли местами — линия ушла под собственную заливку.

Заливка под линией — единственный разрешённый в ките градиент, и он не градиент: сплошной тон с альфой 0.12. Настоящий градиент сообщал бы, что величина меняется по вертикали, чего нет.

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

Варианты

Пример
Разметка
<svg class="inst-sparkline" viewBox="0 0 120 32" preserveAspectRatio="none" aria-hidden="true" style="--series:var(--chart-2)">
  <path class="inst-sparkline-area" d="M0,10 12,14 24,11 36,18 48,15 60,21 72,19 84,24 96,22 108,27 120,25 120,32 0,32Z"/>
  <path class="inst-sparkline-line" d="M0,10 12,14 24,11 36,18 48,15 60,21 72,19 84,24 96,22 108,27 120,25"/>
</svg>

Все три узла читают --series и без него берут --chart-1. Переменная ставится один раз на <svg>. Линия, заливка и точка одного ряда не имеют права разъехаться по цвету.

Номер ряда — часть контракта: первый ряд всегда --chart-1. Правила категориального цвета целиком — на странице палитры.

/* Ряд задаётся снаружи, а не переписыванием stroke */
.my-chart-2 { --series: var(--chart-2); }

Композиции

Под метрикой

В контексте
Токенов в сутки
184 тыс.
За 11 суток
Разметка
<div class="inst-card inst-stack inst-stack--tight">
  <div class="inst-metric-label">Токенов в сутки</div>
  <div class="inst-metric-value">184<span class="inst-metric-unit">&nbsp;тыс.</span></div>
  <svg class="inst-sparkline" viewBox="0 0 120 32" preserveAspectRatio="none" aria-hidden="true">
    <path class="inst-sparkline-area" d="M0,26 12,22 24,24 36,16 48,18 60,10 72,13 84,7 96,9 108,4 120,6 120,32 0,32Z"/>
    <path class="inst-sparkline-line" d="M0,26 12,22 24,24 36,16 48,18 60,10 72,13 84,7 96,9 108,4 120,6"/>
  </svg>
  <div class="inst-metric-label">За 11 суток</div>
</div>

В ячейке таблицы

<td>
  <svg class="inst-sparkline" viewBox="0 0 120 32" preserveAspectRatio="none" aria-hidden="true">
    <path class="inst-sparkline-line" d="M0,26 24,24 48,18 72,13 96,9 120,6"/>
  </svg>
</td>

Правила

Так Спарклайн про направление

Он отвечает на «растёт или падает». Число рядом отвечает на «сколько».

Не так Спарклайн, у которого спрашивают значения

Как только понадобились оси, это полноценный график — и он заслуживает своего места, а не строки под метрикой.

Так --series один раз на svg

Линия, заливка и точка одного ряда не имеют права разъехаться по цвету.

Не так Второй ряд в спарклайне

Два ряда требуют легенды, а легенда требует графика с осями.

Доступность

Имя Декоративный спарклайн — aria-hidden="true", и тогда значение обязано быть в тексте рядом. Самостоятельный — role="img" плюс aria-label с итогом словами: «Рост с 92 до 184 тысяч за 11 суток»
Цвет не единственный носитель Спарклайн один — цвет ничего не кодирует. Два ряда одним цветом различить нельзя, поэтому двух рядов у спарклайна и нет
Контраст Линия берёт категориальный тон и держит 3:1 против поверхности в шести темах. Заливка с альфой 0.12 — декоративная и на порог не проверяется: значение несёт линия
Толщина vector-effect: non-scaling-stroke — штрих остаётся 1.5 при любом растяжении, поэтому не истончается ниже видимого
Движение Анимации нет вовсе: график — это состояние, а не процесс

API

ИмяЗначениеЧто делает
класс
inst-sparkline<svg>. Обязателен: остальные классы работают только внутри него
inst-sparkline-lineЛиния ряда, штрих 1.5, немасштабируемый
inst-sparkline-areaЗаливка под линией, альфа 0.12
inst-sparkline-lastТочка последнего значения с кольцом поверхности
переменная
--series--chart-1Приёмник тона: линия, заливка и последняя точка читают её
токен
--chart-1light-dark(oklch(0.520 0.150 280), oklch(0.700 0.130 280))Тон ряда №1. Порядок — часть контракта
--chart-2light-dark(oklch(0.600 0.150 320), oklch(0.760 0.120 320))Тон ряда №2. Порядок — часть контракта
--chart-3light-dark(oklch(0.550 0.140 355), oklch(0.720 0.120 355))Тон ряда №3. Порядок — часть контракта
--chart-4light-dark(oklch(0.650 0.120 55), oklch(0.800 0.110 55))Тон ряда №4. Порядок — часть контракта
--chart-5light-dark(oklch(0.580 0.130 115), oklch(0.740 0.120 115))Тон ряда №5. Порядок — часть контракта
--chart-6light-dark(oklch(0.620 0.110 190), oklch(0.780 0.100 190))Тон ряда №6. Порядок — часть контракта
--control-h-md32pxВысота считается от неё: ×1.25
--surface-raisedlight-dark(var(--n-0), var(--n-12))Кольцо последней точки — цвет поверхности под ней
--size-marker2pxТолщина кольца последней точки

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