Это перевод статьи Миллера Медейроса — «The problem with CSS pre-processors».

Эта статья очень спорная, я много думал до того, как опубликовать её. Пожалуйста, постарайтесь быть открытыми и прочитать статью до конца, прежде чем что-либо комментировать. Она не должна стать причиной войны. Прочитайте, пожалуйста, статью о моём блоге, чтобы понять его суть и моё мнение обо всём этом.

Я обдумывал использовать CSS-препроцессоры такие как Sass, LESS, Stylus и другие, достаточно долго. Каждый раз, когда меня спрашивали, использую ли я какие-то из этих инструментов, я отвечал, что я привык к моему текущему рабочему процессу и не вижу причины его менять, поскольку проблемы, которые решают эти инструменты, — не те проблемы, что есть у меня в CSS. Но вчера я прочитал две статьи, которые заставили меня пересмотреть свой взгляд, и я решил потратить немного времени изучая альтернативы и перенести часть кода, чтобы посмотреть, помогут ли препроцессоры сохранить мой код более организованным/удобным в обслуживании и/или сможет ли это сделать процесс разработки проще (с учётом того, развивались ли эти инструменты в последние несколько лет).

Для опытного разработчика изучение большинства возможностей препроцессоров занимает пару часов (после того, как вы изучили первую пару, следующие идут легче). Но если у вас нет навыков программирования кроме как CSS/HTML и/или вы не знаете основной логики программирования (циклы, функции, области видимости), это, возможно, займёт больше времени. Командная строка — это ещё одно препятствие для CSS/HTML разработчиков. Но не в этом цель статьи, я буду конкретно говорить о злоупотреблении этими возможностями. Я попробую объяснить большую часть основных проблем, которые я вижу, когда каждый раз кто-то показывает мне пример кода, или я вижу проект, написанный с использованием любого из этих препроцессоров.

Примеси

Что такое примеси?

Примеси — это общее название, используемое для описания того, что один объект должен скопировать все свойства другого объекта. В итоге примеси это не более чем продвинутый способ скопировать и вставить. «Все» известные препроцессоры имеют некое подобие примесей.

Глупое дублирование кода является глупым

Следуя синтаксису SCSS (Sass), примеси могут быть описаны и использованы следующим образом:

Что компилируется в:

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

Эта проблема не является специфичной для Sass, она также существует в LESS, и в Stylus, и в любом другом препроцессоре, который поддерживает эту возможность. Используя новый слой абстракции, разработчик не осознаёт, что он создаёт сильно дублирующийся код. Всегда сжимайте файлы CSS и JavaScript. Gzip очень хорошо сжимает дублирующиеся данные, так что эта проблема может быть несущественной на продакшене. Только учтите, что сгенерированный CSS-код будет тяжелее поддерживать в случае, если ваши будущие разработчики по каким-то причинам решат прекратить использование препроцессора и просто обновят сгенерированный CSS (может, у них не будет доступа к исходным файлам или не будет опыта работы с препроцессорами).

Расширение

LESS и Stylus не поддерживают ничего похожего на расширение, поэтому я выбрал SCSS (Sass) для написания примеров. Расширение — это что-то наподобие «более умной» примеси: вместо копирования и вставки свойств оно единожды установит множественный селектор для этих свойств.

Что компилируется в:

Намного ближе к тому, что обычный человек сделает вручную. Используйте примеси, если вам необходимо передать дополнительные параметры. Если вы заметили у себя использование одинаковых примесей, передающих одинаковые значения, несколько раз, вам следует создать базовый «тип», который будет наследоваться другими селекторами.

Расширения недостаточно

Обратите внимание, что расширение позволяет избежать дублирования кода, но может стать причиной возникновения другой проблемы. Если вы используете @extend одного базового класса много раз, вы можете получить CSS-правило содержащее тысячи селекторов, что плохо скажется на производительности и могло даже привести к падению браузера.

Другая проблема в том, что каждый класс, созданный для использования через @extend, будет включён в компилируемый файл (даже если он не используется). В некоторых случаях это может привести к проблеме (коллизия имён, размер файла) и сделает этот процесс нежизнеспособным при создания фреймворка наподобие Compass.

Я действительно желаю, чтобы Sass улучшил способ работы @extend (а также другие препроцессоры унаследовали бы аналогичную возможность), чтобы мы могли создавать много базовых классов для повторного использования в коде и не экспортировали бы их без необходимости. Что-нибудь наподобие:

Что компилируется в:

Я знаю, что такого рода возможность была уже предложена ранее.

Другой проблемой будет совмещение вложенных селекторов и @extend. Это может привести к нежелательным побочным эффектам.

Расширение и примеси могут быть неудобны в обслуживании

Вопреки общим знаниям, расширение других классов или создание примесей могут ухудшить обслуживание. Из-за того, что место, где вы использовали свойства, находится далеко от места, где они были определены, есть больше шансов, что вы измените свойства, не замечая, что затрагиваете множество объектов сразу, или не осознавая, к каким элементам эти изменения применятся. Это называется «тесная связь»:

Тесно связанным системам, как правило, присущи следующие особенности развития, которые чаще рассматриваются как недостатки:
  • Изменение в одном модуле обычно создаёт волновой эффект в изменениях в других модулях.
  • Группа модулей может потребовать больше усилий и/или времени в связи с увеличением межмодульной зависимости.
  • Конкретный модуль может быть труднее использовать и/или тестировать из-за необходимости включать зависимые модули.

Я предпочитаю группировать мои селекторы по соседству. При таком подходе я уверен, что когда кто-либо меняет селектор/свойство, они точно знают, что именно будет затронуто этими изменениями, даже если это повлечёт за собой дублирование кода.

Максимально избегая редактирования базовых классов, следуйте «принципу открытости/закрытости» насколько это возможно (дополняйте базовые классы, не редактируйте их).

Вложенность

Другая особенность, которую многие люди считают полезной — это вложенные селекторы. Вместо повторения селекторов много раз вы можете просто вложить правила, которые должны применяться к дочерним элементам.

Что компилируется в:

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

Называйте меня странным, но я также считаю вложенный код тяжёлым для восприятия (так как я писал невложенным CSS более 7 лет).

Заключение

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

Моё отношение к этим препроцессорам такое же как и к CoffeeScript: отличный синтаксис и возможности, но слишком много накладных расходов для не такой реальной выгоды. Синтаксис в JavaScript это не проблема для меня, точно так же как и в CSS (и в большинстве языков). Вам всё равно необходимо понимать, как работает блочная модель, специфичность, каскадирование, селекторы, обтекание и так далее. Вы всего лишь добавляете абстрактную прослойку между собой и интерпретируемыми таблицами стилей, создаёте ещё один барьер для будущих разработчиков и увеличиваете шанс появления чрезмерного проектирования. Разметка может стать проще (с меньшим количеством классов/идентификаторов), но она приходит с большим количество недостатков.

Для меня главной проблемой являются разработчики, которые пишут на CSS без знаний необходимых для построения легко сопровождаемых масштабируемых структур. Таблицу стилей полную примесей, операций сравнения, циклов, переменных, функций будет так же тяжело поддерживать, как и раздутую вручную созданную таблицу стилей, а может даже и сложнее. Разработчики унаследовали желание быть «умными», а это обычно как красный флаг.

«Каждый знает, что отлаживание программы в два раза сложнее, чем её написание. Так если вы проявили максимум своих возможностей, когда писали эту программу, как же вы тогда вообще её отладите?»
Брайан Керниган

Примеси сегодня популярны из-за браузерных префиксов. Проблема не в том, что CSS не поддерживает примеси или переменные нативно, а в том, что нам приходится писать абсурдное количество браузерных префиксов без нужной на то причины, поскольку большинство реализаций аналогичны и большинство возможностей чисто косметические. Проблема также не в синтаксисе языка, а в способе, которым браузеры добавляют новые возможности и людях, использующих их до общей реализации (без префиксов). Это может быть решено препроцессором, который всего лишь добавляет префиксы (без необходимости в примесях и в специальных языках), таким как cssprefixer. Попробуйте подумать, какую в действительности проблему вы пытаетесь решить и поищите разные решения.

«Пришло время упразднять браузерные префиксы. Они стали решением для несуществующей проблемы и активно вредят веб-стандартам»
Питер-Пол Кох

Я использовал подход OOCSS на большинстве моих последних проектов и, скорее всего, продолжу использовать его, пока не найду лучшего. Для тех вещей, которыми я занимаюсь, важнее иметь возможность быстро верстать и вносить обновления на этапе разработки, нежели поддерживать/развивать проект в течение многих месяцев/лет. Мне кажется маловероятным, что придётся делать значительные изменения в дизайне без правки разметки. На моих последних 100 проектах это случилось 2-3 раза. CSS zen garden — классный концепт, но не очень практичный. Такая возможность, как desaturate(@red, 10%) крутая штука, но обычно дизайнеры предоставляют мне цветовую палитру, которую надо использовать на всём сайте, и я не так часто дублирую одни и те же значения. Если значения дублируются, я везде могу их поменять, используя «поиск и замену» внутри всех CSS-файлов и закончить на этом. Используя функцию генерирующую цвет (где вы понятия не имеете, какое значение получится) вы не сможете так просто сделать поиск и замену, поскольку вы не знаете, какое значение ищете в исходном коде (я предпочитаю просто использовать Color Picker).

Я знаю, что мой опыт сильно отличается от опыта большинства людей, поэтому мой подход тоже отличается. Если мне когда-нибудь придётся использовать любой из этих инструментов, это не будет для меня проблемой. Я только не думаю, что они сэкономят мне так много времени, что это перевесит количество недостатков. Выбирайте инструменты основываясь на ваших проектах и рабочем процессе. И не стоит отказываться использовать препроцессоры из-за пары проблем, которые я обозначил. Для многих задач препроцессоры будут отличным способом сгенерировать таблицы стилей. Думайте о недостатках и об ответственности.

С большой силой приходит большая ответственность
дядя Бен

P.S. Я люблю CSS, для меня это одна из самых стоящих задач в разработке сайтов, это как собирать сложный пазл...