4. Стили и токены
Сюда попадают изменения CSS-токенов (2 уровня), CSS Layers (ITCSS), интеграции с Tailwind, публичных импортов ./styles/....
Цвета в CSS-переменных — готовые значения, а не каналы RGB
⚠️ BREAKING —
--cds-color-*и--cds-alpha-*хранят готовый цвет (у встроенных тем —oklch()), обёрткаrgb()делает свойство невалидным.
Было (CDS 3):
// CDS 3
.my-block {
color: rgb(var(--cds-color-content-primary));
background: rgb(var(--cds-color-fill-secondary), 0.4);
}Стало (CDS 4):
// CDS 4
.my-block {
color: var(--cds-color-content-primary);
background: color-mix(in srgb, var(--cds-color-fill-secondary) 40%, transparent);
}Действие: заменить rgb(var(--cds-X)) / rgba(var(--cds-X)) на var(--cds-X), альфу поверх — на color-mix(…, transparent). Замену делает скилл cds-migrate (LDS-218); проверка — grep -rnE "rgba?\(\s*var\(--cds-" src пуст. Своя тема может задавать цвета в hex, rgb() или oklch() — значение попадёт в CSS как написано. Палитра-примитивы (utils/colors) удалена.
Изменён путь импорта CSS
⚠️ BREAKING — собранный
dist/cds.cssбольше не является публичной точкой входа.
Было (CDS 3):
// CDS 3
import '@central-design-system/components/dist/cds.css';Стало (CDS 4):
// CDS 4
import '@central-design-system/components/styles';Действие: заменить во всех приложениях-потребителях импорт @central-design-system/components/dist/cds.css на @central-design-system/components/styles. Поиск: grep -rn "@central-design-system/components/dist/cds.css" ..
Legacy reset вынесен в опциональный флаг
⚠️ BREAKING —
styles/utilities/legacy/legacy.scssтеперь содержит только утилитарные классы (display / layout / spacing / flexbox / typography); глобальный reset из CDS 3 больше не подключается по умолчанию.
Было (CDS 3):
// CDS 3 — legacy.scss тянул за собой полный глобальный reset
// (box-sizing, обнуление margin, list-style, media-query'и и т.д.)
// автоматически при подключении стилей CDS.
@use '@central-design-system/components/styles';Стало (CDS 4):
// CDS 4 — legacy.scss содержит только утилиты; старый reset вынесен
// в generic/_legacy-reset.scss и выключен по умолчанию.
// Чтобы вернуть поведение CDS 3, передайте $legacy-reset через with():
@use '@central-design-system/components/styles' with (
$legacy-reset: true
);Действие: если приложение полагалось на глобальный reset из CDS 3 (обнулённые margin, list-style: none, box-sizing: border-box на * и т.д.) — включите его явно через $legacy-reset: true в settings (см. src/styles/settings/_variables.scss). Иначе — проверьте вёрстку и доверьтесь нативным дефолтам браузера.
CSS-архитектура переписана на ITCSS + CSS Layers
⚠️ BREAKING — порядок каскада теперь определяется нативными
@layer. Глобальные переопределения стилей CDS, написанные без!important, могут сработать иначе.
Было (CDS 3):
// CDS 3 — плоская структура без cascade layers.
// Все стили компонентов и утилит грузились в обычный каскад,
// побеждал последний по специфичности / порядку импорта.
@import '@central-design-system/components/dist/cds.css';
// Переопределение приходилось делать через повышение специфичности
// или !important:
.cds-button { color: red !important; }Стало (CDS 4):
// CDS 4 — ITCSS + нативные CSS Layers.
// Каскад: cds-core → cds-components → cds-overrides → cds-utilities,
// см. src/styles/generic/_layers.scss.
@use '@central-design-system/components/styles';
@layer cds-overrides {
.cds-button { color: red; }
}Действие: ознакомиться с ITCSS и порядком слоёв в src/styles/generic/_layers.scss (cds-core → cds-components → cds-overrides → cds-utilities c вложенными theme-base, helpers, grid, tailwind, theme-background, theme-foreground). Проверьте свои глобальные переопределения CDS — если они были написаны без !important и полагались на порядок импорта, теперь они гарантированно перебивают @layer cds-components. Для контролируемого переопределения используйте слой cds-overrides (через @include tools.layer('overrides') { … }) — он специально расположен между компонентами и утилитами.
Утилитарные классы CDS 3 отключены по умолчанию
⚠️ BREAKING — классы
cds-flex,cds-flex-col,cds-px-4,cds-my-*, цветов, типографики и т. п. больше не подключаются автоматически.
Было (CDS 3):
// CDS 3
import '@central-design-system/components/dist/cds.css';
import { createCds } from '@central-design-system/components';
app.use(createCds());<!-- CDS 3 -->
<div class="cds-flex cds-flex-col cds-px-4">…</div>Стало (CDS 4):
// CDS 4 — временно включить легаси-утилиты на период миграции
import '@central-design-system/components/styles';
import '@central-design-system/components/styles/legacy';
import { createCds } from '@central-design-system/components';
app.use(createCds({
theme: { legacyClasses: true },
}));Действие: мигрировать на Tailwind CSS v4 (см. запись «Интеграция с Tailwind CSS v4» ниже). На переходный период включите легаси-утилиты комбинацией theme: { legacyClasses: true } в createCds() + импорт @central-design-system/components/styles/legacy. Источник: src/styles/utilities/legacy/legacy.scss (display, layout, spacing, flexbox, typography).
Интеграция с Tailwind CSS v4
✨ NEW — CDS из коробки поставляет конфигурацию Tailwind v4 с design-токенами как утилитарными классами.
Было (CDS 3):
<!-- CDS 3 — собственные утилитарные классы CDS -->
<div class="cds-flex cds-flex-col cds-px-4 cds-text-surface-primary">…</div>Стало (CDS 4):
/* CDS 4 — main.css */
@import "@central-design-system/components/styles/tailwind";
@import "tailwindcss/theme" layer(cds-utilities.tailwind);
@import "tailwindcss/utilities" layer(cds-utilities.tailwind);<!-- CDS 4 — Tailwind v4 + CDS-токены как утилиты -->
<div class="flex flex-col p-4 text-surface-primary">…</div>Действие: установить Tailwind CSS v4 по официальной документации и подключить конфигурацию @central-design-system/components/styles/tailwind — она расширяет тему Tailwind токенами CDS (bg-surface-*, text-content-*, rounded-200, …) и автоматически реагирует на смену темы. Отступы пишутся стандартной числовой шкалой Tailwind (p-4, gap-2) — шкала отступов CDS с ней совпадает.
Семантика миксина cds-breakpoint-down выровнена с JS useDisplay
⚠️ BREAKING — в CDS 3 SCSS-миксин
cds-breakpoint-down($name)следовал конвенции «строго ниже начала брейкпоинта», а JS-composableuseDisplay— конвенции «брейкпоинт и всё, что ниже». Из-за этогоcds-breakpoint-down('sm')иdisplay.smDownпокрывали разные диапазоны (сдвиг на один брейкпоинт). В CDS 4 CSS выровнен под JS:down('<name>')теперь означает «<name>и ниже».
Было (CDS 3):
// CDS 3 — max-width = ширина САМОГО брейкпоинта − 0.02 («строго ниже sm»)
// down('sm') → @media (max-width: 671.98px) // только диапазон xs
// down('md') → @media (max-width: 1055.98px) // xs + sm
// down('lg') → @media (max-width: 1311.98px) // xs + sm + md
// НЕ совпадает с JS: display.smDown === (width < 1056)
.card { @include cds-breakpoint-down(sm) { display: none; } }Стало (CDS 4):
// CDS 4 — max-width = ширина СЛЕДУЮЩЕГО брейкпоинта − 0.02 («sm и ниже»)
// down('sm') → @media (max-width: 1055.98px) // xs + sm
// down('md') → @media (max-width: 1311.98px) // xs + sm + md
// down('lg') → @media (max-width: 1583.98px) // xs + sm + md + lg
// down('xl') → без media query (все ширины)
// Совпадает с JS: display.smDown === (width < 1056)
.card { @include cds-breakpoint-down(sm) { display: none; } }Действие: пройтись по использованиям cds-breakpoint-down(...) (и cds-breakpoint-between(...) с именованной нижней/верхней границей — она делегирует в тот же миксин). Если код полагался на старую логику «строго ниже названного брейкпоинта», сдвиньте аргумент на один вниз: старый down('md') ⇒ новый down('sm'), старый down('lg') ⇒ down('md') и т. д. Миксины cds-breakpoint-up / значения порогов (320 / 672 / 1056 / 1312 / 1584) не менялись. Поиск: grep -rnE "cds-breakpoint-down\(" src/.
Сетка и брейкпоинты заданы в px вместо rem
⚠️ BREAKING — в CDS 3 вся геометрия сетки (
$grid-gutter,marginиwidthбрейкпоинтов) прогонялась черезconvert.toRemи зависела от размера корневого шрифта. В CDS 4 значения намеренно заданы в px: каркас страницы не зависит отhtml { font-size }хоста, а CSS-медиазапросы гарантированно совпадают с px-порогами JS-композаблаuseDisplay(rem в медиазапросах считается от настройки шрифта браузера и расходится сwindow.innerWidth).
Было (CDS 3):
// CDS 3 — rem от корневого шрифта: хост с html { font-size: 14px }
// получал gutter 28px вместо 32px, а rem-медиазапросы срабатывали
// не там, где JS-логика в px
$grid-gutter: convert.toRem(32px); // 2rem
$grid-breakpoints: (
sm: (columns: 8, margin: convert.toRem(16px), width: convert.toRem(672px)),
// …
);Стало (CDS 4):
// CDS 4 — px: геометрия сетки стабильна в любом хосте и совпадает
// с порогами useDisplay (320 / 672 / 1056 / 1312 / 1584)
$grid-gutter: 32px;
$grid-breakpoints: (
sm: (columns: 8, margin: 16px, width: 672px),
// …
);Действие: в большинстве приложений ничего делать не нужно — браузерный зум масштабирует px-макет целиком. Если хост менял html { font-size } в расчёте на масштабирование сетки, этот механизм больше не работает: сетка и брейкпоинты фиксированы, масштабируемый слой — rem-токены --cds-spacing-* (отступы контента и типографика).
Переменные $standard-easing / $decelerated-easing / $accelerated-easing удалены
⚠️ BREAKING — кривые Material 2 из
settingsзаменены кривыми шкалы движения Luma:standard,enter,exit. Вместе с ними изtoolsубраны$cds-duration-*,get-motionиcds-animation-motion.
Было (CDS 3):
// CDS 3
@use '@central-design-system/components/styles/settings';
.panel {
transition: transform 300ms settings.$decelerated-easing;
}
.panel--closing {
transition: transform 200ms settings.$accelerated-easing;
}Стало (CDS 4):
// CDS 4
@use '@central-design-system/components/styles/motion';
.panel {
transition: transform motion.duration(normal) motion.easing(enter);
}
.panel--closing {
transition: transform motion.duration(fast) motion.easing(exit);
}Действие: убрать $standard-easing, $decelerated-easing и $accelerated-easing из @use '…/styles/settings' with (…) и из styles.configFile vite-плагина: теперь это ошибка Sass (переменная не объявлена в модуле, переопределить её нельзя). Дальше заменить settings.$standard-easing на motion.easing(standard), $decelerated-easing (появление) на motion.easing(enter), $accelerated-easing (уход) на motion.easing(exit), а литеральные длительности — на motion.duration(<ступень>) (instant 50 … very-slow 500). Поиск: grep -rnE "standard-easing|decelerated-easing|accelerated-easing|cds-duration-|get-motion|cds-animation-motion" src/. Значения для JS — motion.easings.* и motion.durations.* из @central-design-system/components. Гайд — «Анимации».
Анимации компонентов переведены на шкалу движения Luma
✨ NEW — все анимации компонентов идут по одной шкале: семь длительностей и кривые
standard/enter/exitвместо кривых Material 2. Публичные переменные вроде$select-transitionили$badge-transitionсохранили имя и форму значения (<длительность> <кривая>), поменялись значения по умолчанию. Не все$*-transitionимеют такую форму:$list-subheader-transition,$responsive-sizer-transitionи$progress-circle-overlay-transitionперечисляют свойства.
Было (CDS 3):
// CDS 3 — кривая Material 2 из settings
$select-transition: .2s settings.$standard-easing !default;Стало (CDS 4):
// CDS 4 — шкала Luma: ступень и кривая из модуля motion
@use '@central-design-system/components/styles/motion';
$select-transition: motion.duration(fast) motion.easing(standard);Действие: миграция не требуется. Если вы переопределяли переменные $*-transition или подстраивали тайминги под старые кривые, сверьтесь с таблицами шкалы в гайде «Анимации» и по возможности берите ступени вместо литералов. Переходы CdsTransition*, модалка (появление normal вместо 225ms, уход fast), тултипы (появление fast вместо 100ms) и тосты перенесены на ступени шкалы: часть значений стала короче, часть длиннее, поэтому единой «скорости» у них больше нет. При prefers-reduced-motion сдвиг и масштаб заменяются затуханием, а декоративные полосы striped у CdsProgressBar останавливаются (цикл неопределённого прогресса идёт как раньше).
Форма значения у $list-subheader-transition (<длительность> min-height <кривая>), $responsive-sizer-transition (padding-bottom <длительность> <кривая>) и $progress-circle-overlay-transition (список из свойств) включает свойства. У последней переменной теперь три элемента вместо двух (stroke-dashoffset, stroke, stroke-width 0s), и CdsProgressCircle рассчитывает на три: переопределение из двух элементов, оставшееся от CDS 3, анимирует stroke-width во время появления круга. Переопределяйте её целиком, тремя элементами.
surface-overlay непрозрачный, подложку разбавляет компонент
⚠️ BREAKING — во всех темах
--cds-color-surface-overlayстал непрозрачным: альфа (0.5 в светлых темах, 0.8 в тёмных) ушла из токена в компоненты. Это модель эталонной темыlumaLight.
Было (CDS 3):
// CDS 3 — полупрозрачность приходила из токена
.my-backdrop {
background: rgb(var(--cds-color-surface-overlay));
}Стало (CDS 4):
// CDS 4 — токен сплошной, долю задаёт потребитель
.my-backdrop {
background: color-mix(in srgb, var(--cds-color-surface-overlay) 50%, transparent);
}Действие: найти свои подложки на токене (grep -rn "surface-overlay" src) и разбавить их через color-mix(…, transparent) или opacity, иначе они закроют страницу сплошным цветом. Подложки CdsOverlay (модалки, диалоги), CdsDrawer, CdsLoader и кнопки CdsCarousel разбавляют токен сами, на общую долю $overlay-opacity (50%). У дровера она вынесена в $drawer-overlay-opacity. Вид меняется: подложка модалки в светлых темах темнее (50% вместо ~25%), подложки дровера и лоадера в тёмных темах светлее (50% вместо 80%).