image

Странное и в то же время удивительное время для 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 классов, которые мы будем использовать, мы сможем сделать кое-что по-настоящему необычное:
  1. Можно уменьшить CSS библиотеку под конкретный проект и оставить только широко используемый фреймворк с набором настроек (где заданы единицы измерения расстояний (padding/margin/width/height), шрифты, цвета и т.д.), который выкидывает все вспомогательные классы, которые нам могли бы пригодиться
  2. Можно реализовать функцию внутри библиотеки fxCSS, которая в качестве входных данных принимала бы HTML шаблоны, составляла бы полный список используемых в шаблонах классов и удаляла бы неиспользуемые. Это кардинально бы уменьшило размер CSS файла (в файле не было бы медиа запросов, так как функционал по применению стилей в зависимости от устройства лежит на JS библиотеке. Эту функцию можно включить или отключить.)
  3. Можно написать тест, который будет проверять наличие у заданного элемента нужного класса. Также с помощью теста можно проверять, добавлены ли или удалены классы к нужному устройству. Концепцию тестов можно развить еще сильнее – так как наши классы независимы и подчиняются заданной схеме именования, можно реализовать проверки типа: если дочернему элементу присвоен класс «fl-l» (float: left), можно проверить, чтобы у родительского элемента был класс «cf» (clearfix)
  4. Можно создать репозиторий HTML-фрагментов компонентов интерфейса – так как ядро CSS библиотеки, ее именования и генерируемые классы стали (теоретически) широко используемыми стандартами, для создания компонентов нам понадобится только HTML: при необходимости код на 100% декларативный и легкоизменяемый. 20 дизайнеров интерфейсов могут создать 20 разных вариантов компонента меню, а так как все они используют одни и те же базовые CSS классы, для просмотра каждого варианта необходимо просто скопировать и вставить правильный HTML код


Не стоит забывать про:

  • Производительность: Учитывая, что новые атрибуты фактически будут применяться ко всем элементам на странице, может наблюдаться значительное падение производительности. Существует потенциальный компромисс – к примеру, во время принудительных трансформаций с помощью библиотеки fxCSS можно проверять видимую область веб-страницы на устройстве и применять стили только к этой части, и только потом при прокрутке пользователем страницы вверх или вниз применять стили к остальным частям
  • Псевдоэлементы все еще не работают – проблему можно решить с помощью дополнительного пользовательского атрибута
  • Есть ли еще какие-либо уступки, на которые нам придется пойти ради старых браузеров? Можем ли мы столкнуться с проблемами с CSS в Internet Explorer?
  • Можно попасть в оценку 80/20 для конфигурации CSS по умолчанию, что позволит разместить его на CDN и сделает написание/правку CSS более эффективной?


Прежде всего, становится ясно, что сам способ мышления о CSS резко меняется. Front-end разработчики понимают, что переписывать одни и те же 50 свойств до посинения не продуктивно. Кроме того, переход к компонентной архитектуре заставляет нас переосмыслить процесс создания стилей для браузера. HTML и CSS – отличная пара. Так почему бы их не связать вместе?

Давайте создавать новые проекты, внедрять новые решения, бросать вызов старым парадигмам мышления, которые мы использовали для создания наших проектов.

Коллеги, уважаемые посетители Хабра! В это последним абзаце моего перевода хотел спросить кое-что у Вас. Мы со своей командой WebForMySelf практические ежедневно публикуем туториалы так или иначе связанные с созданием сайта.

Так вот, хотел узнать, будет ли Вам интересно, если мы самое свежее и, на наш взгляд, интересное из англоязычного интернета будем публиковать на хабре. Если Вы «За», то дайте знать в комментариях.

Приятного Вам дня!

Комментарии (10)


  1. NeoCode
    25.04.2016 21:11
    +3

    Да, это очень интересно.
    Но скажите, неужели все действительно так сложно? Я не веб-разработчик, но некоторое представление имею (и сейчас как-то активно заинтересовался темой веба). И мне кажется что что-то здесь не так, что можно все это делать сильно проще.
    Взять большой общеизвестный сайт — тот же Хабр, или ВКонтакте. Ну сколько там разных типов страниц? Максимум десяток-полтора, включая различные настройки. Многие элементы (например меню) совершенно одинаковы на всех страницах. Общее оформление (шрифты, цвета) в принципе должно быть одинаковым на всех страницах. Ну и что там такого сложного, что не решал бы css 10-летней давности?


    1. Throwable
      26.04.2016 11:25

      Мне кажется CSS ждет медленная смерть от перенасыщения. Технология движется по принципу постоянного добавления и усложнения, чтобы охватить как можно больше кейсов. С выпуском каждого нового модуля возникают проблемы с поддержкой. Многие функции продублированы, многие уже deprecated. На мой взгляд у CSS как стандарта должно быть минималистичное функциональное core и четкая модель рендеринга, а все удобства — во дворе — должны предоставляться различными фреймворками и динамическими генераторами. Включать в сам стандарт функционал для различных способов организации вебстраниц я считаю ошибкой. В любом случае сейчас пойдет мода на вебкомпоненты и CSS сам по себе отойдет на второй план.


    1. derSmoll
      26.04.2016 23:29

      Ну сколько там разных типов страниц? Максимум десяток-полтора, включая различные настройки. Многие элементы (например меню) совершенно одинаковы на всех страницах. Общее оформление (шрифты, цвета) в принципе должно быть одинаковым на всех страницах.

      Ох, если бы все было так просто… :)


      1. NeoCode
        28.04.2016 21:04

        А что не просто? Мне действительно интересно, расскажите.


        1. derSmoll
          28.04.2016 22:47

          В первую очередь зависит от степени участия верстальщика/фронтенд разработчика на проекте. Если это просто «взял макеты -> сверстал 20 статических страниц -> отдал бекенд разработчику -> забыл», тогда да, ничего такого.
          Если же он сопровождает проект в течении всей разработки, то все куда сложнее. Динамический контент, не предусмотренный мокапами, вносит свою изюминку. Структура бекенда тожет может внести свою. Один и тот же блок может совсем по разному выглядеть на разных типах страниц, иметь 3-4 состояния и радикально видоизменяться при уменьшении до размеров мобильного экрана. Это все нужно продумывать, и не всегда это бывает просто.
          Про десяток-полтора типов страниц вы тоже слегка заблуждаетесь, потому что на крупных сайтах вы далеко не все с ходу можете увидеть. На примере того же хабра — кроме страниц, который видят все юзеры, есть не публичные. Например, с десяток относительно уникальных страниц в админке компании .
          Подозреваю, что не меньше страниц есть в админке админов хабра :) и других типов юзеров


  1. Zigzag
    25.04.2016 23:25
    +4

    Вы это все серьёзно? о_0


  1. kimrgrey
    26.04.2016 00:12
    +2

    Работаю сейчас на проекте, где подобный подход активно зачем-то применяется. Я не в восторге.

    Во-первых, дико раздражает постоянно переводить общечеловеческий CSS в набор классов, принятых на проекте. То есть ты постоянно делаешь примерно так. Окей, мне надо запилить контейнер relative, а потом разместить иконку с абсолютным позиционированием в правом верхнем углу контейнера, ага, понятно… а теперь пойдем смотреть, как называются эти самые «высокодекларативные» классы.

    Во-вторых, пугает такое направление движения для общего случая. Сейчас, чтобы нормально работать, мне нужно знать HTML + CSS, которые, как бы, общие для всех стандарты. А тут, по сути, надстраивается свой язык для разметки, специфичный для проекта.

    В-третьих, в разметке меня мало занимает, как компонент выглядит или анимирован, мне важно, что он делает. Поэтому внешний вид — отдельно, разметка — отдельно.


  1. NeXTs_od
    26.04.2016 01:47

    Уж извините, но удобным это не выглядит.
    Ладно небольшое кол-во вспомогательных классов по типу mb20 (margin-bottom: 20px), pt20 (padding-top: 20px), но создавать классы для каждого стиля это перебор.

    Удобнее был бы инструмент, выносящий повторяющиеся стили в отдельный класс на этапе сборки билда в целях оптимизации места, самостоятельно, без человеческого вмешательства. Уверен нечто подобное уже должно быть.


  1. melnik909
    26.04.2016 10:29

    Добавлю свои 5 копеек к комментарию kimrgrey.

    При таком подходе мы полностью теряем семантику. В приведенных примерах не понятно, какие это компоненты и для чего они. Последствия такой методологии можно посмотреть на сайте yahoo.


  1. tdmarko
    26.04.2016 11:23

    По мне так media queries гораздо удобнее, и нету необходимости применять JS.