Странное и в то же время удивительное время для CSS.
Вот уже несколько лет мы наблюдаем рост популярности парадигм, концепций, архитектур, библиотек и фреймворков, отвечающих за модульность, масштабируемость и удобство при написании CSS. С самого зарождения интернета сообщество разработчиков сталкивалось с различными проблемами во front-end разработке, следствием решения которых стало появление данных технологий. Среди возникших проблем были отсутствие программных конструкций (переменных, управляющих структур, областей видимости и т.д.), снижение когнитивной нагрузки (и упрощение организации циклов), вызванной каскадированием и проблемами со специфичностью, налаживание нормальной работоспособности и удобство правил именования. Но самая главная проблема заключалась в том, как структурировать код CSS и вобрать в него самые лучшие практики, которые появились в других языках веб-программирования за последние несколько десятилетий.
Судя по списку ниже, данные задачи были решены с разной степенью успешности:
- Препроцессоры и абстракции типа Sass, Less и PostCSS добавляют в стили программные конструкции. С их помощью мы можем представлять CSS, как настоящий turing-complete язык программирования.
- Шаблоны типа Atomic/Functional/Utility делают селекторы более простыми и откатывают нас назад к презентационной схеме именования.
- Архитектуры типа ITCSS помогают организовывать наш код и файлы в упорядоченные понятным и предсказуемым образом логические части, что позволяет легко находить нужный участок кода, а также помогает выбрать подходящее место для нового кода.
- Фреймворки типа True и Sassaby проводят модульные тесты абстрактного CSS кода.
OOCSS, BEM, SMACSS и т.д. — все эти технологии сейчас находятся на пике популярности. Эти CSS шаблоны и архитектуры также называют «взрослыми».
Каждая из этих технологий по-своему прекрасна, однако, учитывая определенную направленность каждого решения, сразу становится понятно, что универсальная CSS архитектура будет похожа на Франкенштейна, сшитого из этих технологий. Данные решения могут отлично работать все вместе, а могут содержать повторяющиеся объявления и опции, что еще дальше оттолкнет нас от чистого, удобного и масштабируемого кода.
Одним из самых облегчающих жизнь событий в современной front-end разработке стал переход к компонентной архитектуре – т.е. код, в котором разметка, представление и логика структурно и/или функционально объединены. Компонентную архитектуру мы видели в крайне популярном фреймворке React и в набирающих известность веб-компонентах (а также в фреймворках на основе веб-компонентов типа Polymer). Другие основные игроки среди JS фреймворков, такие как Ember и Angular уловили важность данного перехода и также включили различные вариации данной концепции в библиотеки.
В сфере front-end разработки данный переход был решающим, и мы только начинаем наблюдать за тем, куда будет развиваться данная парадигма.
Крайне важно понять огромные преимущества от перехода на компонентную архитектуру. Мало того, что по своей природе компоненты поддаются концепции повторного использования кода, они еще отлично подходят нам, как разработчикам, для более важных вещей: данные компоненты снижают когнитивную нагрузку, упрощают организацию циклов и уменьшают необходимость постоянных скачков от одной задачи к другой. Например, отслеживание и поиск зависимостей в нескольких файлах JS, HTML и CSS, интеграция разметки, представления, логика и отладка.
Нельзя преуменьшать важность данных преимуществ. Если вы, вдруг, начали сомневаться в важности вышеупомянутой архитектуры и ее преимуществ, вспомните ваш кривой проект на Angular 1.x. Вспомните, как вы пробирались через лабиринт HTML атрибутов, контроллеров и директив, названий файлов (часто эти имена совсем не передавали смысла контроллеров и директив), зависимостей модулей… На секунду закройте глаза и представьте, как может выглядеть граф зависимостей такого приложения. Я бы предположил, что «Самый большой в мире моток шпагата» довольно подходящее название для такого графа.
С развитием компонентной архитектуры, особенно в JS, и диким ростом популярности компонентных фреймворков мы начинаем замечать, как похожие концепции просачиваются в мир CSS. Сообщество веб-разработчиков моментально хватается за решения, способные упростить структуризацию кода, его написание и отслеживание. Помимо всего прочего, мы начали развеивать некоторые предубеждения в CSS, которые существовали несколько десятилетий – а именно, извечное убеждение, что HTML никогда не должен содержать данные о представлении.
Прогрессивные фреймворки и библиотеки «оседлали волну», используя вышеупомянутые шаблоны: Atomic/Functional/Utility стали популярны за последний год или два. Примером могут послужить фреймворки Tachyons, BassCSS, а также мой фреймворк Nuclide.
Информацию о фреймворках можно, конечно, найти и на сайтах проектов, но если кратко, то мы будем использовать несколько CSS классов с одним свойством с минимальной специфичностью в качестве простых и узкоспециализированных строительных блоков, из которых будут строиться компоненты интерфейса. Пример использования классов фреймворка Tachyons может выглядеть так:
<section class="mw5 mw7-ns center bg-light-gray pa3 ph5-ns">
<!-- контент -->
</section>
Теперь, когда вы привыкли к такому большому количеству классов в HTML, давайте рассмотрим плюсы этого конкретного подхода:
- Высокая декларативность HTML кода позволяет нам представить, как выглядит элемент без необходимости заглядывать в стили
- С плоским списком классов можно забыть о проблемах со специфичностью и переопределением стилей
- Устранение контекстных CSS селекторов позволяет правильно спланировать и выстроить нашу архитектуру таким образом, чтобы она следовала лучшим современным практикам: модульность, повторное использование и производительность
- Если использовать данный подход на большинстве элементов веб-страницы, можно существенно сократить объем стилей для всего сайта – останутся только наши модульные классы от фреймворка Atomic, которые можно повторно использовать (плюс одноразовые классы, которые часто пишутся для конкретных проектов)
Неплохие такие преимущества, правда?!
Но не все так гладко. Теперь взглянем на минусы:
- Адаптивный дизайн не так хорошо работает с данной моделью. Фреймворк Tachyons использует классы из дополнительного пространства имен для индикации классов медиа запросов – а это означает, что нам нужно продублировать ВСЕ классы фреймворка Atomic для каждого разрешения экрана. Кроме того, возникает когнитивная перегрузка из-за того, что в нашей базе классы техники mobile-first перемешиваются с классами медиа запросов; представьте себе, что вам нужно написать код конкретного компонента для трех или более разрешений экрана с большим количеством изменений в стилях
- Данная модель не охватывает псевдоклассы. Как же тогда реализовывать состояния hover или active?
- Данная модель не охватывает псевдоэлементы. Как тогда стилизовать элементы :before или :after?
В принципе, мы почти закончили. Но можно и лучше.
Давайте доведем эту концепцию до логического конца.
Мы спроектируем фреймворк под CSS код, который будет работать по концепциям, успешно проверенным в JS. Ключевое значение здесь имеет компонентная структура. Крайне важно то, что мы понимаем, что все это чисто концептуально и новой структуре безразлично то, как мы раньше просматривали HTML и CSS код.
Наш фреймворк должен соответствовать следующим критериям:
- В фреймворке должен быть полностью компонентный HTML/CSS код, создающий концептуально-связанные контент и представление
- Фреймворк должен производить высоко декларативный HTML код, чтобы мы легко могли представить, как выглядит компонент без необходимости открывать файлы CSS
- В фреймворке должны быть медиа запросы, чтобы мы могли создавать элементы адаптивного дизайна, предпочтительно без необходимости копирования CSS классов для каждого разрешения экрана
- Должна быть возможность применения стилей к псевдоклассам
И почти сразу же мы столкнемся с ограничениями в HTML. Пару пунктов из этого списка нельзя выполнить без подключения JS. Значит, нам придется это сделать.
Нам понадобится: JS библиотека, способная добавить к стандартным HTML атрибутам новый набор атрибутов, которые для достижения поставленных нами задач будут работать в паре с CSS классами Atomic. В основе библиотеки должна лежать адаптивная техника mobile-first. Библиотека будет применять стандартные возможности HTML на устаревших браузерах.
Пример HTML кода:
<button
class="d-ib p-sm bgc-cool c-warm"
fxcss-device-tablet-remove="p-sm"
fxcss-device-tablet-add="p-md"
fxcss-device-desktop="d-b p-lg bgc-cloudy c-sunshine"
fxcss-pseudo-class-hover="td-u">
кликни меня
</button>
Объясним, что тут происходит: по умолчанию атрибут class будет использоваться для стилей техники mobile-first. Затем по событию полной загрузки страницы и/или изменению ее размера наша библиотека (fxCSS или «futureCSS») подтянет пользовательские атрибуты и применит соответствующие изменения к определенному устройству. В этом примере библиотека fxCSS с помощью атрибутов -remove и –add заменяет класс «p-sm» на «p-md». Поднимаясь до разрешений настольных компьютеров, мы заменяем все классы списком классов для настольного компьютера (для данного функционала отсутствуют директивы -remove/-add). И последнее, у нас есть отдельный атрибут для стилей псевдоклассов наподобие hover.
Для работы всего функционала нам потребуется подключить JS, а значит, сейчас произойдет что-то очень серьезное: если сделать HTML код на 100% декларативным и определить все 100% CSS классов, которые мы будем использовать, мы сможем сделать кое-что по-настоящему необычное:
- Можно уменьшить CSS библиотеку под конкретный проект и оставить только широко используемый фреймворк с набором настроек (где заданы единицы измерения расстояний (padding/margin/width/height), шрифты, цвета и т.д.), который выкидывает все вспомогательные классы, которые нам могли бы пригодиться
- Можно реализовать функцию внутри библиотеки fxCSS, которая в качестве входных данных принимала бы HTML шаблоны, составляла бы полный список используемых в шаблонах классов и удаляла бы неиспользуемые. Это кардинально бы уменьшило размер CSS файла (в файле не было бы медиа запросов, так как функционал по применению стилей в зависимости от устройства лежит на JS библиотеке. Эту функцию можно включить или отключить.)
- Можно написать тест, который будет проверять наличие у заданного элемента нужного класса. Также с помощью теста можно проверять, добавлены ли или удалены классы к нужному устройству. Концепцию тестов можно развить еще сильнее – так как наши классы независимы и подчиняются заданной схеме именования, можно реализовать проверки типа: если дочернему элементу присвоен класс «fl-l» (float: left), можно проверить, чтобы у родительского элемента был класс «cf» (clearfix)
- Можно создать репозиторий HTML-фрагментов компонентов интерфейса – так как ядро CSS библиотеки, ее именования и генерируемые классы стали (теоретически) широко используемыми стандартами, для создания компонентов нам понадобится только HTML: при необходимости код на 100% декларативный и легкоизменяемый. 20 дизайнеров интерфейсов могут создать 20 разных вариантов компонента меню, а так как все они используют одни и те же базовые CSS классы, для просмотра каждого варианта необходимо просто скопировать и вставить правильный HTML код
Не стоит забывать про:
- Производительность: Учитывая, что новые атрибуты фактически будут применяться ко всем элементам на странице, может наблюдаться значительное падение производительности. Существует потенциальный компромисс – к примеру, во время принудительных трансформаций с помощью библиотеки fxCSS можно проверять видимую область веб-страницы на устройстве и применять стили только к этой части, и только потом при прокрутке пользователем страницы вверх или вниз применять стили к остальным частям
- Псевдоэлементы все еще не работают – проблему можно решить с помощью дополнительного пользовательского атрибута
- Есть ли еще какие-либо уступки, на которые нам придется пойти ради старых браузеров? Можем ли мы столкнуться с проблемами с CSS в Internet Explorer?
- Можно попасть в оценку 80/20 для конфигурации CSS по умолчанию, что позволит разместить его на CDN и сделает написание/правку CSS более эффективной?
Прежде всего, становится ясно, что сам способ
Давайте создавать новые проекты, внедрять новые решения, бросать вызов старым парадигмам
Коллеги, уважаемые посетители ! В это последним абзаце моего перевода хотел спросить кое-что у Вас. Мы со своей командой WebForMySelf практические ежедневно публикуем туториалы так или иначе связанные с созданием сайта.
Так вот, хотел узнать, будет ли Вам интересно, если мы самое свежее и, на наш взгляд, интересное из англоязычного интернета будем публиковать на хабре. Если Вы «За», то дайте знать в комментариях.
Приятного Вам дня!
Автор: andreyBern