При разработке интерфейсов на Mithril стили часто оказываются слабым
звеном архитектуры. Классический CSS по умолчанию глобален: любое имя
класса доступно везде, легко конфликтует, переопределяется и со временем
превращается в трудноуправляемый набор правил. В компонентной модели
Mithril, где интерфейс строится из независимых
view-функций, глобальные стили противоречат самой идее
изоляции.
Модульный CSS решает эту проблему за счёт локализации стилей на уровне компонентов. Каждый компонент получает собственное пространство имён для классов, что делает стили предсказуемыми, масштабируемыми и безопасными.
CSS Modules — это не отдельный стандарт CSS, а подход к сборке, при котором каждый CSS-файл компилируется в JavaScript-объект с отображением:
локальноеИмяКласса → сгенерированноеУникальноеИмя
Пример результата сборки:
{
button: "_button_9f3a1",
active: "_active_2d91c"
}
Исходный CSS:
.button {
padding: 8px 12px;
}
.active {
background: #1976d2;
}
В рантайме компонент работает уже не с глобальными классами, а с конкретными, уникальными идентификаторами.
Mithril не навязывает систему стилей и не содержит встроенных механизмов scoped-CSS. Это делает его особенно удобным для интеграции CSS Modules:
class или
className;CSS Modules органично дополняют философию Mithril: минимализм, явность, отсутствие скрытых абстракций.
Типичная структура компонента с модульным CSS:
Button/
Button.js
Button.module.css
Каждый компонент владеет своим CSS-файлом. Отсутствует необходимость
в общих styles.css, за исключением базовых токенов или
reset-стилей.
При использовании сборщика (Webpack, Vite, Rollup) CSS-модуль импортируется как обычный JavaScript-объект.
import styles from "./Button.module.css";
const Button = {
view(vnode) {
const { active } = vnode.attrs;
return m(
"button",
{
class: active
? `${styles.button} ${styles.active}`
: styles.button
},
vnode.children
);
}
};
export default Button;
Ключевые моменты:
styles — обычный объект;Сборщик отвечает за генерацию уникальных имён. Часто используется шаблон:
[filename]__[classname]__[hash]
Пример:
Button__button__9f3a1
Это:
В production-сборке имена обычно сокращаются до хешей для уменьшения размера.
В Mithril нет встроенного хелпера для классов, поэтому используются стандартные приёмы JavaScript.
Пример с несколькими состояниями:
const className = [
styles.button,
disabled && styles.disabled,
primary && styles.primary
].filter(Boolean).join(" ");
Такой код остаётся прозрачным и не требует сторонних библиотек.
CSS Modules поддерживают директиву composes, позволяющую
переиспользовать стили.
.base {
padding: 8px 12px;
border-radius: 4px;
}
.primary {
composes: base;
background: #1976d2;
color: white;
}
В Jav * aScript:
m("button", { class: styles.primary })
Композиция происходит на этапе сборки, не создавая вложенных селекторов и не увеличивая специфичность.
Иногда требуется задать глобальные правила: reset, типографика, стили
для body. CSS Modules позволяют явно обозначать глобальные
селекторы.
:global(body) {
margin: 0;
font-family: system-ui, sans-serif;
}
Или:
:global(.container) {
max-width: 1200px;
}
Это подчёркивает намерение и предотвращает случайное загрязнение глобального пространства.
Компоненты Mithril часто принимают внешние классы через
attrs. При использовании CSS Modules важно разделять
ответственность:
const Card = {
view({ attrs, children }) {
return m(
"div",
{
class: [styles.card, attrs.class].filter(Boolean).join(" ")
},
children
);
}
};
Внешний класс может быть как глобальным, так и модульным. Компонент остаётся универсальным.
CSS Modules не запрещают использование CSS-переменных. Напротив, они хорошо подходят для вынесения общих значений:
:global(:root) {
--color-primary: #1976d2;
--radius: 4px;
}
В модульных стилях:
.button {
background: var(--color-primary);
border-radius: var(--radius);
}
Так достигается баланс между локальностью компонентов и единым визуальным языком.
В модульном CSS исчезает необходимость полагаться на вложенные селекторы:
/* плохо */
.card .title {
font-weight: bold;
}
Предпочтительный вариант:
.card {}
.title {}
Каждый элемент получает собственный класс, явно привязанный в
view. Это уменьшает зависимость от структуры DOM и упрощает
рефакторинг компонентов Mithril.
По сравнению с inline-стилями CSS Modules:
По сравнению с CSS-in-JS:
Для Mithril, ориентированного на производительность и минимальный размер, это особенно важно.
При использовании SSR классы CSS Modules генерируются на этапе сборки, а не во время выполнения. Это гарантирует совпадение HTML и CSS между сервером и клиентом без дополнительных механизмов синхронизации.
Mithril, как фреймворк без жёсткой инфраструктуры, выигрывает от такой детерминированности.
styles.Каждый из этих пунктов снижает ценность модульного подхода.
Модульный CSS превращает стили в полноценную часть компонентной архитектуры. В сочетании с функциональной моделью Mithril он обеспечивает:
Стили перестают быть глобальной проблемой и становятся локальным, управляемым ресурсом каждого компонента.