Как создать переменные в процессоре sass

Обновлено: 07.07.2024

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

С помощью переменных вы можете избавиться от дублирования кода. Посмотрим, как это работает на примере создания цветовой схемы проекта. Возьмём несколько основных цветов, которыми мы хотим пользоваться:

Теперь в начале нашего SASS-файла мы можем объявить переменные и записать эти значения в них. Для этого используется символ $ и указывается уникальное имя.

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

В результате компиляции получится следующий CSS-код:

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

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

Область видимости

Переменная может быть объявлена как внутри селектора, так и вне его. В зависимости от того, где была объявлена переменная, ей можно пользоваться или во всём проекте или только внутри определённого селектора. Посмотрите на пример такого кода:

Компилятор говорит нам, что на 9 строке используется неизвестная переменная. Но ведь она есть — мы её объявили на 4 строке! Да — в коде действительно существует переменная $bg-color, но она существует только внутри селектора .card и вне этого селектора просто невидна.

Такое поведение называется областью видимости переменной. В зависимости от того, где мы объявили переменную, мы можем получать доступ к ней или во всём проекте, или только внутри одного селектора. Переменная $margin-top в этом примере является глобальной переменной, так как доступ к ней есть в любом участке нашего SASS-файла. Переменная $bg-color в примере является локальной переменной и доступна она только внутри того селектора, где была определена.

Разберём ещё один пример:

Обратите внимание, что переменные $main-bg и $header-bg объявлены внутри селектора .card. Так как селекторы .card-header и .card-body лежат внутри селектора .card, то переменные $main-bg и $header-bg будут доступны для этих селекторов. После компиляции мы получим следующий CSS-код:

Именование переменных

Как говорилось выше, имена переменных должны быть уникальны. Это правило создано для предотвращения возможных ошибок. Ведь на самом деле глобальная и локальная переменная может иметь одно и то же имя. Попробуем в наш последний пример добавить глобальную переменную:

Заметьте, что переменная $main-bg объявлена и в начале SASS-файла и в селекторе .card. Скорее всего с первого взгляда вы не определите какой $main-bg будет использован в проекте. Попробуем скомпилировать этот код. В этот раз ошибок не будет:

Созданная внутри селектора .card переменная $main-bg на самом деле не имеет ничего общего с глобальной переменной $main-bg. Даже при условии того, что они имеют одинаковые имена. Но вот путаницу это может внести, поэтому никогда не используйте одинаковые имена для глобальных и локальных переменных.

Подключение переменных из другого файла

Часто для удобной организации SASS стили разбиваются на несколько независимых файлов, в зависимости от их назначения. Например, у нас может быть следующая структура файлов:

В данной структуре у нас есть главный файл app.scss, в котором мы хотим подключить настройки из файла config.scss и стандартные настройки переменных из файла default_variables.scss. Подключить эти файлы в файл app.scss можно с помощью директивы @import, указав путь к необходимому файлу.

Также при подключении SASS-файлов не обязательно указывать расширение. Компилятор найдёт необходимый файл в указанной директории и подключит его. Значит мы можем немного переписать код и не указывать лишнее расширение.

Порядок подключения файлов в данном случае очень важен. Если внутри файлов config.scss и default_variables.scss будут конфликтующие значения, то возьмётся то, которое было указано последним. Здесь работает то же правило каскадности, что и в CSS: стили, записанные позже, имеют больший приоритет.

Флаг default

Вернёмся к структуре нашего проекта. В default_variables.scss запишем базовые цвета для нашего проекта:

Теперь, подключив файл к нашему основному файлу стилей, мы можем использовать эти переменные. Используем цвета в файле app.scss.

После компиляции получим следующий CSS-код:

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

Если мы изменим цвет непосредственно в файле default_variables.scss, то получим необходимый нам результат. Но иногда такой подход не работает. Если мы используем такой файл в виде пакета, который загружается извне, то изменив значение в локальном файле мы не сможем получать обновления. Наш файл уже не идентичен тому, который расположен на общем сервере.

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

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

Препроцессинг

Написание CSS само по себе весело, но когда таблица стилей становится огромной, то становится и сложно её обслуживать. И вот в таком случае нам поможет препроцессор. Sass позволяет использовать функции недоступные в самом CSS , например, переменные, вложенности, миксины, наследование и другие приятные вещи, возвращающие удобство написания CSS.

Как только Вы начинаете пользоваться Sass, препроцессор обрабатывает ваш Sass-файл и сохраняет его как простой CSS -файл, который Вы сможете использовать на любом сайте.

Самый простой способ получить такой результат - использовать терминал. После того, как Sass установлен, вы можете компилировать ваш Sass в CSS , используя команду sass . Вам всего лишь нужно сообщить Sass, где взять файл Sass и в какой файл CSS его скомпилировать. Например, запустив команду sass input.scss output.css в терминале, вы сообщаете Sass взять один Sass файл, input.scss , и скомпилировать в файл output.css .

Также, вы можете следить за изменениями только определенных файлов или папок, используя флаг --watch . Данный флаг сообщает Sass, что необходимо следить за изменениями указанных файлов и при наличии таковых производить перекомпиляцию CSS после сохранения файлов. Если вы хотите отслеживать изменения (вместо ручной перекомпиляции) вашего файла, например, input.scss , то вам необходимо просто добавить флаг в команду:

Вы также можете указать папки для отслеживания изменений и куда сохранять компилированные CSS файлы, для этого достаточно указать пути и разделить их двоеточием, например:

Sass будет отслеживать все файлы в директории app/sass и компилировать CSS в директорию public/stylesheets .

Переменные

Думайте о переменных, как о способе хранения информации, которую вы хотите использовать на протяжении написания всех стилей проекта. Вы можете хранить в переменных цвета, стеки шрифтов или любые другие значения CSS , которые вы хотите использовать. Чтобы создать переменную в Sass нужно использовать символ $ . Рассмотрим пример:

SCSS Syntax

Sass Syntax

CSS Output

Когда Sass обрабатывается, он принимает значения, заданные нами в $font-stack и $primary-color и вставляет их в обычном CSS -файле в тех местах, где мы указывали переменные как значения. Таким образом переменные становятся мощнейшей возможностью, например, при работе с фирменными цветами, используемыми на всем сайте.

Вложенности

При написании HTML , Вы, наверное, заметили, что он имеет четкую вложенную и визуальную иерархию. С CSS это не так.

Sass позволит вам вкладывать CSS селекторы таким же образом, как и в визуальной иерархии HTML. Но помните, что чрезмерное количество вложенностей делает ваш документ менее читабельным и воспринимаемым, что считается плохой практикой.

Чтобы понять что мы имеем ввиду, приведем типичный пример стилей навигации на сайте:

SCSS Syntax

Sass Syntax

CSS Output

Вы заметили, что селекторы ul , li , и a являются вложенными в селектор nav ? Это отличный способ сделать ваш CSS -файл более читабельным. Когда вы сгенерируете CSS -файл, то на выходе вы получите что-то вроде этого:

Фрагментирование

Вы можете создавать фрагменты Sass-файла, которые будут содержать в себе небольшие отрывки CSS , которые можно будет использовать в других Sass-файлах. Это отличный способ сделать ваш CSS модульным, а также облегчить его обслуживание. Фрагмент — это простой Sass-файл, имя которого начинается с нижнего подчеркивания, например, _partial.scss . Нижнее подчеркивание в имени Sass-файла говорит компилятору о том, что это только фрагмент и он не должен компилироваться в CSS. Фрагменты Sass подключаются при помощи директивы @import .

Импорт

Например, у вас есть несколько фрагментов Sass-файлов — _reset.scss и base.scss . И мы хотим импортировать _reset.scss в base.scss .

SCSS Syntax

Sass Syntax

CSS Output

Миксины (примеси)

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

SCSS Syntax

Sass Syntax

CSS Output

Расширение/Наследование

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

SCSS Syntax

Sass Syntax

CSS Output

Вышеуказанный код сообщает классам .message , .success , .error и .warning вести себя как %message-shared . Это означает, что где бы не вызывался %message-shared , то и .message , .success , .error и .warning тоже будут вызваны. Магия происходит в сгенерированном CSS , где каждый из этих классов получает css-свойства, как и %message-shared . Это позволит вам избежать написания множества классов в HTML элементах.

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

Когда вы генерируете ваш CSS , то он будет выглядеть как пример ниже. Обратите внимание, %equal-heights не попадает в CSS , так как ни разу не был использован.

Математические операторы

Использовать математику в CSS очень полезно. Sass имеет несколько стандартных математических операторов, таких как + , - , * , / и % . В нашем примере мы совершаем простые математические вычисления для расчета ширины aside и article .

SCSS Syntax

Sass Syntax

CSS Output

Мы создали простую адаптивную модульную сетку, с шириной в 960 пикселей. Используя математические операторы, мы использовали полученные данные с пиксельными значениями и конвертировали их в процентные, причем без особых усилий. Скомпилированный CSS выглядит так:

Sass © 2006–2018 Hampton Catlin, Natalie Weizenbaum, Chris Eppstein, Jina Anne, и многочисленные участники. Доступно для использования и изменения по лицензии MIT.

Переменные Sass просты: вы присваиваете значение имени, которое начинается с $ , а затем вы можете ссылаться на это имя вместо самого значения. Но, несмотря на их простоту, это один из самых полезных инструментов, которые предлагает Sass. Переменные позволяют сократить количество повторений, выполнять сложные математические операции, настраивать библиотеки и многое другое.

Объявление переменной очень похоже на объявление свойства: оно написано <variable>: <expression> . В отличие от свойства, которое можно объявить только в правиле стиля или в правиле, переменные можно объявлять где угодно. Чтобы использовать переменную, просто включите ее в значение.

SCSS Syntax

Sass Syntax

CSS Output

⚠️ Внимание!

В CSS есть собственные переменные, которые полностью отличаются от переменных Sass. Знай различия!

Все переменные Sass компилируются с помощью Sass. Переменные CSS включены в вывод CSS.

Переменные CSS могут иметь разные значения для разных элементов, но переменные Sass имеют только одно значение за раз.

Переменные Sass являются императивными, что означает, что если вы используете переменную, а затем измените ее значение, предыдущее использование останется прежним. Переменные CSS декларативны, что означает, что если вы измените значение, это повлияет как на предыдущее, так и на последующее использование.

SCSS Syntax

Sass Syntax

CSS Output

💡 Интересный факт:

Переменные Sass, как и все идентификаторы Sass, рассматривают дефисы и подчеркивания как идентичные. Это означает, что $font-size и $font_size оба относятся к одной и той же переменной. Это историческое наследие самых ранних дней Sass, когда в именах идентификаторов разрешались только символы подчеркивания. После того, как Sass добавил поддержку дефисов в соответствии с синтаксисом CSS , они стали эквивалентными, чтобы упростить миграцию.

Значения по умолчанию permalink Значения по умолчанию

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

Чтобы сделать это возможным, Sass предоставляет флаг !default . Это присваивает значение переменной, только если эта переменная не определена или ее значение равно null . В противном случае будет использоваться существующее значение.

Настройка модулей permalink Настройка модулей

В настоящее время только Dart Sass поддерживает @use . Пользователи других реализаций должны использовать правило @import rule вместо этого.

Переменные, определенные с помощью !default , могут быть настроены при загрузке модуля с помощью правила @use . Библиотеки Sass часто используют переменные !default , чтобы позволить своим пользователям настраивать CSS библиотеки.

Чтобы загрузить модуль с конфигурацией, напишите @use <url> с (<variable>: <value>, <variable>: <value>) . Настроенные значения заменят значения переменных по умолчанию. Могут быть настроены только переменные, записанные на верхнем уровне таблицы стилей с флагом !default .

SCSS Syntax

Sass Syntax

CSS Output

Встроенные переменные permalink Встроенные переменные

Переменные, определенные встроенным модулем, не могут быть изменены.

SCSS Syntax

Sass Syntax

Область видимости permalink Область видимости

Переменные, объявленные на верхнем уровне таблицы стилей, являются глобальными. Это означает, что к ним можно получить доступ в любом месте их модуля после того, как они были объявлены. Но это верно не для всех переменных. Те, которые объявлены в блоках (фигурные скобки в SCSS или код с отступом в Sass), обычно являются локальными, и к ним можно получить доступ только внутри блока, в котором они были объявлены.

SCSS Syntax

Sass Syntax

CSS Output

Затенение permalink Затенение

Локальные переменные можно даже объявлять с тем же именем, что и глобальная переменная. Если это произойдет, на самом деле есть две разные переменные с одним и тем же именем: одна локальная и одна глобальная. Это помогает гарантировать, что автор, пишущий локальную переменную, случайно не изменит значение глобальной переменной, о которой он даже не подозревает.

SCSS Syntax

Sass Syntax

CSS Output

Если вам нужно установить значение глобальной переменной из локальной области видимости (например, в миксине), вы можете использовать флаг !global . Объявление переменной, помеченное как !global , всегда будет присвоено глобальной области видимости.

SCSS Syntax

Sass Syntax

CSS Output

⚠️ Внимание!

Старые версии Sass позволяли использовать !global для переменной, которая еще не существует. Это поведение устарело, чтобы гарантировать, что каждая таблица стилей объявляет одни и те же переменные независимо от того, как она выполняется.

Флаг !global может использоваться только для установки переменной, которая уже была объявлена на верхнем уровне файла. Его нельзя использовать для объявления новой переменной.

Область управления потоком permalink Область управления потоком

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

SCSS Syntax

Sass Syntax

CSS Output

⚠️ Внимание!

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

Продвинутые функции переменных permalink Продвинутые функции переменных

Основная библиотека Sass предоставляет несколько дополнительных функций для работы с переменными. Функция meta.variable-exists() возвращает, существует ли переменная с данным именем в текущей области, а функция meta.global-variable-exists() делает то же самое. но только в глобальном масштабе.

⚠️ Внимание!

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

Правила управления переменными в препроцессорах и методика переопределения настроек

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

Предыстория

В 2014 году в компании начали редизайн проекта и в основу вёрстки мы положили свежий на тот момент Bootstrap 3.0.1. Использовали мы его не как отдельную стороннюю библиотеку, а тесно заинтегрировали с нашим собственным кодом: отредактировали переменные под наш дизайн и компилировали кастомизированный Бутстрап из LESS исходников самостоятельно. Проект оброс собственными модулями, которые использовали бутстраповские переменные и добавляли в файл с настройками свои новые переменные.

В тот момент я думал, что это правильный подход.

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

Через год с небольшим редизайн закончился, проект вышел в продакшн, и мы взялись за технический долг. При попытке обновить Бутстрап до версии 3.6.x выяснилось, что смержить новый variables.less с нашим файлом настроек будет нелегко. В Бутстрапе переименовали или убрали часть переменных, добавили новые. Собственные компоненты Бутстрапа обновились без проблем, а вот наши компоненты падали при компиляции из-за этих изменений.

Проблемы

Мы проанализировали ситуацию и сформулировали проблемы.

Слишком связанный код.

Сами компоненты лежали в отдельных файлах. Это создавало иллюзию, что компоненты независимые. Но компоненты использовали переменные, объявленные во внешнем файле variables.less, и без этого файла не работали. Нельзя было просто так взять и переместить компонент в другой проект. Приходилось тянуть за собой файл с настройками, который со временем превратился в помойку.

Слишком много глобальных переменных.

У Бутстрапа было ≈400 переменных. Мы отключили неиспользуемые компоненты Бутстрапа, но переменные оставили в конфиге на случай, если снова понадобятся. Еще мы добавили сотню или полторы своих переменных. Все названия не запомнить, трудно быстро находить нужные. Даже с правилами именования и комментариями ориентироваться в конфиге из 500+ переменных тяжело.

Имена глобальных переменных вышли из-под контроля.

Одна и та же переменная могла использоваться в разных файлах и отслеживать все её появления в коде было долго и трудно. Когда меняли значение переменной в одном компоненте, был риск поломать другие компоненты. Разработчики хардкодили, создавали новые переменные с похожими названиями и значениями и уже не следили за логикой именования.

Как решать

Я придумал три правила, которые помогли побороть наши проблемы:

Переменная используется только в том файле, в котором объявлена.

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

Все переменные внутри компонента — локальные.

Раз у каждого компонента свои переменные, пусть они будут локальными. Это избавит от проблем с именованием: в компонентах можно использовать переменные с одинаковыми именами и разными значениями — они не будут конфликтовать друг с другом.

Глобальные переменные используются только внутри файла настроек.

Благодаря первым двум правилам мы сильно сократим количество глобальных переменных, но они всё равно нужны. Глобальные переменные объявляются в главном файле проекта или в файле типа config.less. К ним тоже применяется правило №1 — переменные не используются за пределами своего файла. Это значит, что нельзя использовать глобальные переменные внутри файлов компонентов. Но существует способ не нарушая первого правила прокинуть значение глобальной переменной внутрь компонента. Как это сделать мы рассмотрим на примерах далее.

Третье правило избыточное. Соблюдая первые два, вы автоматически соблюдаете третье. Но в реальной жизни есть очень большой соблазн пойти по простейшему пути, не создавать локальную переменную, а по-быстрому использовать глобальную. Третье правило напоминает, что так делать вредно, что это создаёт ненужные зависимости и приводит к связыванию кода.

Применим правила на практике.

Реализация на LESS

Представим простейший компонент для стилизации страницы. Согласно правилу №1 создадим переменные внутри файла компонента.

Правило 1
Переменная используется только в том файле, в котором объявлена.

Было. Пример кода компонента.

Стало. Переменные объявлены в глобальной области видимости и у них слишком общие имена. Это плохо.

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

Локальные переменные

Область видимости — это «пространство» между фигурными скобками селектора: < и >. Объявленные внутри фигурных скобок переменные работают только внутри этих скобок и внутри дочерних скобок, но их нельзя использовать снаружи.

Если скобок вокруг нет, то это самый верхний уровень — глобальная область видимости.

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

По правилу №2 сделаем переменные локальными — переместим их внутрь селектора.

Правило 2
Все переменные внутри компонента — локальные.

Переменные объявлены внутри селектора и не создают конфликта имён, потому что теперь они локальные.

Теперь конфликта имен с другими компонентами не будет. Мы решили первую и вторую проблемы: получился изолированный сниппет без внешних зависимостей. Но я не знаю способа переопределить локальные переменные компонента в таком виде извне. Поэтому, чтобы кастомизировать компоненты глобальными переменными проекта, придумал другую форму записи.

Миксины как функции

В LESS можно использовать миксины как функции. Если внутри миксина создать переменные, а потом вызвать миксин внутри селектора, то переменные будут доступны в области видимости этого селектора.

Вынесем объявление переменных внутрь миксина .page-settings() , а потом вызовем его внутри селектора .page :

Миксин доставляет переменные в зону видимости селектора.

Переменные локализованы внутри глобального миксина. Когда мы вызвали миксин в коде, переменные стали доступны в области видимости селектора .page , но по прежнему остались локальными.

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

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

Слияние миксинов

В LESS существует «ленивое вычисление» переменных: не обязательно объявлять LESS-переменную перед её использованием, можно объявить после. В момент компиляции парсер LESS найдет определение переменной и отрендерит значение этой переменной в CSS.

Если переопределить переменную, то во всех местах её использования в силу вступит значение из самого последнего определения, так как оно приоритетнее по порядку следования в исходном коде. В этом смысле переменные ведут себя как константы.

Итак, переменные можно объявлять и до, и после использования, а миксины — это разновидность переменных. Если создать два миксина с одним и тем же именем и разным содержанием, то они объединяют свои внутренности. А если внутри миксинов есть переменные с одинаковыми именами, то происходит переопределение. Приоритет выше у последнего миксина.

Рассмотрим три файла:

Главный файл. Импортируем компоненты и конфиг. Конфиг — последним.

Компонент. Все переменные локальные и хранятся в миксине.

Конфиг проекта. Переопределяем параметры компонента с помощью миксина настроек.

Всё самое интересное происходит в конфиге. Мы создали глобальные переменные и использовали их в этом же файле для кастомизации компонента.

Миксин .page-settings() объявлен два раза. Первый раз внутри файла page.less с дефолтными значениями, второй раз в файле config.less с новыми значениями. На этапе компиляции миксины склеиваются, новые переменные переопределяют дефолтные и CSS рендерится с новыми значениями из файла конфигурации.

Правило 3
Глобальные переменные используются только внутри файла настроек.

Обратите внимание, что config.less инклюдится последним в списке. Это нужно, чтобы объявление миксина в конфиге имело больший приоритет, чем исходное объявление в файле самого компонента. Настройки не применятся, если поставить config.less до компонента, потому что на миксины тоже действуют правило «последнее определение — самое сильное».

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

  1. переменные использовались только в своём файле, даже глобальные переменные не вызывались за пределами файла config.less ;
  2. переменные компонента остались локальными и не засорили глобальную область видимости;
  3. глобальные переменные не использовались внутри компонента напрямую, но значения глобальных переменных хитрым способом попали внутрь компонента.

Ограничения

Нельзя, чтобы имя глобальной переменной совпадало с именем локальной — получим рекурсию и CSS не скомпилируется. Чтобы не ошибиться, лучше все глобальные переменные записывать с префиксом.

Неправильно. Рекурсивное определение переменной вызывает ошибку компиляции.

Правильно. У глобальных переменных свой префикс glob-, что исключает совпадение имён.

Реализация в SASS

SASS отличается от LESS и больше похож на скриптовый язык программирования: нет «ленивых вычислений» и переменная должна быть обязательно объявлена до её использования в коде. Если определить переменную и использовать её в коде, а потом переопределить и использовать ещё раз, то в первый вызов получим исходное значение в CSS, а во второй вызов новое значение. Трюк с миксинами, как в LESS, не пройдет. Но есть другие пути решения.

Наборы переменных для настройки компонента удобно хранить в map-объектах. Это массив из пар «ключ: значение». Метод map-get извлекает конкретное значение из массива, метод map-mergeобъединяет два массива в один, дополняя или переписывая исходный массив.

Простейший компонент без возможности переопределения извне будет выглядеть так:

Настройки хранятся в map-объекте и вызываются в коде с помощью map-get

Чтобы настраивать компонент из другого файла, нужно предусмотреть возможность смержить внешний конфиг с исходными настройками. Рассмотрим три файла:

Главный файл.
Сначала импортируем конфиг, потом компоненты.

Настройки.
Создаём глобальные переменные и переопределяем параметры компонента.

Компонент.
Добавили проверку: а не существуют ли уже настройки, чтобы переопределить компонент?

[1] — В компоненте мы сначала объявили переменную с пустым массивом $page-override .

[2] — Потом проверили, а не существует ли уже переменная $page-settings . И если она уже была объявлена в конфиге, то присвоили её значение переменной $page-override .

[3] — И потом смержили исходный конфиг и $page-override в переменную $page-settings .

Если массив $page-settings был объявлен ранее в глобальном конфиге, то $page-override перепишет настройки при слиянии. Иначе в переменной $page-override будет пустой массив, и в настройках останутся исходные значения.

Я не знаю всех тонкостей SASS, может есть способ реализовать эту методику более красивым способом.

В результате, мы получаем всё те же преимущества, только в отличие от LESS нам приходится переопределять все настройки заранее, перед их использованием в коде.

Выводы

Не важно на чем вы пишете — на LESS, SASS, CSS c кастомными свойствами или Javascript — глобальных переменных должно быть как можно меньше.

С CSS препроцессорами используйте три правила, которые помогут избежать хаоса:

  1. Переменная используется только в том файле, в котором объявлена.
  2. Все переменные внутри компонента — локальные.
  3. Глобальные переменные используются только внутри файла настроек.

Чтобы прокинуть глобальные настройки внутрь компонента, собирайте переменные в миксин (LESS) или map-объект (SASS).

Переопределяйте настройки в правильном месте: в LESS — после инклюда, в SASS — перед инклюдом.

Реальные примеры

Я сформулировал эту методику в декабре 2015 года для LESS и с тех пор применяю её на рабочих и личных проектах.

За полтора года появилось несколько публичных npm-пакетов. Посмотрите исходный код для лучшего понимания, как это работает в реальных ситуациях.

В языке SASS переменные должны начинаться со знаками доллара ("$"). Двоеточие после переменной означает присваивание переменной какого-то значения, в выходном CSS-е это не будет отображено. Если после переменной нет двоеточия, то это говорит препроцессору заменить в выходном CSS-е переменную ее значением.

На видимость переменных влияет уровень вложенности селекторов. Если переменная определена вне каких-либо вложенных селекторов, она видна везде. Переменная может быть определена с !global (использование !global это плохая практика усложняющая поддержку проекта), и в этом случае она также будет видна везде. Например:

$width : 5em !global ;

В языке sass имена переменных и все другие идентификаторы, как дефисы, так и нижнее подчеркивание являются взаимозаменяемыми. Например, если вы определяете переменную $main-width, вы можете получить доступ к ней, как $main_width, и наоборот.

Типы данных языка SASS

В языке sass поддерживается семь основных типов переменных:

    1 numbers - числовый тип, включает в себя все цифровые обозначения которые встречаются в CSS. Данный тип может быть представлен в px, %, em, rem.

Примеры данного типа: 1.2, 3, 10px;

Примеры данного типа: 1.5em 1em 0 2em, Helvetica, Arial, sans-serif.

Пример данного типа: (key1: value1, key2: value2).

Числовой тип языка SASS (numbers)

Как видно из названия данного типа, это любые числа которые встречаются в CSS-e. Числа - это единицы измерения, и данный тип служит для определения единиц измерения. Это px, %, em, rem. Перед выводом данного типа в выходной CSS, сначало выполняются математические действия (+, -, *, /), и в выходной CSS выводится уже готовый результат. Строчка margin: 14px (20px+30px)/2px-5px будет преобразована в margin: 14px 20px. Любое из этих чисел можно вынести в переменную, результат будет тем же.

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

// Данный пример работать не будет, рабочий пример показан ниже

$fontFamily : Tahoma, "Geneva CY", sans-serif ;

font : $fontSize / 120% fontFamily ;

Впринципе это логично, эта часть кода у большинства разработчиков кочует от проекта в проект. Она одинаковая, меняется только основной цвет текста, размер и семейство шрифта. Если подумать, то удобнее переменные $fontSize, $fontFamily, $mainColor вынести в отдельный файл, открыл его, быстро поправил переменные, и все хорошо. Так вот, при компиляции данная конструкция работать не будет. Смотрите, у нас переменная $fontSize измеряется в px, а межстрочный интервал измеряется в процентах. / - в языке sass означает знак деления, а разделить "px" на проценты не возможно, как следствие компилятор выдаст ошибку. Для того, чтобы обойти выполнение арифметических операций и подставить значение переменных в выходной CSS делают так:

$fontFamily : Tahoma, "Geneva CY", sans-serif ;

font : 14px/120% Tahoma, "Geneva CY", sans-serif ;

Текстовый тип языка SASS (strings)

Текстовый тип - это почти все значения свойств которые встречаются в CSS-е. На практике, в большинстве случаев это семейство шрифтов (если указали одно название, без запятых), пути к картинкам в background-е. Что-то другое выносить в переменные особого смысла нет.

В CSS-е название шрифта которое содержит пробелы должно быть обернуто в кавычки, к примеру: "Courier New" или "Century Schoolbook L". В кавычки также может быть обернут и адрес к картинке в background-е. Большая часть свойств CSS пишется без кавычек, к примеру, если речь идет о шрифтах, то Tahoma, sans-serif пишутся без кавычек. Если отвлечься от шрифтов, то значение bold свойства font-weight, или значение italic свойства font-style тоже пишутся без кавычек. Если вы переменной присваиваете значение в кавычках, то и в выходном CSS-е значение этой переменной выведется с кавычками, а если без кавычек, то это значение выведется тоже без кавычек.

Если мы хотим занести значения свойств в переменные, то тип этих переменных будет текстовый (strings). На практике вам предстоит работать или с числовым типом, или задавать семейство шрифтов через тип lists. Строковый тип редко применяется. Для того, чтобы вывести строку в миксине делается так:

@mixin firefox-message ( $selector )

content: " Hi, Firefox users! ";

@include firefox-message (" .header ");

body.firefox .header : before

content : " Hi, Firefox users! ";

Для данного типа возможно применить сложение. Во многих языках программирования это называется конкатенация строк. Как я выше писал, данный тип применяется достаточно редко, но все же применяется. Пример:

$fontFamily : Tahoma, "Geneva CY", sans-serif ;

font : 700 italic 14px / 120% Tahoma,"Geneva CY",sans-serif ;

content : " (ссылка на внешний сайт -" attr(href) ")"

Пример выше показывает стандартную заготовку для сайта, а вернее отдельный ее кусок. Переменные стоит вынести в отдельный файл, как я выше писал так удобнее работать. В данной зоготовки используются все типа переменных, с которыми вы будете в основном работать. К текстовому типу переменных относятся переменные - $fontStyle, $fontWeight:, $afterLinkT. Цветовой тип переменной это переменная $mainColor. Числовой тип переменных это перменные $fontSize, $fontLH. К списку значений, разделенных пробелами или запятыми относится переменная $fontFamily.

Цветовой тип языка SASS (colors)

В CSS цвета могут быть выведены в шестнадцатиричном формате, формате rgb (в том числе rgba). Так же для цветов зарезервированы слова (это red, blue и тд). Для данного типа доступны все арифметические операции, можно даже умножать данный тип на число, но есть одно но.

Как известно в web-е используется модель rgb. Перед выполнением математической операции сначало произойдет разложение цвета на эту модель, а потом будет выполнено математическое действие. Проще это увидеть на примере:

В данном примере произошло тоже самое, сперва на цветовые составляющие было разложено первое число, затем второе, и произошло сложение по цветовым составляющим.

Как я выше писал для данного типа зарезервированы слова. Для нас это означает, что возможна и такая запись:

color : rgb(50, 0, 0) + red ;

color : rgb(200, 00, 00) + rgb(55, 00, 00) ;

color : rgb(200, 00, 00) + rgb(100, 00, 00) ;

В примере выше красная составляющая для первого цвета составляет 200, красная составляющая для второго цвета составляет 100, при сложении получается 300. Но максимальный объем для формата rgb не может быть больше 255, происходит переполнение, и на выходе получаем rgb(255, 0, 0) или просто red.

Есть еще один формат для цветового типа, это формат rgba. Он стоит особняком по сравнению с другими форматами. В sass нельзя сложить два числа с разными альфа каналами. Посмотрите пример:

color : rgba(200, 00, 00, .5) + rgba(55, 00, 00, 0.5) ;

color : rgba(255, 00, 00, 0.5) ;

Как мы видим сложение по альфаканалам не произошло. Более того, если мы попытаемся к чмслу в формате rgba добавить шестнадцатиричное число, или число в формате rgb, то мы получим ошибку.

Cписки значений, разделенных пробелами или запятыми языка SASS (lists)

Как следует из названия данного типа, к нему относятся все значения разделенные пробелами или запятыми. К примеру, это может быть значения padding-а - 15px 0 или значение font-face - Arial, "Helvetica CY", "Nimbus Sans L", sans-serif.

Для работы с данным типом в языке sass существует множество функций. Списки можно соединять, можно добавлять отдельные элементы в списки. Все это можно делать, но я этого делать не советую. Не стоит усложнять.

Тип lists может быть как простым, так и составным. Простой тип lists это 10px 20px, составной тип lists это 10px 20px, 30px 40px. Составные списки могут состоять из 2, 3 и более списков. Для того, чтобы понять где начинается первый, или второй элемент списка официальная документация по языку sass советует группировать их следующим образом: (10px 20px) (30px 40px). После компиляции в выходной CSS компилятор не добавит скобки.

Тип lists может не иметь никаких пунктов вообще, иначе говоря быть пустым. Такой тип lists представлен как () (это как тип map который не имеет значений, о типе map будет написано ниже). Пустой тип lists при компиляции не будет выведен в выходной CSS. такая запись вызовет ошибку компиляции: padding: (). Если же вы используете составные списки, и один из элементов составного списка пустой, то он не будет выведен в выходном CSS.

От себя могу сказать, что с тип lists в большинстве случаев используется для задания font-family. Каким может быть тип lists знать нужно, нужно знать методы которые к нему применяются, но на практике вы будете использовать его только для задания font-family. Для margin и padding лучше использовать числовые переменные, они понятнее и ими проще манипулировать.

Карты от одного значения к другому языка SASS (maps)

Тип maps очень похож на объекты в javascript. Данный тип представляет собой набор ключей и значений. В качетве значения может быть использован любой тип переменных языка sass. Обычно для вывода типа maps используют управляющую конструкцию @each, хотя есть и другие методы которые с ним работают. Без использования этих методов вывести значение ключей данного типа не получится.

Читайте также: