Рисование изображений с помощью CSS-градиентов

Рисование изображений с помощью CSS-градиентов

От автора: под «изображениями CSS» я имею в виду изображения, созданные с использованием только HTML-элементов и CSS. Они выглядят так, как если бы они были SVG, нарисованные в Adobe Illustrator, но они были сделаны прямо в браузере. Некоторые из тех методов, которые я видел, используются возиться с пограничными радиусами, тенями блоков, а иногда и с clip-path. Вы можете найти множество замечательных примеров, если вы будете искать ежедневные изображения css на CodePen.

Я нарисовал некоторые из них, включая этот Infinity Gauntlet, но в одном элементе с только фоном и минимальным использованием других свойств. Давайте посмотрим, как вы можете сами создавать изображения, используя градиент CSS.

Метод

Понимание синтаксиса сокращенного background а также того, как работают градиенты CSS — это практически все, что вам нужно, чтобы нарисовать что-либо в одном элементе. В качестве обзора приведены следующие аргументы:

background: <'background-color'> || <image> || <position> [ / <size> ]? || <repeat> || <attachment> || <origin> || <clip>;

Они могут встречаться в любом порядке, за исключением того, что между position и size должно быть /. Мы должны сохранить эти два аргумента в этом порядке, иначе мы получим неожиданные результаты. Не все они должны быть включены, и для этой цели мы не будем использовать аргументы color, repeat, attachment, origin или clip. Это оставляет нам image, size и position. Однако, поскольку фоны повторяются по умолчанию, мы должны установить background-repeat: no-repeat; прямо под всем background (если некоторые фоны должны быть повторены, мы можем использовать repeating-linear-gradient() и repeating-radial-gradient()). В этом случае скелет CSS будет следующим:

.image { background: <image> <position> / <size>; background-repeat: no-repeat;
}

Мы даже можем использовать несколько наборов фоновых аргументов! Поэтому мы можем складывать и разделять их запятыми следующим образом:

.image { background: <image> <position> / <size>, <image> <position> / <size>, <image> <position> / <size>; background-repeat: no-repeat;
}

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

.circles { background: radial-gradient(7em 7em at 35% 35%, red 50%, transparent 50%), radial-gradient(7em 7em at 50% 50%, gold 50%, transparent 50%), radial-gradient(7em 7em at 65% 65%, blue 50%, transparent 50%); background-repeat: no-repeat; width: 240px; height: 240px;
}

Рисование изображений с помощью CSS-градиентов

Рисование

Мы будем использовать Sass (SCSS) для рисования этих изображений, чтобы мы могли использовать переменные для цветовой палитры. Это сделает код короче, легче читается и изменяет затемненные или более легкие варианты цветов. Вместо этого мы могли бы использовать переменные в обычном CSS и забыть Sass, но из-за отсутствия поддержки Internet Explorer, давайте придерживаться Sass. Чтобы объяснить, как это работает, мы будем экспериментировать с фигурами, используя как линейные, так и радиальные градиенты.

Настройка цветовой палитры

Наша палитра будет состоять из цветов RGB или HSL. Я объясню позже, почему сохранить цвета в любом из этих форматов. В этом примере мы будем использовать RGB.

$r: rgb(255,0,0); // hsl(0,100%,50%)
$o: rgb(255,128,0); // hsl(32,100%,50%)

Что мне нравится делать, чтобы код был коротким и легким для чтения, используйте как минимум одну букву для представления каждого цвета (например, $r для красного). Если вы используете более темные или более светлые оттенки одного цвета, я добавляю d перед базовой буквой или буквами для темного или l для света. Я бы использовал $dr для темно-красного и $lr для светло-красного. Если есть потребность в более чем двух других оттенках, я добавляю число в конце, чтобы указать уровень тени. Например, $dr1 для темно-красного, $dr2 для более темного красного и $lr1 для светло-красного, $lr2 $lr1 для светло-красного. Такая палитра будет выглядеть так (с темными сначала, нормальными и последними)

$dr1: rgb(224,0,0);
$dr2: rgb(192,0,0);
$r: rgb(255,0,0);
$lr1: rgb(255,48,48);
$lr2: rgb(255,92,92);

Настройка масштаба и холста

Мы будем использовать em единицы для размеров изображения, чтобы изображение можно было легко изменить пропорционально. Так как 1em равно размеру шрифта элемента, каждая единица изображения будет соответствующим образом скорректирована, если изменится. Давайте установим размер шрифта 10px и установим ширину и высоту 24em. Единицы 10px легче всего думать, потому что если вы мысленно выполните математику, вы сразу получите 240 × 240 пикселей. Затем, чтобы увидеть, где находятся края холста, мы будем использовать серию 1px grey.

$r: rgb(255,0,0); // hsl(0,100%,50%)
$o: rgb(255,128,0); // hsl(32,100%,50%) .image { background-repeat: no-repeat; font-size: 10px; outline: 1px solid #aaa; width: 24em; height: 24em;
}

Однако помните об использовании меньших размеров шрифта; у браузеров минимальная настройка размера шрифта (по причинам доступности). Если вы установите размер шрифта 4px, а минимальный — 6px, он будет принудительно установлен на 6px.

Кроме того, вы можете включить отзывчивость, просто используя единицы calc() и viewport. Возможно, мы сможем использовать что-то вроде calc(10px + 2vmin) если calc(10px + 2vmin) , но давайте придерживаться 10px.

Рисование фигур

Здесь начинается интересная часть. Чтобы нарисовать квадрат размером 8 × 8 мкм в центре, мы используем linear-gradient() с двумя одноцветными остановками.

.image { background: linear-gradient($r, $r) 50% 50% / 8em 8em; ...
}

Рисование изображений с помощью CSS-градиентов

Чтобы превратить его в нечто более похожее на трапецию, установите угол 60 градусов. В то же время добавим $T для transparent нашей палитры, а затем разместим обе стопы для $r и $T на 63% (прямо перед тем, как нижний правый угол обрезается).

$T: transparent; .image { background: linear-gradient(60deg,$r 63%, $T 63%) 50% 50% / 8em 8em; ...
}

Рисование изображений с помощью CSS-градиентов

Установка обоих остановок с одним и тем же значением делает наклонную сторону такой же четкой, как и остальные. Если вы посмотрите на это более близко, но, похоже, сторона пикселирована:

Рисование изображений с помощью CSS-градиентов

Чтобы исправить это, мы слегка корректируем одну из стопов (на 1% или примерно так), чтобы край был достаточно гладким. Итак, давайте изменим $r на 63% до 62%.

Это будет проблемой с круглыми краями, а также при работе с радиальными градиентами, которые мы увидим позже. Если вы просматриваете это в браузере, отличном от Safari, все выглядит великолепно даже при переходе на непрозрачный цвет (скажем, оранжевый). Проблема перехода на transparent в Safari заключается в том, что вы заметите немного черной подкладки на наклонной стороне.

Рисование изображений с помощью CSS-градиентов

Это связано с тем, что transparent ключевое слово в Safari всегда является черной прозрачностью, и в результате мы видим черный. Я действительно хочу, чтобы Apple исправила это, но они никогда не будут. В настоящее время добавим новую переменную $redT для прозрачности красного цвета под $r. Отбросьте $T мы использовали для transparent поскольку мы больше не будем его использовать.

$rT: rgba(255,0,0,0); // hsla(0,100%,50%,0)

Затем заменим transparent на $redT. Это позаботится о нашей проблеме Safari!

.image { background: linear-gradient(60deg,$r 62%, $rT 63%) 50% 50% / 8em 8em; ...
}

Рисование изображений с помощью CSS-градиентов

Если вам интересно, почему мы не использовали шестнадцатеричные цвета, Internet Explorer и Edge не поддерживают нотации #rgba и #rrggbbaa (ага, hex имеет альфа-канал с конца 2016 года, если вы никогда не знали), и мы хотим, чтобы это работало как кросс-браузер, насколько это возможно. Мы также хотим оставаться в соответствии с нашим выбором цветового формата.

Теперь давайте переместим форму вертикально на 20% и нарисуем оранжевый круг тех же размеров. Кроме того, добавьте еще одну переменную для своей прозрачной версии. Для гладкого края вставьте 1%-ный зазор между твердым и прозрачным апельсинами.

$oT: rgba(255,128,0,0); // hsla(32,100%,50%,0) .image { background: linear-gradient(60deg,$r 62%, $rT 63%) 50% 20% / 8em 8em, radial-gradient(8em 8em at 50% 80%, $o 49%, $oT 50%); ...
}

Рисование изображений с помощью CSS-градиентов

Чтобы поддерживать согласованность с нашим размером, вторая остановка цвета должна составлять 50% вместо 100%.

Позиционирующие фигуры

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

.image { background: linear-gradient($r, $r) 24em 20% / 8em 8em, linear-gradient($o, $o) 100% 80% / 8em 8em; ...
}

Рисование изображений с помощью CSS-градиентов

Красный квадрат заканчивается полностью на холсте (очерчен), а правая сторона оранжевого квадрата касается другой стороны. Использование фиксированных единиц — это как размещение абсолютно позиционированных элементов или рисования фигур в холсте HTML5. В этом смысле верно, что точка происхождения находится в левом верхнем углу. При использовании процентов и заданного размера фона, div получает «поддельное заполнение» половины размера фона. В то же время точка происхождения фона центрирована (не путать с background-origin, что касается углов блока).

Рисование изображений с помощью CSS-градиентов

Теперь, если мы превратили эти градиенты в радиальные градиенты в виде кругов и применили одни и те же позиции x 24 и 100%, оба оказались на другой стороне пополам. Это связано с тем, что точка происхождения всегда находится в центре, если мы пишем фон так:

.image { background: radial-gradient(8em 8em at 24em 20%, $r 49%, $rT 50%), radial-gradient(8em 8em at 100% 80%, $o 49%, $oT 50%); ...
}

Рисование изображений с помощью CSS-градиентов

Если мы перепишем фон, чтобы положение и размер были после градиента и использовались на 100% 100% at center, они будут расположены как линейные градиенты. Красная выходит наружу, а оранжевая — к правому краю. «Поддельное заполнение» происходит еще раз оранжевым цветом.

.image { background: radial-gradient(100% 100% at center, $r 49%, $rT 50%) 24em 20% / 8em 8em, radial-gradient(100% 100% at center, $o 49%, $oT 50%) 100% 80% / 8em 8em; ...
}

Рисование изображений с помощью CSS-градиентов

Нет единого правильного способа позиционирования фигур, но для размещения его как абсолютно или фиксированного позиционного элемента HTML используйте фиксированные единицы. Если вам нужен быстрый способ разместить фигуру (используя параметры position / size) в мертвой position / size оптимальным вариантом будет 50%, так как начало координат будет его центром. Используйте 100%, если он должен касаться самой правой стороны.

Калибровочные фигуры

Размер в CSS-фонах работает так, как мы ожидали, но на него все еще влияет тип устройства, используемого для фиксированных позиций или процентов. Если мы снова возьмем наши квадраты и изменим их ширину на 10em, красный будет расширяться вправо, а оранжевый будет расширяться в сторону.

.image { background: linear-gradient($r, $r) 12em 20% / 10em 8em, linear-gradient($o, $o) 50% 80% / 10em 8em; ...
}

Рисование изображений с помощью CSS-градиентов

Если мы использовали em единицы для y-позиции, форма будет расти вниз или сжиматься вверх после изменения высоты. Если мы будем использовать процент, то он будет расширяться как по вертикали. Некоторое время назад мы рассмотрели два способа рисования кругов с радиальными градиентами. Первый способ — указать ширину и высоту между ( и at и затем положением после этого:

.image { background: radial-gradient(8em 8em at 50% 50%, $r 49%, $rT 50%); ...
}

Второй способ — использовать 100% 100% в центре, а затем дать положение и размер:

.image { background: radial-gradient(100% 100% at 50% 50%, $r 49%, $rT 50%) 50% 50% / 8em 8em; ...
}

Эти методы рисуют круги, но приводят к различным результатам, потому что:

Первый способ занимает весь div, так как не было реального фонового положения или размера.

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

Предположим, что мы заменили $rT на $o. Вы увидите, что оранжевый будет покрывать то, что было белым или фигур под ним (если мы добавили какие-либо) для первого пути. Используя второй способ, вы легко заметите рамку, открытую оранжевым.

Рисование изображений с помощью CSS-градиентов

Кроме того, цель 100% 100% вместо использования circle или ellipse — позволить кругу занимать всю ограничительную рамку. Это даже дает нам полный контроль над его размерами. Таким образом, он останется таким же, если вы измените 50% 50% позицию на что-то еще. Если используется одно из двух ключевых слов, край круга останавливается только около 71% пути при центрировании и становится более искаженным, если его положение отрегулировано. Например, вот что происходит, когда мы меняем положение x на 0 для circle и ellipse:

Рисование изображений с помощью CSS-градиентов

В конечном итоге вы можете пересмотреть синтаксис как radial-gradient(width height at xy) или radial-gradient(100% 100% at x-in-bounding-box y-in-bounding-box) xy / width height. Если вы рисуете только круг или овал, вы можете упростить код с первого взгляда. Если вы рисуете часть круга или часть кольца, тогда вступает в игру второй способ. В примерах, которые мы создадим дальше, будет много применений.

Примеры

Готовы сейчас нарисовать что-то реальное? Мы будем проходить три примера шаг за шагом. Первые два будут статическими — одно с большим количеством полукругов, а другое — с закругленными прямоугольниками. Последний пример будет меньше, но сфокусирован на анимации.

Статическое изображение

Этот зонтик будет нашим первым статическим изображением:

Рисование изображений с помощью CSS-градиентов

Мы будем использовать палитру с красным ($r и $rT), белым ($w и $wT), оранжевым ($o и $oT) и темно-оранжевым ($do и $doT).

$r: rgb(255,40,40);
$rT: rgba(255,40,40,0); $w: rgb(240,240,240);
$wT: rgba(240,240,240,0); $o: rgb(255,180,70);
$oT: rgba(255,180,70,0); $do: rgb(232,144,0);
$doT: rgba(232,144,0,0);

Настроем область рисования размером 30 × 29em.

.parasol { // background to go here background-repeat: no-repeat; font-size: 10px; outline: 1px solid #aaa; width: 30em; height: 29em;
}

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

.parasol { background: // 1 radial-gradient(200% 200% at 100% 100%, $do 49%, $doT 50%) 14em 0 / 1em 1em, radial-gradient(200% 200% at 0% 100%, $o 49%, $oT 50%) 15em 0 / 1em 1em, // 2 linear-gradient(90deg, $do 50%, $o 50%) 14em 1em / 2em 25em, // 3 radial-gradient(100% 200% at 50% 0, $oT 0.95em, $o 1em, $o 1.95em, $do 2em, $do 2.95em, $doT 3em) 14em 26em / 6em 3em, // 4 radial-gradient(200% 200% at 100% 100%, $o 49%, $oT 50%) 18em 25em / 1em 1em, radial-gradient(200% 200% at 0% 100%, $do 49%, $doT 50%) 19em 25em / 1em 1em; ...
}

Рисование изображений с помощью CSS-градиентов

Чтобы нарисовать каждую сторону верха полюса, мы использовали четверти круга, которые 1 × 1em. Чтобы они занимали свои ограничивающие прямоугольники, мы использовали круги, которые в два раза больше (200% 200%), расположенные внизу справа и внизу слева. Мы могли бы также использовать пары ключевых слов, например, right bottom или left bottom, но использовать процентные эквиваленты короче. Обратите внимание на 1% зазоры между упорами, чтобы обеспечить гладкость.

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

Эта часть полюса немного сложнее, чем другие, потому что мы должны поддерживать 2-й диаметр. Чтобы нарисовать эту дугу, мы используем поле 6 × 3em, так что между концами есть 2em-пространство, которое также равно 2em. Затем мы используем радиальный градиент в центре сверху, где каждый останов происходит каждый раз (и распространяется на 0.05em для гладкости).

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

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

.parasol { background: radial-gradient(100% 200% at 50% 100%, $r 50%, $rT 50.25%) 50% 1.5em / 9em 12em, radial-gradient(100% 200% at 50% 100%, $w 50%, $wT 50.25%) 50% 1.5em / 21em 12em, radial-gradient(100% 200% at 50% 100%, $r 50%, $rT 50.25%) 50% 1.5em / 30em 12em, ...
}

Рисование изображений с помощью CSS-градиентов

Чтобы нарисовать половину кругов, составляющих эту часть, мы использовали размер градиента 100% 200%, который заставляет каждый диаметр вписываться в его фоновую ширину, но в два раза больше высоты и центрируется внизу. Заказывая их сверху вниз, чтобы наибольший был внизу и наименьший сверху, мы получаем нужные нам кривые.

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

.parasol { background: /* top */ radial-gradient(100% 200% at 50% 100%, $r 50%, $rT 50.25%) 50% 1.5em / 9em 12em, radial-gradient(100% 200% at 50% 100%, $w 50%, $wT 50.25%) 50% 1.5em / 21em 12em, radial-gradient(100% 200% at 50% 100%, $r 50%, $rT 50.25%) 50% 1.5em / 30em 12em, /* pole */ radial-gradient(200% 200% at 100% 100%, $do 49%, $doT 50%) 14em 0 / 1em 1em, radial-gradient(200% 200% at 0% 100%, $o 49%, $oT 50%) 15em 0 / 1em 1em, linear-gradient(90deg, $do 50%, $o 50%) 14em 1em / 2em 25em, radial-gradient(100% 200% at 50% 0, $oT 0.95em, $o 1em, $o 1.95em, $do 2em, $do 2.95em, $doT 3em) 14em 26em / 6em 3em, radial-gradient(200% 200% at 100% 100%, $o 49%, $oT 50%) 18em 25em / 1em 1em, radial-gradient(200% 200% at 0% 100%, $do 49%, $doT 50%) 19em 25em / 1em 1em; ...
}

Затем, между вершиной и полюсом, мы добавим следующий фрагмент фона, чтобы отобразить концы. Чтобы определить ширину каждого сегмента, мы должны получить расстояние между каждой точкой, где встречаются красный и белый. Все они должны составлять до 30 em.

Рисование изображений с помощью CSS-градиентов

Начиная с белых и самых узких красных полукругов, мы вычитаем ширину красного 9 eм от ширины белого 21 em и разделим результат на 2, чтобы получить ширину двух белых сегментов (точка «b» на рисунке). Таким образом, результат будет равен 6em (b = (21 — 9) / 2 = 6). Тогда средний красный сегмент будет 9em (21 — (6 + 6) = 9). Теперь мы оставили внешние красные сегменты (точка «а» на рисунке). Вычтите сумму того, что у нас есть сейчас, из ширины большей красной половины круга и разделите этот результат на 2. Это будет делать значение точки a: (30em — (6 + 6 + 9)) / 2 = 4.5em.

.parasol { background: ... /* pointy ends */ radial-gradient() 0 13.5em / 4.5em 3em, radial-gradient() 4.5em 13.5em / 6em 3em, radial-gradient() 50% 13.5em / 9em 3em, radial-gradient() 19.5em 13.5em / 6em 3em, radial-gradient() 25.5em 13.5em / 4.5em 3em, ...
}

Чтобы нарисовать полукруги, похожие на то, как мы нарисовали верхнюю часть, начинаем с прозрачной копии цвета для каждой формы, чтобы они напоминали дуговые мосты. Мы также добавим дополнительную 5% к каждой ширине градиента (не ширину окна фона), чтобы каждая точка, образованная смежными фонами, не была слишком резкой и тонкой.

.parasol { background: ... /* pointy ends */ radial-gradient(105% 200% at 50% 100%, $rT 49%, $r 50%) 0 13.5em / 4.5em 3em, radial-gradient(105% 200% at 50% 100%, $wT 49%, $w 50%) 4.5em 13.5em / 6em 3em, radial-gradient(105% 200% at 50% 100%, $rT 49%, $r 50%) 50% 13.5em / 9em 3em, radial-gradient(105% 200% at 50% 100%, $wT 49%, $w 50%) 19.5em 13.5em / 6em 3em, radial-gradient(105% 200% at 50% 100%, $rT 49%, $r 50%) 25.5em 13.5em / 4.5em 3em, ...
}

Рисование изображений с помощью CSS-градиентов

Наконец, вам больше не понадобится эта 1px solid #aaa контур 1px solid #aaa. Наш зонтик завершен!

Что-то с закругленными прямоугольниками

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

Рисование изображений с помощью CSS-градиентов

Палитра будет состоять из черного ($bk и $bkT) для края домашней кнопки, темно-серого ($dg и $dgT) для тела, серого ($g и $gT) для камеры и динамика, светло-серого ($lg и $lgT) для внешней границы, синий ($bl и $blT) для объектива камеры и очень темный фиолетовый ($p и $pT) для экрана.

.parasol { background: ... /* pointy ends */ radial-gradient(105% 200% at 50% 100%, $rT 49%, $r 50%) 0 13.5em / 4.5em 3em, radial-gradient(105% 200% at 50% 100%, $wT 49%, $w 50%) 4.5em 13.5em / 6em 3em, radial-gradient(105% 200% at 50% 100%, $rT 49%, $r 50%) 50% 13.5em / 9em 3em, radial-gradient(105% 200% at 50% 100%, $wT 49%, $w 50%) 19.5em 13.5em / 6em 3em, radial-gradient(105% 200% at 50% 100%, $rT 49%, $r 50%) 25.5em 13.5em / 4.5em 3em, ...
}

Давайте создадим наш холст размером 20 × 40em и будем использовать тот же размер шрифта, который мы использовали для зонтика, 10 пикселей:

.iphone { // background goes here background-repeat: no-repeat; font-size: 10px; outline: 1px solid #aaa; width: 20em; height: 40em;
}

Прежде чем мы начнем рисовать наш первый округленный прямоугольник, нам нужно подумать о нашем пограничном радиусе, который будет 2em. Кроме того, мы хотим оставить некоторое пространство слева для переключателей блокировки и кнопок регулировки громкости, что будет 0,25 em. По этой причине прямоугольник будет равен 19,75 × 40 мкм. Учитывая 2-кратный радиус границы, нам понадобятся два линейных градиента, пересекающих друг друга. Нужно иметь ширину 15.75em (19.75em — 2 × 2), а другая должна иметь высоту 36em (40em — 2 × 2). Поместите первый 2.25em слева, а затем второй 0.25em слева и 2em сверху.

.iphone { background: /* body */ linear-gradient() 2.25em 0 / 15.75em 40em, linear-gradient() 0.25em 2em / 19.75em 36em; ...
}

Поскольку светло-серая граница будет иметь толщину 0,5 em, давайте сделаем каждую градиентную остановку немедленно переключенной с светло-серого ($lg) на темно-серый ($dg) и наоборот на 0.5em и 0.5em до конца (40em — 0.5 = 39.5 em для первого градиента, 19.75em — 0.5 = 19.25em для второго). Установите угол 90 градусов для второго, чтобы он стал горизонтальным.

.iphone { background: /* body */ linear-gradient($lg 0.5em, $dg 0.5em, $dg 39.5em, $lg 39.5em) 2.25em 0 / 15.75em 40em, linear-gradient(90deg, $lg 0.5em, $dg 0.5em, $dg 19.25em, $lg 19.25em) 0.25em 2em / 19.75em 36em; ...
}

Рисование изображений с помощью CSS-градиентов

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

.iphone { background: /* corners */ radial-gradient(200% 200% at 100% 100%, $dg 1.45em, $lg 1.5em, $lg 50%, $lgT 51%) 0.25em 0 / 2em 2em, radial-gradient(200% 200% at 0% 100%, $dg 1.45em, $lg 1.5em, $lg 50%, $lgT 51%) 18em 0 / 2em 2em, radial-gradient(200% 200% at 100% 0%, $dg 1.45em, $lg 1.5em, $lg 50%, $lgT 51%) 0.25em 38em / 2em 2em, radial-gradient(200% 200% at 0% 0%, $dg 1.45em, $lg 1.5em, $lg 50%, $lgT 51%) 18em 38em / 2em 2em, ...
}

Рисование изображений с помощью CSS-градиентов

Чтобы получить светло-серые концы толщиной 0,5 em, подумайте о том, где начинается градиент, а затем выполните вычисления. Поскольку светло-серый находится в конце, мы вычитаем 0.5em из 2em, чтобы правильно разместить первую остановку. Для гладкости мы берем небольшой бит с первого 1.5em и добавляем 1% к второму 50%, чтобы круглые края сливались с плоскими краями.

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

Рисование изображений с помощью CSS-градиентов

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

.iphone { background: /* body */ linear-gradient($lg 0.5em, $dg 0.55em, $dg 39.5em, $lg 39.55em) 2.25em 0 / 15.75em 40em, linear-gradient(90deg, $lg 0.5em, $dg 0.55em, $dg 19.175em, $lg 19.25em) 0.25em 2em / 19.75em 36em; ...
}

Затем в одном линейном градиенте мы добавим кнопки блокировки и кнопки регулировки громкости, чтобы заполнить пространство 0,25 eм слева. Если между кнопками и телом произойдет 1px-пространство, мы можем добавить крошечное кровоточение от 0,05 em к ширине фона (что делает его 0,3), чтобы он не торчал в темно-серый цвет.

.iphone { background: /* volume buttons */ linear-gradient($lgT 5em, $lg 5em, $lg 7.5em, $lgT 7.5em, $lgT 9.5em, $lg 9.5em, $lg 11em, $lgT 11em, $lgT 13em, $lg 13em, $lg 14.5em, $lgT 14.5em) 0 0 / 0.3em 100%, ...
}

Рисование изображений с помощью CSS-градиентов

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

Затем добавим край кнопки дома, а также плоские края квадрата внутри него. Теперь квадрат внутри домашней кнопки будет 1.5 × 1.5em и будет следовать в основном той же процедуре, что и тело: два пересекающихся линейных градиента и радиальные поля для заполнения углов. Чтобы разместить их по горизонтали в центре, calc() пригодится. 50% + 0.125em будет выражением; если бы мы сосредоточили только тело телефона, на каждой стороне будет 0.125 м пробелов. Поэтому мы перемещаем его на 0.125 метра справа. Такое же x-позиционирование будет применяться к верхним двум фонам.

.iphone { background: /* home button */ linear-gradient() calc(50% + 0.125em) 36.5em / 0.5em 1.5em, linear-gradient() calc(50% + 0.125em) 37em / 1.5em 0.5em, radial-gradient(3em 3em at calc(50% + 0.125em) 37.25em, $bkT 1.25em, $bk 1.3em, $bk 49%, $bkT 50%), ...
}

Подобно тому, как мы заштриховали линейные градиентные части тела телефона, остановки начнутся и заканчиваются светло-серым, но с прозрачным посередине. Обратите внимание, что мы оставили промежутки между 0,05% между каждыми переходами от серого к прозрачному (и наоборот). Так же, как и углы тела, это обеспечит смесь между круглым углом и плоским концом внутри.

.iphone { background: /* home button */ linear-gradient($lg 0.15em, $lgT 0.2em, $lgT 1.35em, $lg 1.35em) calc(50% + 0.125em) 36.5em / 0.5em 1.5em, linear-gradient(90deg, $lg 0.15em, $lgT 0.2em, $lgT 1.3em, $lg 1.35em) calc(50% + 0.125em) 37em / 1.5em 0.5em, radial-gradient(3em 3em at calc(50% + 0.125em) 37.25em, $bkT 1.25em, $bk 1.3em, $bk 49%, $bkT 50%), ...
}

Рисование изображений с помощью CSS-градиентов

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

Теперь, чтобы получить углы серого квадрата точно там, где они должны быть, давайте сначала сосредоточимся на x-позиции. Мы начинаем с calc(50% + 0.125em) , затем добавляем или вычитаем ширину каждой части, или я должен calc(50% + 0.125em) радиус границы квадрата. Эти фоны будут выше трех последних.

.iphone { background: /* home button */ radial-gradient(200% 200% at 100% 100%, $lgT 0.3em, $lg 0.35em, $lg 0.48em, $lgT 0.5em) calc(50% + 0.125em - 0.5em) 36.5em / 0.5em 0.5em, radial-gradient(200% 200% at 0% 100%, $lgT 0.3em, $lg 0.35em, $lg 0.48em, $lgT 0.5em) calc(50% + 0.125em + 0.5em) 36.5em / 0.5em 0.5em, radial-gradient(200% 200% at 100% 0%, $lgT 0.3em, $lg 0.35em, $lg 0.48em, $lgT 0.5em) calc(50% + 0.125em - 0.5em) 37.5em / 0.5em 0.5em, radial-gradient(200% 200% at 0% 0%, $lgT 0.3em, $lg 0.35em, $lg 0.48em, $lgT 0.5em) calc(50% + 0.125em + 0.5em) 37.5em / 0.5em 0.5em, ...
}

Рисование изображений с помощью CSS-градиентов

Затем экран будет прямоугольником 17.25 × 30. Так же, как и части кнопки дома, мы будем горизонтально calc(50% + 0.125em) его с помощью calc(50% + 0.125em). Сверху это будет 5em.

.iphone { background: /* screen */ linear-gradient($p, $p) calc(50% + 0.125em) 5em / 17.25em 30em, ...
}

Рисование изображений с помощью CSS-градиентов

Наконец, мы добавим камеру и динамик. Камера представляет собой простой 1 × 1 сине-серый радиальный без каких-либо причудливых вычислений. Чисто-серый динамик, хотя будет немного больше задействован. Он будет прямоугольником размером 5 × 1 em и имеет радиус границы 0,5 eм. Чтобы нарисовать это, мы сначала рисуем прямоугольник с первыми четырьмя точками ширины и центрируем его с помощью calc(50% + 0.125em) . Затем мы используем 0,5 × 1 eм половину окружности, в которых градиентные позиции составляют 100% 50% и 0% 50%. Лучший способ разместить эти левые и правые прямоугольники — использовать некоторые новые выражения calc(). Для левой части мы вычитаем половину ширины прямоугольника и половину ширины полукруга из центра тела (50% + 0.125em — 2em — 0.25em). Право будет следовать по той же схеме, но с добавлением, поэтому 50% + 0.125em + 2em + 0.25em.

.iphone { background: /* camera */ radial-gradient(1em 1em at 6.25em 2.5em, $bl 0.2em, $g 0.21em, $g 49%, $gT 50%), /* speaker */ radial-gradient(200% 100% at 100% 50%, $g 49%, $gT 50%) calc(50% + 0.125em - 2em - 0.25em) 2em / 0.5em 1em, radial-gradient(200% 100% at 0% 50%, $g 49%, $gT 50%) calc(50% + 0.125em + 2em + 0.25em) 2em / 0.5em 1em, linear-gradient($g, $g) calc(50% + 0.125em) 2em / 4em 1em, ...
}

Рисование изображений с помощью CSS-градиентов

Удалите серый контур вокруг div, и iPhone завершен!

Анимированные изображения

Возможно, вы думаете, что можете использовать background-position чтобы анимировать эти виды изображений, но вы можете сделать так много. Например, невозможно самостоятельно одушевить вращение отдельного фона. Фактически, анимация background-position обычно не выполняется, а также transform анимацию, поэтому я не рекомендую ее.

Чтобы анимировать любую часть изображения любым желаемым способом, мы можем разрешить :before или :after псевдоэлементов отвечать за эту часть. Если нам нужно больше выбора, мы можем вернуться к нескольким дочерним div, но не нуждаемся в них для каждой мелочи. Для нашего примера анимированного изображения мы создадим этот анимированный радар:

Рисование изображений с помощью CSS-градиентов

Сначала мы рисуем статическую часть, это все, кроме серой рамки и вращающейся руки. До этого давайте дадим нашу палитру (примечание: нам не понадобится $dgnT для $dgn ) и базовый код.

$gn: rgb(0,192,0);
$gnT: rgba(0,192,0,0);
$dgn: rgb(0,48,0);
$gy: rgb(128,128,128);
$gyT: rgba(128,128,128,0);
$bk: rgb(0,0,0);
$bkT: rgba(0,0,0,0); .radar { background-repeat: no-repeat; font-size: 10px; outline: 1px solid #aaa; width: 20em; height: 20em;
}

Поскольку этот образ будет полностью круглым, мы можем безопасно применить радиус границы 50%. Затем мы можем использовать повторяющийся радиальный градиент, чтобы нарисовать кольца — примерно на 1/3 пути друг от друга.

.radar { background: /* rings */ repeating-radial-gradient($dgn, $dgn 2.96em, $gn 3em, $gn 3.26em, $dgn 3.3em); background-repeat: no-repeat; border-radius: 50%; ...
}

Рисование изображений с помощью CSS-градиентов

Также обратите внимание на дополнительные $dgn в начале. Для повторения градиентов для начала, конца и цикла, как и ожидалось, нам нужно указать начальный цвет в 0 (или без 0).

В отличие от предыдущего примера, мы не используем calc() для центрирования строк, потому что Internet Explorer будет делать все это неловко, когда мы позже используем псевдоэлемент. Чтобы нарисовать четыре линии 0.4em, которые пересекают друг друга в центре, знайте, что половина линии должна быть равна половине div в 10em. Итак, мы вычитаем и добавляем половину 0,4 (0,4 / 2 = 0,2) с каждой стороны. Другими словами, левая часть зеленого цвета должна быть 9,8 em, а правая — 10,2 em. Однако для диагоналей 45deg мы должны умножить 10em на квадратный корень из 2, чтобы получить их центр (10 × √2 ≈ 14.14). Это длина самой длинной стороны правого треугольника 10 eм. В результате стороны каждой диагонали будут примерно равны 13,94 и 14,34 em.

.radar { background: /* lines */ linear-gradient($gnT 9.8em, $gn 9.8em, $gn 10.2em, $gnT 10.2em), linear-gradient(45deg,$gnT 13.94em, $gn 13.98em, $gn 14.3em, $gnT 14.34em), linear-gradient(90deg,$gnT 9.8em, $gn 9.8em, $gn 10.2em, $gnT 10.2em), linear-gradient(-45deg,$gnT 13.94em, $gn 13.98em, $gn 14.3em, $gnT 14.34em), ...
}

Рисование изображений с помощью CSS-градиентов

Чтобы предотвратить пикселизацию диагоналей, мы оставили крошечный разрыв 0,04 em между зеленым и прозрачным зеленым цветом. Затем, чтобы создать некоторое освещение, добавьте этот прозрачный-чёрный радиальный градиент:

.radar { background: /* lighting */ radial-gradient(100% 100%, $bkT, $bk 9.9em,$bkT 10em), ...
}

Рисование изображений с помощью CSS-градиентов

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

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

.radar { ... position: relative; &:before { background-repeat: no-repeat; border-radius: 50%; content: ""; position: absolute; width: 100%; height: 100%; }
}

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

.radar { ... &:before { animation: scan 5s linear infinite; background: /* frame */ radial-gradient($gyT 9.20em, $gy 9.25em, $gy 10em, $gyT 10.05em), /* hand */ linear-gradient(45deg, $gnT 6em, $gn) 0 0 / 50% 50%; ... }
} @keyframes scan { from { transform: rotate(0); } to { transform: rotate(1turn); }
}

Теперь наш маленький гаджет завершен!

Преимущества (плюс недостаток)

Такой подход рисования изображений CSS имеет ряд преимуществ. Во-первых, HTML будет очень легким по сравнению с растрированным файлом изображения. Во-вторых, это отлично подходит для обработки изображений, которые невозможно рисовать хорошо, не используя экспериментальные свойства и API, которые могут быть широко не поддерживаться.

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

Вывод

Вкратце, способ рисования изображений CSS, которые мы рассмотрели в этой статье, позволяет нам:

Настраивать палитру, состоящую из переменных для цветов.

Отключать повтор фона, устанавливать масштаб с font-size и ширину и высоту холста в em единицах для целевого элемента.

Использовать временное outline, чтобы показать края, когда мы работаем.

Рисовать каждую фигуру снизу вверх, потому что фоны отображаются в этом порядке. Ниже приведен background синтаксис для каждой фигуры image position / size(с или без позиции и размера).

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

Автор: Jon Kantner

Источник: https://css-tricks.com/

Редакция: Команда webformyself.