Статьи

Построение линейно-градиентного миксина в Sass

Перво-наперво: вам, вероятно, не следует использовать препроцессор, здесь Sass, для добавления префиксов вендоров в свойства CSS. Это не та вещь, которую вы хотите привнести в свою базу кода. Как правило, это то, что вы хотите обработать чем-то вроде Autoprefixer

Autoprefixer не только сделает гораздо лучше, чем вы, печатая точные префиксы (я смотрю на вас, разработчиков, которые пишут -ms-linear-gradient и -moz-border-radius ), но это также очень легко обновлять, поддерживать и масштаб. Все делается из файла конфигурации, а не из таблиц стилей.

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

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

Строим миксин

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

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

Давайте вспомним, что нам нужно сделать:

  • Выведите первый цвет как запасной вариант, если CSS-градиенты не поддерживаются.
  • Выведите -webkit- префиксом -webkit- при преобразовании угла в старый синтаксис.
  • Выведите стандартную декларацию, как указано.

Тогда нашему миксину нужны две вещи: направление и любое количество дополнительных аргументов, которые будут напечатаны при передаче.

 /// Mixin printing a linear-gradient /// as well as a plain color fallback /// and the `-webkit-` prefixed declaration /// @access public /// @param {Keyword | Angle} $direction - Linear gradient direction /// @param {Arglist} $color-stops - List of color-stops composing the gradient @mixin linear-gradient($direction, $color-stops...) { background: nth(nth($color-stops, 1), 1); background: -webkit-linear-gradient(legacy-direction($direction), $color-stops); background: linear-gradient($direction, $color-stops); } 

Не беспокойтесь слишком сильно о функции legacy-direction и запасном варианте. Мы вернемся к этим позже. Теперь направление является необязательным в линейно-градиентной нотации. Например, следующее объявление является абсолютно действительным:

 .selector { background-image: linear-gradient(hotpink, tomato); } 

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

 .selector { @include linear-gradient(hotpink, tomato); } 

В этом случае $direction — это hotpink , а $color-stops arglist — это arglist с одним значением: tomato . Из-за этого нам нужен наш mixin, чтобы определить значение по умолчанию для $direction если оно не является допустимым направлением (угол или ключевое слово direction). В этом случае текущее $direction , цвет, необходимо добавить в список $color-stops .

Это может показаться немного сложным, но поверьте мне, все будет ясно с помощью следующего фрагмента кода:

 @mixin linear-gradient($direction, $color-stops...) { // Direction has been omitted and happens to be a color-stop @if is-direction($direction) == false { $color-stops: $direction, $color-stops; $direction: 180deg; } background: nth(nth($color-stops, 1), 1); background: -webkit-linear-gradient(legacy-direction($direction), $color-stops); background: linear-gradient($direction, $color-stops); } 

Напомним: если аргумент $direction не является направлением (мы рассмотрим функцию is-direction позже), мы добавляем его в список $color-stops color-stop (потому что это color-stop) и переопределяем $direction до 180deg , значение по умолчанию. Легко, правда?

Мы почти закончили, позвольте мне объяснить, как работает запасной вариант, потому что он может выглядеть странно. Мы хотим, чтобы первое значение $color-stops списке $color-stops было запасным цветом в случае, если линейные градиенты не поддерживаются.

Кто-то может подумать, что nth($color-stops, 1) будет достаточно, но что, если первое значение окажется длинным списком из 2 элементов, содержащим цвет и остановку цвета (например, hotpink 42% )? Из-за этого мы всегда выбираем значение цвета, используя nth(nth($color-stops, 1), 1) , также известное как первое значение первого значения $color-stops .

Проверка, является ли значение направлением

Первая строка нашего миксина проверяет, является ли аргумент $direction действительным направлением согласно спецификациям CSS. Для этого нет встроенной функции, поэтому нам нужно ее создать. Это не очень сложно само по себе, но оказывается, что существует довольно много способов определить направление в CSS. Если мы придерживаемся линейных градиентов, вот разные варианты:

  • значение ключевого слова: to top to bottom right to top right (или to right top ), to right , to bottom right (или to right bottom ), to bottom , to bottom left (или to left bottom ), to left , to left top ( или to top left );
  • угол в deg , rad , grad или turn .

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

 /// Test if `$value` is a valid direction /// @param {*} $value - Value to test /// @return {Bool} @function is-direction($value) { $is-keyword: index((to top, to top right, to right top, to right, to bottom right, to right bottom, to bottom, to bottom left, to left bottom, to left, to left top, to top left), $value); $is-angle: type-of($value) == 'number' and index('deg' 'grad' 'turn' 'rad', unit($value)); @return $is-keyword or $is-angle; } 

Преобразование угла в унаследованный синтаксис

Версия WebKit опирается на старый синтаксис, где:

Итак, нам нужна наша функция legacy-direction чтобы:

  • вернуть точное ключевое слово, если вход является ключевым словом;
  • вернуть точный угол, если вход является углом;
  • выдает ошибку, если ввод не является ни ключевым словом, ни углом.
 /// Convert a direction to legacy syntax /// @param {Keyword | Angle} $value - Value to convert /// @require {function} is-direction /// @require {function} convert-angle /// @throw Cannot convert `#{$value}` to legacy syntax because it doesn't seem to be a direction.; @function legacy-direction($value) { @if is-direction($value) == false { @error "Cannot convert `#{$value}` to legacy syntax because it doesn't seem to be a direction."; } $conversion-map: ( to top : bottom, to top right : bottom left, to right top : left bottom, to right : left, to bottom right : top left, to right bottom : left top, to bottom : top, to bottom left : top right, to left bottom : right top, to left : right, to left top : right bottom, to top left : bottom right ); @if map-has-key($conversion-map, $value) { @return map-get($conversion-map, $value); } @return 90deg - $value; } 

Примечание: на момент написания, LibSass 3 еще не поддерживает @error . Если вы хотите увеличить поддержку LibSass, смело заменяйте @error на @warn . В настоящее время я поддерживаю таблицу совместимости между различными версиями Sass (Ruby и LibSass)

Используй это

Хорошо! Мы закончили с кодом. Осталось только использовать наш миксин, чтобы убедиться, что он работает.

 .selector-1 { @include linear-gradient(#31B7D7, #EDAC7D); } .selector-2 { @include linear-gradient(to right, #E47D7D 0%, #C195D3 50%, #4FB4E8 100%); } .selector-3 { @include linear-gradient(42deg, #B58234 0%, #D2B545 50%, #D7C04D 50.01%, #FFFFFF 100%); } 
 .selector-1 { background: #31B7D7; background: -webkit-linear-gradient(-90deg, #31B7D7, #EDAC7D); background: linear-gradient(180deg, #31B7D7, #EDAC7D); } .selector-2 { background: #E47D7D; background: -webkit-linear-gradient(left, #E47D7D 0%, #C195D3 50%, #4FB4E8 100%); background: linear-gradient(to right, #E47D7D 0%, #C195D3 50%, #4FB4E8 100%); } .selector-3 { background: #B58234; background: -webkit-linear-gradient(48deg, #B58234 0%, #D2B545 50%, #D7C04D 50.01%, #FFFFFF 100%); background: linear-gradient(42deg, #B58234 0%, #D2B545 50%, #D7C04D 50.01%, #FFFFFF 100%); } 

Последние мысли

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