От автора: основная задача статьи – пройтись по всем этапам написания атомного CSS и разобрать некоторые сложные моменты. Мы будем использовать sass и angular 2.
Что такое атомный CSS?
На самом деле, речь идет не о atomic-css, а про способ написания CSS в атомном веб-дизайне. Предыдущее просто легче записать.
Существует множество стилей и шаблонов написания CSS в дизайне, у всех свои достоинства и недостатки. Не так давно мне показали концепцию Atomic CSS за авторством одного из лучших ведущих разработчиков, с которым мне довелась честь работать вместе, и я влюбился в эту идею. К сожалению, его больше нет с нами. Он в другом месте… Google.
Одно из главных преимуществ написания CSS в атомном стиле состоит в том, что вам больше не придется писать CSS код. Конечно, это немного преувеличено, но идея в том, что вы дойдете до такой точки, когда новые стили вам понадобятся только для создания крайне специфических и супер кастомизированных элементов.
Базовая концепция заключается в том, что на один класс есть одна пара свойства и значения. Такой класс называется атом.
1 2 3 |
.height20 { height: 20px; } |
Если нужно изменить высоту, просто добавляете еще один класс.
1 2 3 |
.height30 { height: 30px; } |
И бум, вот так. Можно пойти еще дальше и назвать классы h20 и h30.
Некоторым не нравятся сокращения, и они предпочитают семантику. Довольно спорная тема, тут решать только вам. Но как только сделали выбор, придерживайтесь его! Главное постоянство.
Кажется, что это слишком утомительно. Не хочу я сидеть и прописывать все возможные варианты высоты, которые я буду использовать. Это десятки, сотни строк кода. Я стал разработчиком, потому что ленивый. Давайте посмотрим, что с этим можно сделать.
SASS/SCSS
Генерацию таких классов можно автоматизировать через Sass.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
// heights.scss // Список наших пар ключ/значение $heights: ( 6: 0.375rem, 10: 0.625rem, 11: 0.688rem, 18: 1.125rem ); // Проходимся циклом и ключ уходит в имя // а значение уходит в значение свойства. @each $name, $val in $heights { .h#{$name} { height: #{$val}; } .min-h#{$name} { min-height: #{$val}; } } // heights.compiled.css .h6 { height: 0.375rem; } .h10 { height: 0.625rem; } .h11 { height: 0.688rem; } .h18 { height: 1.125rem; } .min-h6 { min-height: 0.375rem; } .min-h10 { min-height: 0.625rem; } .min-h11 { min-height: 0.688rem; } .min-h18 { min-height: 1.125rem; } |
Огромное преимущество атомного CSS в том, что он сдвигает обслуживание кода от просто стилей к шаблону. Если нужно поправить отступы на странице, то вам нужно отредактировать HTML, а не CSS.
В конце концов, вы создадите столько атомов, что вам больше не нужно будет писать CSS код.
Молекулы
Используемая группа атомов называется молекулой. Молекула – это не новый код, это просто шаблон повторяющихся классов. Молекула карточки может состоять из таких классов:
1 2 3 |
<div class="width-250 height-100 font-size-16 padding-5"></div> <!- или если вы любите сокращения -> <div class="w250 h100 f16 p5"></div> |
Что переводится в:
1 2 3 4 5 6 |
{ width: 250px; height: 100px; font-size: 16px; padding: 5px; } |
На первый взгляд слишком много букв, кажется, что будет трудно привыкнуть. Однако так у вас не будет проблемы, когда вам придется создать отдельный класс для «.card» только из-за того, что вам нужен «.card», который слегка отличается от остальных.
Angular 2
Если вы вообще не знакомы с Angular 2, сейчас я вам быстро расскажу про CSS.
В angular 2 есть такие вещи, называемые компоненты. Приложение начинается с одного главного/root компонента, а все остальные компоненты являются его потомками.
У компонентов могут быть свои стили, которые работают только на них. Если у FiltersCmp есть класс .hide, то TodosCmp не будет знать о нем. Вы можете спросить, как писать глобальные стили, если весь CSS код разграничен по компонентам? Мы хотим писать глобальные стили, чтобы они не ограничивались на отдельных компонентах.
Сделать атомные стили глобальными можно двумя способами. Самый простой – отдать всю работу angular. Сперва необходимо подключить scss в AppCmp. Затем устанавливаем свойство encapsulation декоратора @Component() в значение ViewEcapsulation.None. Так мы скажем angular 2, чтобы этот компонент не жадничал и поделился стилями с потомками, смежными компонентами и родителями, что сделает стили глобальными.
1 2 3 4 5 6 7 8 9 |
import { Component, ViewEncapsulation } from ‘@angular/core’; @Component({ selector: 'app', templateUrl: require('./app.component.html'), styles: [ require('./app.main.scss') ], encapsulation: ViewEncapsulation.None }) |
Вот тут есть загвоздка. Angular 2 вставляет теги style прямо в head в момент выполнения. Сначала может показаться, что все не так плохо, но как только вы начнете вникать в рендеринг на стороне сервера и SEO оптимизацию, вы поймете, что 120 000 строк CSS кода в файле index.html – плохая идея. Хотя, может, это не так, я не SEO эксперт.
К счастью, есть другой метод. Мы можем компилировать наш scss и сохранять его в отдельный файл main.css, после чего подключать его в html.
Компиляция и извлечение
В сети есть несколько инструментов, наподобие Gulp и Grunt. На мой взгляд, Webpack – самый простой, в нем очень просто разобраться. Я буду использовать webpack2, но с той же легкостью можно взять и webpack1.
Webpack работает в файле webpack.config.js. В этом конфиге мы говорим ему, чтобы он искал определенные файлы и обработал их с помощью загрузчиков. В нашем случае это scss файлы. Загрузчик – просто красивый термин для операций трансформации и других операций над файлами. По существу, это плагины, самая важная часть webpack.
Создайте файл app.main.scss на одном уровне с app.component.ts и импортируйте остальные scss файлы в него с помощью @import. Не забудьте удалить свойство styles из всех декораторов компонентов. Добавьте строку require(‘./path/to/app.main.scss’) в client.ts. Так webpack точно найдет эти scss файлы и обработает их так, как мы хотим.
Минус в том, что после импорта этих scss файлов в main.app.scss, относительные пути в других scss файлах должны относиться к main.app.scss.
SCSS должен превратиться в CSS, для этого его нужно прогнать через sass-loader. Мы будем тестировать только файл app.main.scss. Все другие scss файлы должны импортироваться в app.main.scss. Загрузчик может напрямую не знать о них.
1 2 3 4 5 6 7 |
module.exports = { module: { rules: [ { test: /app\.main\.scss/, loader: 'sass-loader' } ] } } |
Теперь наш scss превратился в CSS, но на этом этапе webpack еще не знает, что делать с этим css кодом. Нам придется добавить css-loader. Этот загрузчик также меняет все url адреса на адрес с вашей папкой ./dist, если у вас есть подходящий загрузчик для этих файлов. Или же можно использовать file-loader.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
module.exports = { module: { rules: [ { test: /app\.main\.scss/, loaders: [ { loader: 'css-loader', options: { importLoaders: 1 } }, 'sass-loader' ] } ] } } |
Теперь давайте добавим postcss, нам нужно добавить специфические префиксы браузеров в стили.
Поместите этот файл в корень проекта. Все, что он делает, это говорит postcss, что мы хотим использовать autoprefixer и поддерживать последние 6 версий браузеров. Префиксы -moz-, -webkit- и -ms- будут автоматически добавляться в нужных местах.
1 2 3 4 5 6 7 8 9 |
// postcss.config.js const autoprefixer = require('autoprefixer'); module.exports = { plugins: [ autoprefixer({ browsers: ['last 6 versions'] }) ] } |
С текущими настройками webpack обработает все наши scss файлы и вернет строку css. Сама строка бесполезна, если она не завернута в файл. Нам осталось извлечь скомпилированный css в нашу папку ./dist в отдельный файл.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
const ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports = { module: { rules: [ { test: /app\.main\.scss/, loaders: [ ExtractTextPlugin.extract({ loader: 'exports-loader?module.exports.toString()' }), { loader: 'css-loader', options: { importLoaders: 2 } }, 'postcss-loader', 'sass-loader' ] } ] }, plugins: [ new ExtractTextPlugin({ filename: 'assets/css/main.css', allChunks: true }) ], output: { path: './dist/client', filename: 'assets/[ext]/[name].[ext]' } } |
Ну вот и все. Почти завершенный webpack.config для извлечения полностью скомпилированного css из атомных scss файлов. Конечно, нужны еще загрузчики, которые будут транспилить исходники angular 2, но это тема для отдельного поста.
Автор: Vitaliy Isikov
Источник: //medium.com/
Редакция: Команда webformyself.