Перейти к содержанию

Импорт стилей

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

Импорт стилей в CSS

В CSS директива @import позволяет импортировать стили из других таблиц. Проще говоря, можно разбить одну большую таблицу стилей на несколько маленьких. Делается это следующим образом:

@import url('имя файла');
@import 'имя файла';

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

.class {
  background-color: #fff;
}

@import 'имя файла';

Разрешено делать только так:

@import 'имя файла';

.class {
  background-color: #fff;
}

Причём имя файла должно быть с расширением .css.

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

Импорт стилей в Less

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

@import (keyword) 'имя файла';

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

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

.one {
  background-color: #000;
}

@import 'имя файла';

.two {
  background-color: #fff;
}

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

Файлы с расширением .css:

Если при подключении файла с помощью директивы @import будет указано расширение .css, то такой файл подключается как обычный css-файл и не обрабатывается компилятором.

Файлы без расширения:

Если при подключении файла с помощью директивы @import у него не будет указано расширение, то такой файл подключается как less-файл и обрабатывается компилятором.

Файлы с другими расширениями:

Если при подключении файла с помощью директивы @import у него будет указано расширение, но оно не соответствует ни .css ни .less, то такой файл подключается как less-файл и будет обрабатываться компилятором.

Все это вкупе с доступными опциями для директивы @import, которые будут рассматриваться позднее, даёт вам возможность построения гибкой и хорошо поддерживаемой структуры проекта. Про структуру проекта я буду рассказывать намного позднее, так как без полного понимания доступных возможностей Less она вам не пригодится.

Пример 2.6.1

Рассмотрим пример, который отображает всю суть импорта стилей в Less. Для этого создадим в директории import/ следующие файлы: _duckduckgo.less, _mail.css, _yandex.less и _yahoo.less. В этих файлах объявим одноимённые с названиями файлов классы и укажем с помощью свойства color официальный цвет сервиса. Кроме них нам понадобится файл _styles.less, к которому будут подключаться эти файлы.

Для наглядности я предлагаю посмотреть на карту директории этого примера:

2.6.1/
├── import/
│   ├── _duckduckgo.less
│   ├── _mail.css
│   ├── _yahoo.less
│   └── _yandex.less
└── _styles.less

Теперь я предлагаю взглянуть на содержимое файла _styles.less и то, что получилось после его компиляции.

Содержимое файла _styles.less:

@import 'import/_mail.css';
@import 'import/_duckduckgo';

.canonium {
  color: #53599a;
}

@import 'import/_yahoo';
@import 'import/_yandex';

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

Содержимое файла styles.css, полученное после компиляции:

@import 'import/_mail.css';
.duckduckgo {
  color: #de5833;
}
.canonium {
  color: #53599a;
}
.yahoo {
  color: #400191;
}
.yandex {
  color: #ffcc00;
}

Во время компиляции происходит конкатенация содержимого файлов. А файлы с расширением .css подключаются стандартным для CSS способом.

Опции импорта

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

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

Опция (less)

С помощью этого ключевого слова можно попросить компилятор рассматривать подключаемый файл как less-файл, то есть производить его компиляцию, а также конкатенацию с тем файлом, где происходит его подключение.

Может пригодиться при использовании файлов, которые имеют не стандартное расширение, например, .variables или .mixin.

Пример 2.6.2

Необходимо подключить файл _mail.css:

.mail {
  color: #168de2;
}

.mail .orange {
  color: #ffa930;
}

Если подключить этот файл как раньше, с помощью импорта без ключевых слов (@import "import/_mail.css";), то файл будет подключён как обычный CSS-файл в файле styles.css.

@import 'import/_mail.css';
.canonium {
  color: #53599a;
}

Но нам необходимо провести конкатенацию этих двух файлов. Для этого требуется указать ключевое слово less. Тогда файл styles.css приобретает необходимый нам вид:

.canonium {
  color: #53599a;
}
.mail {
  color: #168de2;
}
.mail .orange {
  color: #ffa930;
}

Опция (css)

Полная противоположность опции (less). На этот раз мы можем заставить любой файл подключаться стандартным для CSS способом.

Пример 2.6.3

На этот раз стоит задача подключения файла стандартным для CSS способом. Без лишних слов. Просто посмотрите на код:

@import (css) 'import/_duckduckgo.less';

.canonium {
  color: #53599a;
}

После компиляции:

@import 'import/_duckduckgo.less';
.canonium {
  color: #53599a;
}

Опция (reference)

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

Пример 2.6.4

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

Немного изменим файл _yandex.less, чтобы можно было продемонстрировать работу более наглядно:

.yandex {
  color: #ffcc00;
}

.yandex-topbar {
  background-color: #e4491b;
}

В файле _styles.less добавим ключевое слово (reference):

.canonium {
  color: #53599a;
}

@import (reference) 'import/_yandex';

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

Добавим явный вызов в файл _styles.less, в виде псевдокласса :extend(). Делается это следующим образом:

.canonium {
  color: #53599a;
}

@import (reference) 'import/_yandex';

.topbar {
  &:extend(.yandex-topbar);
}

Теперь, после компиляции в получившемся CSS-файле у класса .topbar появятся все свойства класса .yandex-topbar, объявленного в импортируемом файле. При этом класс .yandex в этот файл добавлен не будет.

.canonium {
  color: #53599a;
}
.topbar {
  background-color: #e4491b;
}

Опция (inline)

Задача этой опции сказать компилятору, что разработчик ожидает на выходе подключённый файл, но без обработки компилятором. Такая опция может пригодиться при подключении CSS-файла, в котором присутствуют конструкции, которые в Less необходимо преобразовывать. Например, используемое в IE свойство filter: ms:alwaysHasItsOwnSyntax.For.Stuff();, требующее экранирования в Less.

Пример 2.6.5

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

Добавим в файл _mail.css класс, содержащий свойство filter:

.mail {
  color: #168de2;
  filter: ms:alwaysHasItsOwnSyntax.For.Stuff();
}

Помимо этого, добавим ключевое слово (less) в файле _styles.less, чтобы CSS-файл склеивался с less-файлом:

@import (less) 'import/_mail.css';

.canonium {
  color: #53599a;
}

Производим компиляцию стандартным способом. Но не тут-то было, вместо счастливого финала наш компилятор как-то приуныл и выдал ошибку. В ней говорится, что он не понимает предоставленный синтаксис и ему хочется, чтобы мы его исправили.

Ошибка

Именно сейчас и пригодится рассматриваемая опция (inline). Дописываем её в директиву @import через запятую:

@import (less, inline) 'import/_mail.css';

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

.mail {
  color: #168de2;
  filter: ms:alwaysHasItsOwnSyntax.For.Stuff();
}
.canonium {
  color: #53599a;
}

Опция (once) и (multiple)

Я не зря объединил эти две опции. Они представляют собой абсолютную дуальную пару, то есть они полностью противоположны по значению.

Ключевое слово (once) запрещает многократное подключение файла с таким именем. Эта опция включена в Less изначально, и прописывать её в директиве @import не нужно.

Ключевое слово (multiple) разрешает многократное подключение файла с таким именем.

Пример 2.6.6

Попробуем провести эксперимент. Сначала объявим директиву @import без опций, потом запретим многократное подключение с помощью (once), а затем разрешим, используя (multiple). После этого обговорим полученные результаты. Приступаем.

Объявим директиву @import без опций:

@import 'import/_yahoo';

.canonium {
  color: #53599a;
}

@import 'import/_yahoo';

В полученном результате файл подключился ровно один раз, так как все директивы импорта файлов содержат опцию (once) по умолчанию.

.yahoo {
  color: #400191;
}
.canonium {
  color: #53599a;
}

Объявим директиву @import с опцией (once):

@import (once) 'import/_yandex';

.canonium {
  color: #53599a;
}

@import (once) 'import/_yandex';

И снова тот же результат. Очевидно, что опция (once) все таки установлена по умолчанию, а её повторное применение ничего не меняет.

.yandex {
  color: #ffcc00;
}
.canonium {
  color: #53599a;
}

Объявим директиву @import с опцией (multiple):

@import (multiple) 'import/_duckduckgo';

.canonium {
  color: #53599a;
}

@import (multiple) 'import/_duckduckgo';

На этот раз скомпилированный CSS-код содержит селектор .duckduckgo дважды, а это значит, что опция (multiple) сработала.

.duckduckgo {
  color: #de5833;
}
.canonium {
  color: #53599a;
}
.duckduckgo {
  color: #de5833;
}

Опция (optional)

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

Пример 2.6.7

В этом примере есть обязательный для компиляции файл _duckduckgo.less, а также два необязательных: _yahoo.less и _yandex.less. Один из этих файлов будет удалён.

@import 'import/_duckduckgo';
@import (optional) 'import/_yahoo';
@import (optional) 'import/_yandex';

.canonium {
  color: #53599a;
}

Пусть будет отсутствовать файл _yahoo.less. Тогда после компиляции получится следующий CSS-код:

.duckduckgo {
  color: #de5833;
}
.yandex {
  color: #ffcc00;
}
.canonium {
  color: #53599a;
}

Мысли и советы

Несколько советов, которые позволят сделать ваш код лучше на этом этапе:

  • Не указывайте расширение файлов без явной на то нужды, это делает структуру более приятной для чтения.
  • Создайте один файл, в котором будут объявлены все директивы импорта файлов в проекте.