Як писати атомний CSS за допомогою Sass в Angular 2

32

Від автора: основне завдання статті – пройтися по всіх етапах написання атомного CSS і розібрати деякі складні моменти. Ми будемо використовувати sass і angular 2.

Що таке атомний CSS?

Насправді, мова йде не про atomic-css, а про спосіб написання CSS в атомному веб-дизайні. Попереднє просто легше записати.

Існує безліч стилів і шаблонів написання CSS в дизайні, у всіх свої переваги і недоліки. Не так давно мені показали концепцію Atomic CSS за авторством одного з кращих ведучих розробників, з яким мені довелась честь працювати разом, і я закохався в цю ідею. На жаль, його більше немає з нами. Він в іншому місці… Google.

Одне з головних переваг написання CSS в атомному стилі полягає в тому, що вам більше не доведеться писати CSS код. Звичайно, це трохи перебільшено, але ідея в тому, що ви дійдете до такої точки, коли нові стилі вам знадобляться для створення дуже специфічних і супер кастомізованих елементів.

Базова концепція полягає в тому, що на один клас є одна пара властивості і значення. Такий клас називається атом.

.height20 {
height: 20px;
}

Якщо потрібно змінити висоту, просто додаєте ще один клас.

.height30 {
height: 30px;
}

І бум, ось так. Можна піти ще далі і назвати класи h20 і h30.

Деяким не подобаються скорочення, і вони воліють семантику. Досить спірна тема, тут вирішувати тільки вам. Але як тільки зробили вибір, дотримуйтеся його! Головне сталість.

Здається, що це занадто утомливо. Не хочу я сидіти і прописувати всі можливі варіанти висоти, які я буду використовувати. Це десятки, сотні рядків коду. Я став розробником, тому що ледачий. Давайте подивимося, що з цим можна зробити.

SASS/SCSS

Генерацію таких класів можна автоматизувати через Sass.

// heights.scss
// Список наших пар ключ/значення
$heights: (
6: 0.375 rem,
10: 0.625 rem,
11: 0.688 rem,
18: 1.125 rem
);
// Проходимся циклом і ключ йде в ім’я
// а значення сягає значення властивості.
@each $name, $val in $heights {
.h#{$name} {
height: #{$val};
}
.min-h#{$name} {
min-height: #{$val};
}
}
// heights.compiled.css
.h6 {
height: 0.375 rem;
}
.h10 {
height: 0.625 rem;
}
.h11 {
height: 0.688 rem;
}
.h18 {
height: 1.125 rem;
}
.min-h6 {
min-height: 0.375 rem;
}
.min-h10 {
min-height: 0.625 rem;
}
.min-h11 {
min-height: 0.688 rem;
}
.min-h18 {
min-height: 1.125 rem;
}

Величезна перевага атомної CSS в тому, що він зрушує обслуговування коду від просто стилів шаблону. Якщо потрібно поправити відступи на сторінці, то вам потрібно відредагувати HTML CSS.

В кінці кінців, ви створите стільки атомів, що вам більше не потрібно буде писати CSS код.

Молекули

Використовувана група атомів називається молекулою. Молекула – це не новий код, це просто шаблон повторюваних класів. Молекула картки може складатися з таких класів:

Що переводиться в:

{
width: 250px;
height: 100px;
font-size: 16px;
padding: 5px;
}

На перший погляд занадто багато літер, здається, що буде важко звикнути. Однак так у вас не буде проблеми, коли вам доведеться створити окремий клас для «.card» тільки з-за того, що вам потрібен «.card», який дещо відрізняється від інших.

Angular 2

Якщо ви взагалі не знайомі з Angular 2, зараз я вам швидко розповім про CSS.

У angular 2 є такі речі, звані компоненти. Додаток починається з одного головного/root компонента, а всі інші компоненти є його нащадками.

Как писать атомный CSS с помощью Sass в Angular 2

У компонентів можуть бути свої стилі, які працюють тільки на них. Якщо у FiltersCmp є клас .hide, то TodosCmp не буде знати про нього. Ви можете запитати, як писати глобальні стилі, якщо весь CSS код розмежований з компонентів? Ми хочемо писати глобальні стилі, щоб вони не обмежувалися на окремих компонентах.

Зробити атомні стилі глобальними можна двома способами. Найпростіший – віддати всю роботу angular. Спершу необхідно підключити scss в AppCmp. Потім встановлюємо властивість encapsulation декоратора @Component() значення ViewEcapsulation.None. Так ми скажемо angular 2, щоб цей компонент не був жадібним і поділився стилями з нащадками, суміжними компонентами і батьками, що зробить стилі глобальними.

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. Завантажувач може безпосередньо не знати про них.

module.exports = {
module: {
rules: [
{ test: /app\.main\.scss/, loader: ‘sass-loader’ }
]
}
}

Тепер наш scss перетворився в CSS, але на цьому етапі webpack ще не знає, що робити з цим css кодом. Нам доведеться додати css-loader. Цей завантажувач також змінює всі url-адреси на адресу з вашої папки ./dist, якщо у вас є відповідний завантажувач для цих файлів. Або ж можна використовувати file-loader.

module.exports = {
module: {
rules: [
{
test: /app\.main\.scss/,
loaders: [
{
loader: ‘css-loader’,
options: {
importLoaders: 1
}
},
‘sass-loader’
]
}
]
}
}

Тепер давайте додамо postcss, нам потрібно додати специфічні префікси браузерів в стилі.

Помістіть файл в корінь проекту. Все, що він робить, це говорить postcss, що ми хочемо використовувати autoprefixer і підтримувати останні 6 версій браузерів. Префікси -moz-, -webkit — і -ms — будуть автоматично додаватися в потрібних місцях.

// postcss.config.js
const autoprefixer = require(‘autoprefixer’);
module.exports = {
plugins: [
autoprefixer({
browsers: [‘last 6 versions’]
})
]
}

З поточними налаштуваннями webpack обробить всі наші scss файли і поверне рядок css. Сама рядок марна, якщо вона не загорнута в файл. Нам залишилося отримати скомпільований css в нашу папку ./dist в окремий файл.

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, але це тема для окремого посту.