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

Начало

Установка

Библиотека подключается двумя тегами и не требует сборки. Ниже — целая страница, которую можно скопировать и открыть.

Установка

Три способа. Файл во всех трёх один и тот же.

npm

npm i @keshon/instrument
import '@keshon/instrument/min';        // dist/instrument.min.css
import '@keshon/instrument/js';         // поведение, по желанию

Пакет также экспортирует несжатый CSS (@keshon/instrument), спрайт (@keshon/instrument/sprite.svg) и исходники (@keshon/instrument/src/*).

CDN

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@keshon/instrument@0.9.0/dist/instrument.min.css">

Версия в адресе указывается точно. @latest кэшируется на неделю и может обновиться в произвольный момент.

Файлом

<link rel="stylesheet" href="instrument.min.css">

Возьмите dist/instrument.min.css — 120 КБ, 19 КБ в gzip. Это вся библиотека: токены, пять тем, пять масштабов, три плотности, все компоненты. dist/instrument.css — то же самое без сжатия и с комментариями.

С иконкой

Иконка рисуется ссылкой на символ: <use href="#i-refresh">. Символы должны быть в самом документе: ссылка вида href="https://cdn…/sprite.svg#i-refresh" подчиняется правилу одного источника и не отрисуется — без ошибки в консоли.

Вставьте содержимое assets/sprite.svg первым элементом внутри <body> — один раз на страницу.

<body>
  <svg class="inst-sprite" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg">
    <!-- сюда содержимое assets/sprite.svg -->
  </svg>

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

Поведение с клавиатуры

<script type="module" src="instrument.js"></script>

Отдельный файл и по желанию. Он выполняет то, что библиотека обещает разметкой: стрелки в списках и вкладках, копирование, снятие тега, перетаскивание оси. Оформление он не трогает. Подробности — в поведении.

Целая страница

<!doctype html>
<html lang="ru">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Моё приложение</title>
  <link rel="stylesheet" href="instrument.min.css">
  <script type="module" src="instrument.js"></script>
</head>
<body>
  <div class="inst-shell">
    <header class="inst-shell-header">
      <strong>Моё приложение</strong>
      <button class="inst-btn inst-btn--primary" type="button">Запустить</button>
    </header>

    <main class="inst-shell-main">
      <div class="inst-container">
        <div class="inst-panel">
          <div class="inst-panel-header">
            <span class="inst-panel-title">Очередь</span>
          </div>
          <div class="inst-panel-body">
            <div role="listbox" aria-label="Очередь задач">
              <div class="inst-task" role="option" data-state="running"
                   aria-selected="true" tabindex="0">
                <span class="inst-task-gutter"><span class="inst-dot"></span></span>
                <span class="inst-task-main">
                  <span class="inst-task-title">Разбор карты высот</span>
                  <span class="inst-task-sub">terrain/heightmap.ts</span>
                </span>
                <span class="inst-task-meta">2,1 с</span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </main>
  </div>
</body>
</html>

Вот как это выглядит:

В контексте
Очередь
Разбор карты высот terrain/heightmap.ts 2,1 с
Сборка биомов —
Разметка
<div class="inst-panel">
  <div class="inst-panel-header">
    <span class="inst-panel-title">Очередь</span>
  </div>
  <div class="inst-panel-body">
    <div role="listbox" aria-label="Очередь задач">
      <div class="inst-task" role="option" data-state="running" aria-selected="true" tabindex="0">
        <span class="inst-task-gutter"><span class="inst-dot"></span></span>
        <span class="inst-task-main">
          <span class="inst-task-title">Разбор карты высот</span>
          <span class="inst-task-sub">terrain/heightmap.ts</span>
        </span>
        <span class="inst-task-meta">2,1 с</span>
      </div>
      <div class="inst-task" role="option" data-state="queued" aria-selected="false" tabindex="-1">
        <span class="inst-task-gutter"><span class="inst-dot"></span></span>
        <span class="inst-task-main">
          <span class="inst-task-title">Сборка биомов</span>
        </span>
        <span class="inst-task-meta">—</span>
      </div>
    </div>
  </div>
</div>

Тема и плотность

Оба — атрибуты, и оба работают на любом поддереве, а не только на документе.

<html data-theme="dark">              <!-- пять тем; без атрибута — по настройке ОС -->
<html data-accent="clay">             <!-- петроль (умолчание) · graphite · indigo · clay -->
<section data-density="compact">      <!-- compact · comfortable -->
Тема
light-neutral light light-cool светлые: нейтральная, тёплая, холодная
dark-soft dark тёмные, различаются глубиной поверхностей

Без атрибута тема выбирается по настройке ОС. Что именно меняет каждая ручка — в цвете и плотности.

Ваши стили выигрывают

Библиотека целиком лежит в каскадных слоях, а ваши стили — вне их. Поэтому любое ваше правило перебивает её, и !important не нужен нигде.

.inst-btn { border-radius: 0; }   /* сработает, специфичность неважна */

Порядок слоёв — в токенах.

Требования

Chrome 123+, Safari 17.5+, Firefox 128+ — по light-dark(), oklch(), каскадным слоям, вложенности, :has(), единице lh и @property. Полифилов нет.

Границу держит @property: незаследуемое пользовательское свойство — это то, чем колонка говорит своим детям, что они меряются содержимым, не перечисляя их по именам. Firefox умеет его с 128, остальные два браузера — задолго до своих порогов выше.

Дальше

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

Оболочка приложения — шапка, боковая панель, основная область.

Принципы дизайна — правила, из которых выводятся компоненты.

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