Конические градиенты в CSS3

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

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

В 2011 году, Lea Verou создала тему на форуме о реализации конического градиента средствами CSS и создала черновую спецификацию, которая была представлена на официальном сайте W3C как черновик. Однако, мы все еще ожидаем, когда W3C утвердит стандарт и браузеры начнут его поддерживать, что может занять определенное время. А тем временем, я покажу вам, как имитировать конический градиент, используя только средства CSS3.

На картинке выше показан пример конического градиента.

Чудесно, не правда ли? Давайте взглянем на код!

Начало

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

@mixin circle($size){
   content: "";
   position: absolute;
   border-radius: 50%;
   width: $size;
   height: $size;
   left: calc(50% - #{$size/2});
   top: calc(50% - #{$size/2});
}

@mixin circle используется только для установки свойств формы и расположения, создавая круг с абсолютным позиционированием, отцентрированный по горизонтали и вертикали относительно своего родительского контейнера.

Магия!

Комбинируя @mixin circle со свойством clip, мы можем получить полукруг. Давайте начнем с создания целого круга, соединив вместе два полукруга с различными цветами. Можете представить, что получится, если мы повернем один из полукругов? Магия!

$wheel: 15em; .color {
   @include circle($wheel);
   background: red;
   clip: rect(0, $wheel, $wheel, #{$wheel/2});
   &:after {
     @include circle($wheel);
     background: blue;
     clip: rect(0, #{$wheel/2}, $wheel, 0);
     transform: rotate(45deg);
   }
 }

Свойство clip: rect (top, right, bottom, left) ограничивает видимую область до прямоугольника, таким образом, что в приведенном выше примере будет видна только половина красного круга. Такой же принцип применяется и для голубого круга, с помощью селектора элемента .color:after.

На данном этапе у нас есть половина красного и половина синего круга. Однако, применение свойства transform означает, что голубой полукруг при повороте будет «налезать» на красный.

Смотрите пример.

Магия!

Цветной зонтик

Цветной зонтик

Мы уже знаем, как выполнить этот магический трюк. Давайте создадим 12-цветный зонтик:

<div class="wheel">
   <ul class="umbrella">
     <li class="color"></li>
     <li class="color"></li>
     <li class="color"></li>
     <li class="color"></li>
     <li class="color"></li>
     <li class="color"></li>
     <li class="color"></li>
     <li class="color"></li>
     <li class="color"></li>
     <li class="color"></li>
     <li class="color"></li>
     <li class="color"></li>
   </ul>
</div>

Так как мы хотим создать полный круг, составленный из полукругов, из семи элементов (первый элемент находится во второй половине), то мы должны реверсировать прямоугольные области:

.color, .color:nth-child(n+7):after {
   clip: rect(0, $wheel, $wheel, #{$wheel/2});
}
.color:after, .color:nth-child(n+7) {
   @include circle($wheel);
   clip: rect(0, #{$wheel/2}, $wheel, 0);
}

Начиная с седьмого элемента, .color становится полукругом в левой половине круга, а элементы .color:after переходят на правую половину круга.

Мы почти сделали это!! Нам нужно только изменить цвет и угол для каждого элемента. И вновь, давайте используем мощь Sass, чтобы сгенерировать 26193^42 строк кода с помощью 10 команд!

$colors: (#9ED110, #50B517, #179067, #476EAF, #9f49ac, #CC42A2, #FF3BA7, #FF5800, #FF8100, #FEAC00, #FFCC00, #EDE604); //зададим массив цветов
 @for $i from 0 to length($colors) { //цикл, последовательно перебирающий элементы зонтика
   .color:nth-child(#{1+$i}):after {
     background-color: nth($colors, $i+1);
     @if $i < 6 {
       transform: rotate(#{30*(1+$i)}deg);
       z-index: #{length($colors)-$i}; //управляем z-буфером для верного расположения элементов
     }
 @else {
       transform: rotate(#{-30+(30*(1+$i))}deg); //поворачиваем элементы
     }
   }
 }

Вначале мы определили массив $colors с «12 цветами радуги» и затем прошлись по всем элементам, создав селектор .color:nth-child(n):after и определив в нем свойства background-color, transform: rotate и z-index.

Свойство transform: rotate имеет несколько важных особенностей. Это угол поворота, который задан в соответствии с количеством цветов. В нашем случае, это 12 цветов, поэтому 360/12 = 30 таков угол поворота для каждого цвета. Но с седьмого элемента начинается новый полукруг, помните? По этой причине, процесс, описанный выше, останавливается на седьмом элементе.

Мы начнем этот процесс заново, но теперь уже в другом направлении. Вот почему присутствует условный оператор @else с командой rotate(#{-30+(30*($i+1))}deg), которая вычитает 30 градусов от седьмого элемента, который попадает на вторую половину круга.

Если вы внимательно наблюдали и хорошо понимаете CSS и SASS, то должны были заметить, что c нашим зонтиком что-то не так. Чтобы последний цвет из первой половины круга не налезал на цвета из второй, нам нужно реверсировать индекс этих элементов.

Например, z-index (6) = 1 нужно изменить на z-index (1) = 6.

Еще больше магии

Наконец, нам осталось сгладить переходы между цветами после их отрисовки, потому что мы хотим получить не зонтик, а конический градиент:

.umbrella {
  -webkit-filter: blur(1.7em);
}

.wheel {
  overflow: hidden;
  box-shadow: inset 0 0 0 3em rgba(0, 0, 0, 0.3);
}

Фильтр смазывание (blur) отвечает за размывание слоя, к которому он применен. Но, при его применении, цвета будут выходить за пределы своего элемента. По этой причине мы установили свойство overflow: hidden, которое добавлено к селектору .wheel.

Свойство box-shadow используется для затенения размытых граней. Вот так выглядит конечный результат.

Демо

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

РедакцияПеревод статьи «Conical Gradients in CSS3»