CSS модули
CSS модули — это популярная система для модульности и компоновки CSS. vue-loader предоставляет первоклассную интеграцию с CSS модулями как возможную альтернативу эмулируемого scoped CSS.
Использование
Просто добавьте атрибут module к тегу :
style module> .red < color: red; > .bold < font-weight: bold; > style>
Это включит режим CSS-модулей в css-loader , и полученный индентификатор объекта класса будет внедрен в компонент как вычисляемое свойство с именем $style . Вы можете использовать его в своих шаблонах для динамического добавления классов:
template> p :class="$style.red"> Этот текст будет красным p> template>
Поскольку это вычисляемое свойство, оно также будет работать с объектом/массивом в :class :
template> div> p :class="< [$style.red]: isRed >"> Буду ли я красным? p> p :class="[$style.red, $style.bold]"> Красный и жирный p> div> template>
Вы также можете получить доступ в JavaScript:
script> export default < created () < console.log(this.$style.red) // -> "_1VyoJ-uZOjlOxP7jWUy19_0" // идентификатор генерируется на основе имени файла и className. > > script>
Указание внедряемого имени модуля
У вас может быть более одного тега в одном *.vue компоненте. Во избежание перезаписи внедряемых стилей вы можете указать имя внедряемого вычисляемого свойства в значении атрибута module :
style module="a"> /* идентификатор будет внедрён как a */ style> style module="b"> /* идентификатор будет внедрён как b */ style>
Настройка параметров css-loader
CSS-модули обрабатываются с помощью css-loader. При использовании настройки css-loader по умолчанию будут такими:
< modules: true, importLoaders: 1, localIdentName: '[hash:base64]' >
Вы можете использовать в vue-loader опцию cssModules чтобы добавить дополнительные параметры для css-loader :
module: < rules: [ < test: '\.vue$', loader: 'vue-loader', options: < cssModules: < localIdentName: '[path][name]---[local]---[hash:base64:5]', camelCase: true > > > ] >
results matching » «
No results matching » «
Что такое CSS-модули и зачем они нам?
В последнее время меня интригуют CSS-модули. Если вы о них не слышали — эта статья для вас. Мы рассмотрим, что это за проект, какие задачи он решает и каковы причины его возникновения. Если вы тоже заинтриговались — не переключайтесь, следующая статья будет о том, как начать их применять. А если вас интересует внедрение в проект или более продвинутое использование CSS-модулей, третья статья в этой серии будет о том, как использовать их c React.
Серия статей
Часть 1: Что такое CSS-модули и зачем они нам? (Вы её читаете!)
Что такое CSS-модули?
Согласно определению из репозитория, CSS-модули — это:
CSS-файлы, в которых все классы и анимации по умолчанию находятся в локальной области видимости.
CSS-модули — это не официальная спецификация, они не имплементированы в браузеры, скорее, это задача, запускаемая на стадии сборки проекта (например, с помощью Webpack или Browserify), в процессе выполнения которой имена классов и селекторы изменяются так, чтобы образовалась своего рода локальная область видимости (что-то вроде пространства имен).
Как это выглядит и зачем нам это? Сейчас расскажу. Во-первых, вспомните как обычно работают HTML и CSS. Класс прописывается в HTML:
h1 class="title">Пример заголовка h1>
И стилизуется в CSS:
.title < background-color: red; >
Пока CSS применяется к HTML-документу, фон будет красным. Нам не нужно как-то обрабатывать CSS или HTML, оба формата понятны браузеру.
CSS-модули используют другой подход. Вместо того, чтобы писать обычный HTML, нам придётся написать разметку в JavaScript-файле, например, в index.js . Вот как это может выглядеть (ниже мы рассмотрим более реальные примеры):
import styles from "./styles.css"; element.innerHTML = `$ "> Пример заголовка `
;
В процессе сборки компилятор проанализирует styles.css , который мы импортировали, потом проанализирует JavaScript и сделает класс .title доступным через styles.title . Затем сгенерирует на их основе новые HTML и CSS-файлы, уже с новыми классами.
Сгенерированный HTML может выглядеть следующим образом:
h1 class="_styles__title_309571057"> Пример заголовка h1>
А вот так может выглядеть CSS:
._styles__title_309571057 < background-color: red; >

Значение атрибута class и селектор .title заменены на новые. Исходный CSS в браузер вообще не попадает.
Как сказал Хьюго Жироде́ль (Hugo Giraduel) в своей статье по этому поводу:
[классы] генерируются автоматически, они уникальны и привязаны к исходным стилям.
Вот это и называется поместить стили в локальную область видимости. Они находятся в области видимости определенного шаблона. Если у нас есть файл buttons.css , он будет импортирован только в шаблон buttons.js , и класс .btn , который он содержит, будет недоступен для других шаблонов (например, forms.js ), пока мы не импортируем его и туда тоже.
Зачем нам устраивать всю эту канитель с CSS и HTML? Зачем нам это вообще сдалось, ради всего святого?!
Зачем нам нужно использовать CSS-модули?
CSS-модули гарантируют, что все стили одного компонента:
- Находятся в одном месте
- Применяются только к этому компоненту и никакому другому
Кроме того, каждый компонент может иметь настоящие зависимости, например:
import buttons from "./buttons.css"; import padding from "./padding.css"; element.innerHTML = `$ $ ">`;
Этот подход был разработан, что бы решить проблему глобальной области видимости в CSS
Вы когда-нибудь испытывали соблазн в условиях нехватки времени или ресурсов просто писать CSS так быстро, как можете, не думая о последствиях?
Пихали ли в конец таблицы стилей какой-нибудь мусор, собираясь потом его отрефакторить, и так никогда этого и не сделали?
Бывало ли такое, что вы просматривали стили, не до конца понимая что они делают и используются ли они вообще?
Задумывались ли вы, получится ли избавиться от некоторых стилей, ничего при этом не сломав? Не приходилось ли гадать, эти стили работают сами по себе или зависят от других? Случалось ли вам перезаписывать стили?
Это вопросы, которые могут привести к серьезной головной боли, пропущенным дедлайнам и грустным взглядам в окно.
С CSS-модулями и концепцией использования локальной области видимости по умолчанию таких проблем можно избежать. Вам всегда приходится думать о последствиях, когда вы пишите стили.
Например, если вы используете в HTML класс random-gross-class , не обработав его как класс CSS-модуля, стили не применятся, так как CSS-селектор превратится во что-то вроде ._style_random-gross-class_0038089 .
Ключевое слово composes
Допустим, у нас есть модуль под названием type.css , содержащий стили для текста. В этом файле может быть, например, такое:
.serif-font < font-family: Georgia, serif; > .display < composes: serif-font; font-size: 30px; line-height: 35px; >
Один из этих классов мы используем в шаблоне:
import type from "./type.css"; element.innerHTML = `$ "> Пример заголовка `
;
В результате получится такая разметка:
h1 class="_type__display_0980340 _type__serif_404840"> Пример заголовка h1>
Оба класса связаны с элементом через использование ключевого слова composes , решая таким образом некоторые проблемы, которые есть в похожих решениях, например в @extend Sass.
Так можно даже подставлять данные из отдельного CSS-файла:
.element < composes: dark-red from "./colors.css"; font-size: 30px; line-height: 1.2; >
БЭМ не нужен
Нам не нужен БЭМ, если мы используем CSS-модули. По двум причинам:
- Простота чтения. Код вроде type.display так же понятен для разработчика, как и .font-size__serif—large из БЭМ. Его даже проще читать, чем разросшиеся БЭМ-селекторы.
- Локальная область видимости. Допустим, в одном из модулей у нас есть класс .big и он увеличивает font-size на некоторую величину. В другом модуле у нас есть точно такой же класс .big , который увеличивает padding и font-size на другую величину. И это не имеет никакого значения! Они не будут конфликтовать, так как у стилей различаются области видимости. Даже если модуль импортирует обе таблицы стилей, у классов будет своё уникальное имя, созданное в процессе сборки специально для них. Другими словами, при использовании CSS-модулей проблемы специфичности селекторов просто исчезают.
И это только некоторые из достоинств использования CSS-модулей.
Если вам интересно узнать больше, Глен Маден (Glen Madden) много пишет на эту тему.
В следующей статье из этой серии мы рассмотрим как поднять проект используя Webpack и CSS-модули. Мы будем использовать для этого новейшие возможности ES2015 и рассмотрим в процессе несколько примеров, чтобы в полной мере разобраться в происходящем.
Материалы для дальнейшего изучения
- CSS-модули: Добро пожаловать в будущее
- Руководство по CSS-модулям Хьюго Жирауделя (Hugo Giraudel) на Sitepoint
- Разбираемся с модулями в ES6
- Учим ES2015
- Знакомимся с синтаксисом модулей ES6
# CSS модули
— это популярная система для модульности и компоновки CSS. vue-loader предоставляет первоклассную интеграцию с CSS модулями как возможную альтернативу эмулируемого локального (scoped) CSS.
# Использование
Во-первых, CSS модули нужно явно включить, передав опцию modules: true в css-loader :
// webpack.config.js module: rules: [ // . другие правила опущены test: /\.css$/, use: [ 'vue-style-loader', loader: 'css-loader', options: // включаем CSS модули modules: true, // настраиваем генерируемое имя класса localIdentName: '[local]_[hash:base64:8]' > > ] > ] > >
Затем, добавляем атрибут module к тегу секции :
style module> .red color: red; > .bold font-weight: bold; > style>
Атрибут module подскажет Vue Loader о необходимости внедрить CSS модуль в компонент в качестве вычисляемого свойства с именем $style . Вы можете использовать его в шаблонах для динамического добавления классов:
template> p :class="$style.red"> Текст должен быть красным p> template>
Поскольку это вычисляемое свойство, оно будет работать с объектом/массивом в :class :
template> div> p :class="< [$style.red]: isRed >"> Буду ли я красным? p> p :class="[$style.red, $style.bold]"> Красный и жирный p> div> template>
Вы также можете получить доступ в JavaScript:
script> export default created () console.log(this.$style.red) // -> "red_1VyoJ-uZ" // идентификатор генерируется на основе имени файла и className. > > script>
для получения информации о глобальных исключениях
# Опциональное использование
Если вы хотите использовать CSS модули только в некоторых компонентах Vue, вы можете использовать правило oneOf и проверять наличие строки module внутри resourceQuery :
// webpack.config.js -> module.rules test: /\.css$/, oneOf: [ // это соответствует `` resourceQuery: /module/, use: [ 'vue-style-loader', loader: 'css-loader', options: modules: true, localIdentName: '[local]_[hash:base64:5]' > > ] >, // это соответствует простому `` или `` use: [ 'vue-style-loader', 'css-loader' ] > ] >
# Использование с пре-процессорами
CSS модули могут быть использованы вместе с другими пре-процессорами:
// webpack.config.js -> module.rules test: /\.scss$/, use: [ 'vue-style-loader', loader: 'css-loader', options: modules: true > >, 'sass-loader' ] >
# Указание имени внедряемого модуля
У вас может быть несколько тегов в одном компоненте *.vue . Во избежание перезаписи внедряемых стилей вы можете указать имя внедряемого вычисляемого свойства в значении атрибута module :
style module="a"> /* идентификатор будет внедрён как a */ style> style module="b"> /* идентификатор будет внедрён как b */ style>
Практическое руководство по использованию CSS Modules в React приложениях
Привет Хабр! Предлагаю вашему вниманию свободный перевод статьи «Practical Guide to React and CSS Modules» от Tatu Tamminen.
В прошлом веб-разработчики тратили много времени и сил на создание повторно используемых компонентов. Оcобую проблему представлял собой CSS и природа его каскадов. Например, если разработчик создаёт компонент для отображения древовидной структуры, то как он может гарантировать, что CSS класс (например, .leaf), используемый в этом компоненте, не приведёт к побочным эффектам в других частях приложения? Были созданы различные методологии и соглашения, чтобы справиться с проблемами селекторов. БЭМ и SMACSS — широко используемые методологии, которые хорошо выполняют свои задачи, но в то же время далеко не идеальны. В этой статье рассказывается о недостатках таких методологий, основанных на соглашении об именах, о том, что представляют собой CSS Modules, и о том, как эти модули можно использовать в React приложении.
Проблема с каскадами
Давайте создадим повторно используемый компонент select в качестве примера, иллюстрирующего проблемы глобальных стилей. Стилизация элемента напрямую — это плохое решение, поскольку в других местах сайта нам может потребоваться или изначальный нестилизованный элемент, или совсем другая его стилизация. Вместо этого можно использовать синтаксис БЭМ для определения классов:
.select <> .select__item <> .select__item__icon <> .select--loading <>
Если бы новый класс item был создан без префикса select__, то у всей команды могли бы возникнуть проблемы, если бы кто-нибудь захотел использовать такое же имя item. При этом неважно, разработчик ли пишет CSS или же его генерирует какая-то утилита. Использование БЭМ помогает решить эту проблему, вводя контекст для элемента select.
Синтаксис БЭМ является шагом вперёд по направлению к компонентам, так как «Б» в БЭМ расшифровывается как «Блок», а блоки можно интерпретировать как легковесные компоненты. Select — это компонент, у которого есть различные состояния (select—loading) и потомки (select__item).
К несчастью, использование соглашений по именованию и мышление в терминах компонентов не решает всех проблем селекторов. Коллизии имён всё ещё не гарантированы, а семантическая избыточность имён увеличивает риск опечаток и требует дисциплинированной команды, где каждый на все сто процентов понимает соглашения. Опечатки включают в себя использование одного дефиса вместо двух, путаницу между модификатором (—) и блоком (__) и прочее.
CSS Modules спешат на помощь
«CSS модуль» определяется следующим образом:
CSS модуль — это CSS файл, в котором все имена классов и анимаций имеют локальную область видимости по умолчанию.
Ключевая идея здесь — локальная область видимости.
Чтобы проиллюстрировать эту концепцию, давайте создадим JavaScript и CSS файлы компонента.
/* select.css */ .select <> .loading <> .item <> .icon <>
/* select.js */ import styles from "./select.css"; console.log(styles.select, styles.loading);
Это простой пример, который, однако, содержит много всего, происходящего за сценой.
Теперь CSS файл содержит намного меньше шума, чем в БЭМ версии, потому что в нём больше нет префиксов и специальных символов, задающих контекст. Почему же стало возможным удалить префикс .select—, не создавая при этом проблем?
Оператор import в JavaScript файле загружает CSS файл и конвертирует его в объект. В следующем разделе мы рассмотрим, как настроить рабочее окружение, позволяющее импортировать CSS файлы.
Каждое имя класса из CSS файла является свойством объекта. В примере выше это styles.select, styles.icon и т. д.
Если имя свойства — это имя класса, то какое же значение у этого свойства? Это уникальное имя класса, и уникальность обеспечивает то, что стили не «протекают» в другие компоненты. Вот пример хешированного имени класса: _header__1OUvt.
Вы можете подумать: «Какой ужас!» В чём смысл изменения осмысленного имени класса на непонятный хеш? Основная причина в том, что такой идентификатор гарантированно является уникальным в глобальном контексте. Позднее в этом руководстве мы изменим механизм создания идентификаторов, так что они будут иметь более осмысленный вид, но при этом останутся уникальными.
Вот ключевые преимущества использования CSS с локальной областью видимости:
- шаг вперёд по направлению к модульным и повторно используемым компонентам без побочных эффектов,
- более чистый CSS,
- избегание монолитных CSS файлов, так как у каждого компонента будет свой файл со стилями.
- сложнее читать и понимать DOM,
- требуется некоторая начальная настройка окружения, чтобы заставить всё это работать.
Для простоты в этой статье мы остановимся на сборщике модулей Webpack и библиотеке React.
React, Webpack и CSS Modules
Для быстрого создания приложения можно использовать Create React App.
Следуя инструкциям в документации, мы создадим и запустим новый проект практически мгновенно.
npm install -g create-react-app create-react-app css-modules cd css-modules/ npm start
Вуаля, и у нас работающее React приложение:
Начальная страница сообщает нам, что нужно редактировать файл App.js.
import React, < Component >from 'react'; import logo from './logo.svg'; import './App.css'; class App extends Component < render() < return (
className="App-logo" alt="logo" /> Welcome to React
To get started, edit and save to reload.
); > > export default App;
Используются ли CSS Modules в Create React App? Это можно узнать, взглянув на файл App.js. CSS файл импортируется, но не присваивается никакой переменной, при этом во всех атрибутах className используются строки вместо динамических значений.
С этой точки зрения Create React App не поддерживает CSS Modules, так что нужно изменить конфигурацию, чтобы включить эту поддержку.
Настройка Create React App для поддержки CSS Modules
Чтобы получить доступ к скрытому конфигу сборки, нужно выполнить команду eject. Внимание: если вы сделали это, то вернуться обратно вы уже не сможете.
npm run eject
Теперь можно открыть папку с конфигами для webpack:
Create React App использует webpack для сборки, поэтому webpack.config.dev.js — тот самый файл, который нужно изменить (а также webpack.config.prod.js для настроек продакшна — прим. переводчика).
Найдём раздел, задающий, что делать с CSS файлами (в оригинальной статье используется старый синтаксис конфигов webpack, здесь же я использовал новый — прим. переводчика):
< test: /\.css$/, use: [ require.resolve('style-loader'), < loader: require.resolve('css-loader'), options: < importLoaders: 1, >, >, < loader: require.resolve('postcss-loader'), options: < // Necessary for external CSS imports to work // https://github.com/facebookincubator/create-react-app/issues/2677 ident: 'postcss', plugins: () =>[ require('postcss-flexbugs-fixes'), autoprefixer(< browsers: [ '>1%', 'last 4 versions', 'Firefox ESR', 'not ie < 9', // React doesn't support IE8 anyway ], flexbox: 'no-2009', >), ], >, >, ], >,
Когда мы изменим этот раздел, как показано ниже, то это на мгновение разрушит стилизацию сайта, поскольку будет включена поддержка CSS Modules, но требуются ещё изменения в самом компоненте. При изменении конфига webpack, можно изменить правило именования CSS классов, чтобы в них была и читаемая часть, и хеш для обеспечения уникальности:
< test: /\.css$/, use: [ require.resolve('style-loader'), < loader: require.resolve('css-loader'), options: < importLoaders: 1, modules: true, localIdentName: "[name]__[local]___[hash:base64:5]" >, >, < loader: require.resolve('postcss-loader'), options: < // Necessary for external CSS imports to work // https://github.com/facebookincubator/create-react-app/issues/2677 ident: 'postcss', plugins: () =>[ require('postcss-flexbugs-fixes'), autoprefixer(< browsers: [ '>1%', 'last 4 versions', 'Firefox ESR', 'not ie < 9', // React doesn't support IE8 anyway ], flexbox: 'no-2009', >), require('postcss-modules-values'), ], >, >, ], >,
Что делают эти загрузчики loaders? В файле webpack.config есть закомментированная секция, описывающая загрузчики стилей и CSS:
postcss-loader применяет autoprefixer к CSS.
style-loader преобразовывает CSS в JS модули, которые инжектят теги .
css-loader разрешает пути в CSS и добавляет ресурсы как необходимые зависимости.
Опция modules: true в настройках css-loader включает поддержку CSS Modules. Параметр localIdentName изменяет шаблон имени класса таким образом, что оно включает в себя имя компонента React, имя класса и уникальный хеш-идентификатор. Это позволит производить отладку намного легче, потому что легко можно идентифицировать все компоненты.
Использование CSS Modules в React
Можно проверить, что конфигурация работает, добавив вызов console.log после оператора import.
Заменяя import ‘./App.css’; на
import styles from './App.css'; console.log(styles);
мы получаем следующий вывод в консоль браузера:
Сейчас классы уникальны, но они не используются в React компонентах. Нужно сделать ещё два шага, чтобы применить стили к React компонентам. Во-первых, нужно изменить имена классов согласно camelCase нотации. Во-вторых, нужно изменить атрибуты className так, чтобы они использовали импортированные классы.
Использовать camelCase нотацию необязательно, но при доступе к классам из JavaScript легче писать styles.componentName, чем styles[«component-name»].
Исходный файл стилей выглядит так:
.App < text-align: center; >.App-logo < animation: App-logo-spin infinite 20s linear; height: 80px; >.App-header < background-color: #222; height: 150px; padding: 20px; color: white; >.App-intro < font-size: large; >@keyframes App-logo-spin < from < transform: rotate(0deg); >to < transform: rotate(360deg); >>
Больше нет необходимости в префиксах App, поэтому сейчас хороший момент, чтобы удалить их тоже. Модифицированный CSS будет выглядеть так:
.app < text-align: center; >.logo < animation: logoSpin infinite 20s linear; height: 80px; >.header < background-color: #222; height: 150px; padding: 20px; color: white; >.intro < font-size: large; >@keyframes logoSpin < from < transform: rotate(0deg); >to < transform: rotate(360deg); >>
Следующий шаг — изменить использование классов в компоненте. Результат будет следующим:
import React, < Component >from 'react'; import logo from './logo.svg'; import styles from './App.css'; class App extends Component < render() < return ( > >
className= < styles.logo >alt="logo" /> Welcome to React
> To get started, edit and save to reload.
); > > export default App;
Теперь наш компонент использует CSS Modules.
Как нарушить границы CSS модуля, когда это необходимо
Подход, описанный в предыдущем разделе, является основным для React проектов, но разработчики обычно быстро обнаруживают, что им нужен способ выделять и использовать общие стили. В этом контексте «общие» значит лишь то, что компонент должен наследовать что-то от базовых стилей.
Эту общую информацию могут представлять собой переменные (цвета, размеры шрифта, и т. д.), хелперы (миксины SASS) или utility-классы.
CSS Modules дают возможность композиции с помощью ключевого слова from. Композиция возможна и между классами из разных файлов.
В следующем примере имеется два файла: один для базовых стилей кнопки и второй для реализации кнопки Submit. Можно сказать, что класс submitButton должен быть представлен через композицию базовых стилей кнопки и некоторых дополнительных свойств.
/* base_button.css */ .baseButton < border: 2px solid darkgray; background-color: gray; >/* submit_button.css */ .submitButton < composes: baseButton from "./base_button.css"; background-color: blue; >
Если есть необходимость в использовании переменных, то можно использовать или препроцессор, например, SASS или Less, или настроить поддержку переменных в webpack.
Пример из документации webpack по переменным в CSS:
/* variables.css */ @value blue: #0c77f8; @value red: #ff0000; @value green: #aaf200; /* demo.css */ /* import your colors. */ @value colors: "./variables.css"; @value blue, red, green from colors; .button
Этот пример можно изменить, используя собственные имена переменных. Это нужно потому, что переопределение стандартных значений, таких как blue, делает CSS файл менее понимаемым, так как больше нельзя быть уверенным, было ли переопределено какое-то значение или нет.
/* variables.css */ @value customBlue: #0c77f8; @value customRed: #ff0000; @value customGreen: #aaf200; /* demo.css */ /* import your colors. */ @value colors: "./variables.css"; @value customBlue, customRed, customGreen from colors; .button
Заключение
В этом руководстве мы начали с рассмотрения проблем глобального CSS, затем увидели, как CSS Modules улучшают ситуацию, вводя область видимости CSS и заставляя нас думать в терминах компонентов. Также мы рассмотрели, как легко можно начать экспериментировать с CSS Modules, используя React Starter Kit.
CSS Modules используются совместно со сборкой всего фронтэнда, то есть, с поддержкой в браузере нет никаких проблем. Браузеры получают обычный CSS от сервера, так что нет никакой возможности «сломать» сайт, используя CSS Modules. Наоборот, при этому мы только повышаем его надёжность, уменьшая количество потенциальных багов. Webpack с загрузчиками, сконфигурированными для поддержки CSS Modules, не создаёт никаких проблем, так что без сомнений можно рекомендовать этот инструмент к использованию.
Если вы использовали CSS Modules в своих проектах, я (то есть, автор оригинальной статьи — прим. переводчика) хотел бы услышать о вашем опыте!
→ Публикация — свободный перевод статьи «Practical Guide to React and CSS Modules». Автор статьи Tatu Tamminen
→ Исходный код можно найти в react-cssmodules-demo
→ Также заслуживает внимания CSS Modules Webpack Demo