Всем доброго времени суток.
Хочу поделиться одной наработкой с использованием 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.: Код вставлял с готового решения, поэтому названия переменных могут резать глаз. С орфографией, пунктуацией и прочим сами знаете куда.
Автор: hermit931