SCSS и кросплатформенный градиент (ну почти)

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

Я никогда не мог запомнить как правильно записывать правила для кроссбраузерного градиента, поэтому всегда гуглю онлайн сервисы (например этот www.colorzilla.com/gradient-editor). Сразу при загрузке мы получаем код для градиента:

background: #1e5799; /* Old browsers */
background: -moz-linear-gradient(left, #1e5799 0%, #2989d8 50%, #207cca 51%, #7db9e8 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, right top, color-stop(0%,#1e5799), color-stop(50%,#2989d8), color-stop(51%,#207cca), color-stop(100%,#7db9e8)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(left, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(left, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(left, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* IE10+ */
background: linear-gradient(to right, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#1e5799', endColorstr='#7db9e8',GradientType=1 ); /* IE6-9 */


Забегая наперёд, скажу сразу filter: для ИЕ, и -webkit-gradient для Safari4+ пришлось упустить, из-за невозможности реализовать (ну или я не нашел способа реализации). Поэтому в заголовке красуется «почти». Из вышесказаного у нас получится как то так:

background: #1e5799; /* Old browsers */
background: -moz-linear-gradient(left, #1e5799 0%, #2989d8 50%, #207cca 51%, #7db9e8 100%); /* FF3.6+ */
background: -webkit-linear-gradient(left, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(left, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(left, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* IE10+ */
background: linear-gradient(to right, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* W3C */


Вот это я и реализировал, в результате чего нужно задать для градиента «массив» из цвета и позиции, и на выходе получим правила, описанные выше. Собственно сам массив:

$gradientOptions: rgba(225,225,225,0) 0%, rgba(225,225,225,1) 10%, rgba(225,225,225,1) 90%, rgba(225,225,225,0) 100%;  
@include linearGradient(#fff, $gradientOptions , left);


Подробно изучив (методом проб и ошибок) структуру записи выше, можно выделить 2 повторяющиеся части:

background: -*-linear-gradient(left, #1e5799 0%, #2989d8 50%, #207cca 51%, #7db9e8 100%);


и

#1e5799 0%, #2989d8 50%, #207cca 51%, #7db9e8 100%


Для стоки «background: linear-gradient(to right, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%);» потом сделаем исключение, у нее все равно строка задания цвета повторяется.
Ниже функция для вывода общего кода:

$browsersPrefix: moz o webkit ms;
@mixin linearGradient($oldColor, $gradientList, $direction) {
	background: $oldColor;
	$directionRevers:null; 
	@if $direction == left {
		$directionRevers: right;
	}
	@else if $direction == right {
		$directionRevers: left;
	}
	@else if $direction == top {
		$directionRevers: bottom;
	}
	@else if $direction == bottom {
		$directionRevers: top;
	}
	@include buildGradientLine($gradientList); 
	@each $prefix in $browsersPrefix {
		background:-#{$prefix}-linear-gradient($direction, $resultLine);
	}
	background: linear-gradient(to $directionRevers, $resultLine);
}


Небольшое обьяснение: переменная $directionRevers нужна как раз для правила по W3C стандарту, где направление указывается к какой стороне идет градиент, в отличие от браузерных решений, у которых указано откуда начинается направление. Ах да, в коде возможны всего 4ре направления, но кому хочется более гибкого решения, нарастить код несложно. @each производит перебор по ранее указанных в переменной $browsersPrefix префиксах и выводит почти нужный код.

Остались упущенными строка @include buildGradientLine($gradientList) и переменная $resultLine. Строка @include buildGradientLine($gradientList) как раз и формирует «цветовую строку», а переменная $resultLine ее содержит:

$resultLine:null;
@mixin buildGradientLine($gradientList) {
	$resultLine:null;
	@for $i from 1 through length($gradientList) {
      $colors: nth($gradientList, $i);
			$color: nth($colors, 1);
			$position: nth($colors, 2);
			
      $resultLine: $resultLine $color $position;
      @if $i != length($gradientList) {
			$resultLine: $resultLine#{','}
      }
  }
}


Для начала объявляем как глобальную переменную $resultLine:null, а далее логика понятна для рядового программиста (должно быть понятно и для студента, хотя, всякое бывает). Кстати с этой частью кода у меня была проблема. Вместо цикла я использовал обычный @each, в результате чего у меня получалось то же самое, с разницей в том, что в строке, в конце, присутствовала последняя запятая, с которой градиент не захотел отображаться. Решение с циклом @for я подсмотрел тут. Кому интересно что это за хитрая часть кода:

$colors: nth($gradientList, $i);
	$color: nth($colors, 1);
	$position: nth($colors, 2);


объясняю: $colors: nth($gradientList, $i); выбирает нужную пару значений в цикле из всего массива, а $color: nth($colors, 1); $position: nth($colors, 2) запись в переменные цвета и позиции соответственно.

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

P.S.: Код вставлял с готового решения, поэтому названия переменных могут резать глаз. С орфографией, пунктуацией и прочим сами знаете куда.
Поделиться публикацией
Ой, у вас баннер убежал!

Ну. И что?
Реклама
Комментарии 9
  • 0
    Посмотрите реализацию Gradient в Stylus Nib
    Мне кажется она сделана довольно интересно, как впрочем и сам nib
    • 0
      мне нужно было на SCSS, а это кажется не то
      • 0
        Я не говорю про то, что это SCSS — я говорю про реализацию. Может она наведет на какую то интересную идею. Кстати в Compass есть михин градиента с color-stop, но там довольно просто это реализовано.
        • 0
          До компаса еще не дорос :), но уже подумываю и на него подсаживаться
    • 0
      -ms- градиенту не нужен: IE до 9 включительно не поддерживает градиент вообще, а 10-й — поддерживает без префикса.
      • 0
        в принципе да, не задумался об этом, был сосредоточен на реализации. Ну и префиксы я использую не только для вывода градиента, а и для других эффектов
        • 0
          IE9 поддерживает градиенты, но придется использовать SVG.
        • +1
          Если используете Sass, то почему не используете Compass? Там есть своя годная реализация compass-style.org/reference/compass/css3/images/
          Для ie используется или filter, или svg.
          Можете посмотреть код на githab для расчета filter.
          • 0
            да я не спорю что она плоха, или моя лучше. Мне нужно было для SCSS, без компаса, ну не использую пока что его, а решение нужно было сейчас. Да и при поиске гугл ничего по этому не выдал (плохо искал наверное). Если бы напоролся на это решение сразу, возможно им бы и воспользовался.

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

          Самое читаемое