Від автора: існує маса способів іменування CSS. Ви, напевно, чули про BEM і SMACSS (останній більше ніж просто спосіб). Також є OOCSS, більше схожий на цілу методику. Всі вони в значній мірі залежать від селекторів класів CSS із-за їх великої універсальності.
Sass допомагає писати селектори класів в модульній формі. За допомогою спадкування селекторів і mixin’ов ми можемо вигадувати божевільні API. У цій статті я продемонструю (ще раз) пару цих способів і перерахую їх плюси і мінуси, з моєї точки зору.
Нативне спадкування селекторів
Можливість успадковувати селектори, не повторюючи оригінальні імена блоків, давно напрошувалася в Sass. І у версії 3.3 ця функція, нарешті, була представлена. У бета-версії синтаксис був дуже дивним, пізніше з випуском стабільної версії він був поліпшений. У своїй статті Natalie Weizenbaum пояснила причини зміни синтаксису.
В основному селектор-посилання (&) може використовуватися як частина імені підкласу для створення іншого класу від першого батька на кореневому рівні документа (тобто @at-root не потрібен).
.foo {
// Стилі `.foo`
&-bar {
// Стилі `.foo-bar`
}
}
Незабаром цією функцією будуть зловживати при написанні BEM селекторів, як у вкрай популярний медіа-об’єкті:
.media {
// Стилі для блоку `.media`
&__img {
// Стилі для елемента `.media__image`
&–full {
// Стилі для модифікованого елемента`.media__image–full`
}
}
&–new {
// Стилі модифікатора`.media–new`
}
}
Код вище буде складати:
.media {}
.media__img {}
.media__img–full {}
.media–new {}
Плюси
Використовуються нативні функції. Не потрібно жодних додаткових помічників, таких як змінні або mixin’и.
В цілому досить легко розібратися в роботі селекторів-посилань (&).
Мінуси
Синтаксис (&) здається трохи заплутаним, якщо не страшним для розробників, не знайомих з Sass.
Якщо не використаний @at-root, то спадкування зазвичай не распрастраняется на кореневий рівень, що може збентежити.
BEM mixins
З-за вкрай незручного синтаксису генерації класів в бета-версії Sass 3.3 (at-root #{&}__element) для створення більш дружніх API то тут, то там почали з’являтися mixin’и, як заміна потворного синтаксису.
@mixin element($element) {
&__#{$element} {
@content;
}
}
@mixin modifier($modifier) {
&–#{$modifier} {
@content;
}
}
Ви використовуєте їх так:
.media {
// Стилі `.media` block
@include element(“image”) {
// Стилі для елемента `.media__image` element
@include modifier(“full”) {
// Стилі для модифікованого елемента `.media__image–full`
}
}
@include modifier(“new”) {
// Стилі модифікатора `.media–new`
}
}
За таким же принципом ми могли б створити блок mixin, але від нього не буде користі, якщо блок не відповідає одному імені класу. Давайте спростимо. Так як декому хочеться набирати імена модифікаторів і елементів, ми згадали пару скорочень e та m.
.media {
// Стилі для блоку`.media`
@include e(“image”) {
// Стилі для елемента `.media__image`
@include m(“full”) {
// Стилі для модифікованого елемента `.media__image–full`
}
}
@include m(“new”) {
// Стилі модифікатора `.media–new`
}
}
Плюси
Якщо ви знаєте, як працює BEM, то вам не складе труднощів розібратися в API цієї версії.
Мінуси
Вся логіка прихована під mixin’ами, і якщо ви не зовсім розумієте, як це працює, то зовсім не факт, що нові класи і селектори будуть сгенерированны.
Mixin’и в одну букву швидше за все не самий вдалий варіант, іноді складно зрозуміти призначення mixin’а. B і m можуть означати все, що завгодно.
Очеловеченные-BEM mixin’и
Нещодавно я прочитав про новий BEM-подібному методі у статті Anders Schmidt Hansen. Основна ідея статті полягає в тому, щоб заховати жаргон «Блок-Елемент-Модифікатор» за загальними поняттями, які і так зрозумілі.
@mixin new($block) {
@at-корінь .#{$block} {
@content;
}
}
@mixin has($element) {
&__#{$element} {
@content;
}
}
@mixin when($modifier) {
&–#{$modifier} {
@content;
}
}
У цьому випадку вся суть у тому, щоб заховати код за продуманим mixin’ами таким чином, щоб це виглядало як код нового mixin’а.
@include new(“media”) {
// Стилі для блоку `.media`
@include has(“image”) {
// Стилі для елемента `.media__image`
@include when(“full”) {
// Стилі для модифікованого елемента `.media__image–full`
}
}
@include when(“new”) {
// Стилі модифікатора `.media–new`
}
}
Anders пішов ще далі з is(..) і holds(..) mixin’ами. Вся ця ідея частково нагадує мені мій when-inside(..) mixin, що приховує & за доброзичливим mixin’ом під час стилізації елемента, заснованого на даному контексті.
@mixin when-inside($selector) {
#{$selector} & {
@content;
}
}
img {
display: block;
@include when-inside(“.media-inline”) {
display: inline;
}
}
Плюси
Даний метод робить код більш читабельним. Наприклад, коли ми почали називати наші класи станів з приставкою is- (стало популярним в SMACSS).
До цих пір цей підхід дотримується певної методології (у нашому випадку BEM). Однак, код стає набагато дружелюбніше.
Мінуси
Більше mixin’ів, більше помічників, необхідно ще більше все вивчити, щоб у всьому розібратися. Ніхто не любить писати тонни mixin’ів заради простих CSS селекторів.
Для деяких це може бути занадто абстрактно; не всім подобається читати код по-англійськи. Залежить від знання мови.
Прикінцеві міркування
Пам’ятайте, що дані методи убезпечать вас від пошуку вихідного селектора. І вже тим більше, якщо він зовсім не існує, а генерується Sass. Коментарі перед селекторами вирішують цю проблему, але чому б просто не писати селектори безпосередньо в одному місці?
У будь-якому випадку, це найпопулярніші способи написання CSS селекторів з допомогою Sass, які я знаю. І між нами: жоден мені не подобається. І не тільки із-за проблеми з пошуком, для мене це не така вже й проблема.
Я бачу проблему, яку вони намагаються вирішити, але іноді простота краще зручності. Повторювати кореневої селектор не так і складно, а також робить код більш зручним для читання, т. к. в такому варіанті менше наслідувань і сам код ближче до стандартного CSS.