Перейти к содержимому
EN
Масштаб
Плотность
Тема
Акцент

Графики

Спарклайн

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

Компонент
Разметка
<svg class="inst-sparkline" viewBox="0 0 120 32" preserveAspectRatio="none" aria-hidden="true">
  <path class="inst-sparkline-area" d="M0,27 5,24 10,26 15,21 20,23 25,18 30,20 35,14 40,17 45,11 50,15 55,9 60,13 65,6 70,10 75,5 80,12 85,8 90,11 95,4 100,7 105,3 110,6 115,4 120,2 120,32 0,32Z"/>
  <path class="inst-sparkline-line" d="M0,27 5,24 10,26 15,21 20,23 25,18 30,20 35,14 40,17 45,11 50,15 55,9 60,13 65,6 70,10 75,5 80,12 85,8 90,11 95,4 100,7 105,3 110,6 115,4 120,2"/>
</svg>

Контракт

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

Что Обязательно Почему
viewBox да Без него SVG не масштабируется, и путь уезжает за границы
aria-hidden="true" или role="img" с aria-label да Третьего не дано: либо картинка декоративна и число рядом несёт значение, либо у неё есть имя
Прямые дети <svg> да Правила библиотеки написаны через & >: узел, завёрнутый в <g>, потеряет тон и толщину
inst-sparkline-area и -last нет Заливка и точка последнего значения необязательны

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

Доступность

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

Устройство

Узел Обязателен Работа
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,27 5,24 10,26 15,21 20,23 25,18 30,20 35,14 40,17 45,11 50,15 55,9 60,13 65,6 70,10 75,5 80,12 85,8 90,11 95,4 100,7 105,3 110,6 115,4 120,2 120,32 0,32Z"/>
  <path class="inst-sparkline-line" d="M0,27 5,24 10,26 15,21 20,23 25,18 30,20 35,14 40,17 45,11 50,15 55,9 60,13 65,6 70,10 75,5 80,12 85,8 90,11 95,4 100,7 105,3 110,6 115,4 120,2"/>
  <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,27 5,24 10,26 15,21 20,23 25,18 30,20 35,14 40,17 45,11 50,15 55,9 60,13 65,6 70,10 75,5 80,12 85,8 90,11 95,4 100,7 105,3 110,6 115,4 120,2 120,32 0,32Z"/>
    <path class="inst-sparkline-line" d="M0,27 5,24 10,26 15,21 20,23 25,18 30,20 35,14 40,17 45,11 50,15 55,9 60,13 65,6 70,10 75,5 80,12 85,8 90,11 95,4 100,7 105,3 110,6 115,4 120,2"/>
  </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>

API

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

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