За един по-добър CSS, част 1

Jun 15, 2017 17:41 · 1419 words · 7 minute read

CSS - плътта и кръвта на един front-end. Жизнената сила на дизайна и духът на UX-а. Magenta-та на layout-а. Нещото, което на всички ни се налага да пишем. And yet, някои хора мразят часовете, през които го правят.

Защо, питам се аз?

Преди сякаш отговорът на този въпрос беше очевиден - времето, когато задължително имахме едновременно отворени Internet Explorer 6 и Firefox 1.6 един до друг, а Chrome дори не съществуваше. Когато градиенти се симулираха с картинки 2x300, а сенки - с 8 картинки, разтегнати в <table> елемент. Времето, в което IE6 не поддържаше дори прозрачни PNG-та без polyfill, който го правеше двойно по-бавен. Как изобщо е възможно да бъде по-бавен за мен все още е мистерия. Времето, в което беше почти задължително да има отделни стилове за Firefox и Opera + две версии на Internet Explorer. Помните ли <!--[if lte IE 6]>? Светът беше изпълнен с хакове и черни магии. В тези тъмни времена ненавистта към CSS беше оправдана и повсеместна.

Internet Explorer 6

Връщайки се в съвремието, писането на CSS прилича по-малко на игра на бинго и повече на “истинско” програмиране. Животът на сиесесописателите се е подобрил драматично. Вече можем да се възползваме от удобства като box-shadow, font-face (помните ли flash заглавията и Cufon?) и flex. Дори не се налага да режем картинки 5x5 от Photoshop заради заоблени ръбове. Като се замисля, не помня кога последно съм рязал части от дизайн с Photoshop.

И все пак, все още често се срещат дози екстракт от “Оф, сега трябва да пиша CSS”, “Няма какво да ти ревюирам CSS-а, нали работи” и “Тъкмо съм го накарал(а) да работи, не ме карай да го променям”. Писането на CSS не се състои от хвърляне на CSS правила към стената. Сякаш се отнасяме със CSS-а с някакво снисхождение и подценяване.

Писането на CSS като “истинското” програмиране ли е?

Може би няма алгоритми и изчисления, но ако се абстрахираме от това нещата не са толкова различни. Част от добрите практики от “истинското” програмиране директно се прилагат и върху CSS.

Какво искаме от един CSS код?

Ако трябва да отговоря на този въпрос (а трябва, защото току-що го зададох), бих обособил следните цели. Един CSS код трябва да бъде…

  • …правилен. На всички поддържани браузъри, резолюции и с всяко съдържание трябва да се вижда правилното нещо.
  • …съвместим с останалия CSS в приложението.
  • …гъвкав. CSS кодът трябва да бъде максимално податлив на промени.
  • …възможно най-прост и очевиден.
  • …възможно най-кратък.

Горните точки ги спазвам в низходящ ред на приоритет. Преминавам към следващото само ако всички по-горни са вече адресирани.

Очевидно, не си държа лист с тези точки на бюрото. Оптимизацията на горните я правя съзнателно, но не и алгоритмично. Аз лично съм си извадил някои изводи и практики, които ми помагат да го правя. Но! Това, че аз произвеждам каскадни стилови листа по този начин, не означавава, че това е единственият правилен подход. Както винаги, взимайте чужди мнения с песъчинка сол.

Дартс

Знам, че е очевидно, но списъкът няма да е изчерпателен, ако не го спомена. Ако човек не е напълно наясно, в детайли, как работят различните механизми в CSS, тогава единствената останала алтернатива е пробване на произволни комбинации от CSS правила, докато нещо не сработи. Всички имаме такива моменти, но важното е в края да сме разбрали как работи това нещо, което сме постигнали с налучкване.

Италия

Спагети Болонезе

Една от най-големите причини стиловете в един проект да се превърнат в автентична италианска паста болонезе, е излишният код. Това е и най-ниско висящият плод що се отнася до изчистването на CSS. Често, за да стигнем до определен код, преминаваме през няколко итерации. За бога, хора, изхвърлете ненужните CSS правила след като сте приключили със стилизирането. Не оставяйте висящи правила, които не правят нищо. Същото се отнася и за CSS класове в HTML-а, както и за излишно вложени HTML елементи. Разбира се, никой не оставя излишни неща нарочно. Често тези неща се пропускат несъзнателно, или мислейки си че ни трябват. Ако не сте абсолютно сигурни защо нещо ви е необходимо - проверете го. Това не е загубено време. Вместо да ни бави, това ни прави по-ефективни при следващия допир с подобен проблем.

Народна кухня

Каша

Най-големите каши със CSS, които съм виждал, са били причинени от (липсваща) организация на кода. Когато стиловете за някаква част от приложението са разхвърляни и оплетени със стиловете за друга част - тогава CSS-ът става също толкова управляем, колкото хеликоптер без перки… в космоса. Най-лошото нещо, което може да се случи с един CSS е да не сте сигурни къде се използва. Това пък води до страх от промени и размножаващи се буболечки.

Проблемът може да се реши с малко конвенции. Всеки компонент от приложението (било то Angular, React или нещо друго) трябва да има собствен CSS файл. Всички стилове в този файл трябва да се отнасят единствено за елементите от компонента. Нищо друго не трябва да може да се използва отвън. Това scope-ване на стилове може да стане по няколко начина:

  • Префиксване на класовете с името на компонента. Ако компонентът се казва article, тогава елементите вътре ще имат класове article-title, article-content и article-footer.
  • Лимитиране на селекторите спрямо root елемента на компонента. Този елемент ще има клас article, в който ще има title, content и footer. После в CSS-а ще са селектирани така: .article .title.

Аз съм привърженик на втория вариант, поради няколко причини:

  • Постоянното повторение на едни и същи неща води до по-трудно четене на кода.
  • Селектирането спрямо parent елемент става изключително удобно в SCSS:
.article {
  .title { /* ... */ }
  .content { /* ... */ }
  .footer { /* ... */ }
}

Като резултат - не се налага постоянно да се замислям дали не съм пропуснал да огранича някой стил.

Да, това си има недостатъци - например, този title клас може да се намира в друг компонент някъде по-надолу в DOM дървото. Забелязал съм, обаче, че това не е толкова чест проблем, колкото си представяме. Обикновено компонентите са малки и не съдържат други в себе си. Ако съдържат такива внимавам какви класове слагам, така че да не са прекалено общи. Ако нямам избор - понякога все пак префиксвам подобен клас с името на елемента.

Това е и причината част от React community-то да проповядва inline стилове в JS файловете, което аз смятам за изключително грозно. В тази връзка, в Angular 2+ стиловете за определен елемент се отнасят единствено за HTML-а в неговия темплейт. Това, според мен, е идеалното решение :)

Фън Шуй

“Пробвах пет подхода и все нещо не работи." В CSS има няколко механизма, които имат припокриващи се употреби. Например, за layout може да се използва (1) стандартната подредба с блокови елементи, (2) плаващи елементи (float), (3) подредба с inline-block, (4) Flexbox, (5) абсолютно/релативно позициониране и от скоро (6) grid. Друг пример - хоризонтално центриране може да стане с (1) text-align/inline-block, (2) Flexbox, (3) margin: 0 auto и (4) абсолютна позиция.

Изборът е хубаво нещо, но мешането на различни подходи в една и съща страница води до проблеми. Например - float-овете чупят блок подредбата, flexbox не играе добре с width/height = 100%, inline-block елементите се поддават на промени в baseline-а на текста (и се обръщат в RTL конфигурации) и т.н.

Логичното решение тук е да се използват колкото се може по-малко подходи за подреждане. Но, за да се получи това в един проект - трябва да се разберат програмистите в какъв приоритет да избират. Всеки един от тези подходи има случаи, в които работи добре и случаи, в които не е подходящ. Тогава кой да изберем за основен? За мен логично е това да е този, приложим в най-голяма част от случаите. Според опита ми, flexbox работи в най-голяма област от ситуации, понякога такива, за които няма друг подходящ избор.

Sidenote: Flexbox в никакъв случай не е фокусът на този пост, но тъй като темата е спорна, се чувствам задължен да отделя параграф с аргументация. Някои хора не го харесват и имат валидни причини за това. Най-голямата от тях е, че част от другите layout механизми не работят върху деца на flex контейнери. Лично аз не го виждам като голям проблем на практика. Защо? Както казах по-горе, ако ще използвам flexbox - го използвам за всичко, за което “става”. Това обикновено означава 95% от случаите за подредба на неща. В останалите 5 процента, когато не е подходящ - то е за елементи, които трябва да са по един или друг начин абсолютно позиционирани. Според мен, плюсовете доста силно накланят везната.

Тъй като, както винаги, пиша много - ще си позволя да прекъсна наратива внезапно и неочаквано като испанската инквизиция. Имам още неща за казване, така че очаквайте втора част :)

EDIT: Втора част