Разработка сайтов в Димитрове, ДНР. Скрипучие портреты: развлекаемся с функцией CSS path()

С выпуском Chrome 88 мы получили поддержку clip-path: path (). Это означает, что теперь он поддерживается «большинством» основных браузеров!

С помощью path () мы можем использовать определения пути для файла clip-path. (Вы догоняете то clip-path, что здесь). Эти строки определения пути такие же, как те, которые мы можем использовать с элементом пути SVG. Что в этом крутого, так это то, что он предоставляет способ создания фигур, которые раньше могли означать использование SVG. Мы даже можем создавать пути, которые ломаются, не требуя никаких уловок.

С усилением поддержки появилась возможность попробовать что-нибудь интересное! Давайте сделаем «Скрипучие портреты»! Это забавный подход clip-path: path () к вырезанию видимой области элемента в эти пятна в стиле Nickelodeon.

Создание пути

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

Чтобы сделать некоторые пути, мы можем использовать любой векторный графический редактор. В данном случае я использую Figma. И вместо того, чтобы создавать пути с нуля, мы можем использовать желаемую «точку» в качестве основы. Этот выглядит хорошо!

Пример Splat найден в Интернете

Пример Splat найден в Интернете

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

Три разных знака, построенных из одного знака

Три разных знака, построенных из одного знака

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

Но разве я не говорил, что им нужно постоянное количество очков? Они делают. И это то, что мы имеем здесь! Эти две капли появляются для каждого знака. Но хитрость в том, что мы можем переместить их за остальную часть пути, когда они не нужны.

Figma показывает две капли позади основного пути

Figma показывает две капли позади основного пути

После того, как у нас есть наши знаки, мы можем экспортировать их и получить строки определения пути:

Применение знаков

Чтобы применить знаки, мы создадим переменные для каждого пути:

.portrait {

—splat: «M161 188.375C170 193.5 177.919 193.854 186 188.375C197.919 180.294...»;

—splattier: «M161 188.375C170 193.5 177.919 193.854 186 188.375C197.919...»;

—splatted: «M232.5 256C225 251 209.5 262.5 224 281.5C232.736 292.948...»;

}

Это пути, которые мы вытащили прямо из экспортированного SVG.

Мы будем использовать названия «splat», «splattier» и «splatted». Называть вещи трудно. Ха! Но возьмем, к примеру, «разбрызганный» SVG:Мы извлекаем dатрибут из pathэлементов и создаем для них переменные CSS. Далее нам нужен элемент, к которому мы применим их. Создадим элемент с классом «портретЗатем примените к нему некоторые стили:.portrait

—splattier: «M161 188.375C170 193.5 177.919 193.854 186 188.375C197.919...»;

—splatted: «M232.5 256C225 251 209.5 262.5 224 281.5C232.736 292.948...»;

—none: «»;

height: 300px;

width: 300px;

background: #daa3f5;

clip-path: path (var (—clip, var (—none)));

transition: clip-path 0.2s;

}

И мы готовы идти! Вот демонстрация, в которой вы можете переключаться между различными состояниями клипа:

Обратите внимание, как форма переходит между тремя формами знака. Но также обратите внимание, как мы указали нашему элементу явную высоту и ширину. Этот размер соответствует размерам нашего экспорта SVG. Это важно. Это единственный недостаток использования clip-path: path (). Он не отвечает. Определение пути зависит от размеров вашего элемента. Это та же проблема, с которой сталкиваются траектории движения CSS.

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

Взаимодействие

Для нашей демонстрации мы хотим, чтобы знак был интерактивным. Мы можем сделать это только с помощью CSS. Мы можем использовать переменную CSS с ограниченной областью видимости — —clip— для управления текущим клипом. И тогда мы можем обновить эту переменную как для, так: hoverи для: active. Состояние —activeсрабатывает, когда мы нажимаем указатель вниз:

.portrait {

clip-path: path (var (—clip, var (—splat)));

}

.portrait: hover {

—clip: var (—splattier) ;

}

.portrait: active {

—clip: var (—splatted) ;

}

Сложите это вместе, и мы получим что-то вроде этого. Попробуйте навести курсор на значок и нажать на него:

Добавление персонажа

Теперь, когда мы можем переместить кляксу, нужно что-то еще. Что, если мы трансформируем его и в этих состояниях?

.portrait {

transition: clip-path 0.2s, transform 0.2s;

transform: scale (var (—scale, 1)) rotate (var (—rotate, 0deg));

}

.portrait: hover {

—scale: 1.15;

—rotate: 30deg;

}

.portrait: active {

—scale: 0.85;

—rotate: -10deg;

}

Используя переменные CSS с ограниченной областью действия для применения transform, мы можем что-то добавить. Здесь мы обновляем scaleи rotationнашего знака. Здесь мы можем экспериментировать с разными значениями и играть с разными эффектами. Небольшой перевод элемента может выглядеть хорошо?

Добавление портрета

Теперь самое интересное! Я бы не рекомендовал использовать эти мои фотографии. Но ты можешь, если хочешь, ха! У меня была идея сделать три глупых снимка самого себя и заставить их ответить пользователю. Я получил некоторую помощь и в итоге получил эти три картинки:

Три глупые позы

Три глупые позы

Затем нам нужно поместить их в портрет:

Это будет выглядеть не очень. Им нужны некоторые стили:

.portrait {

position: relative;

}

.portrait__img {

height: 100%;

width: 100%;

position: absolute;

top: 0;

left: 0;

}

Почти готово:

Как мы можем показать и скрыть их на: hoverи: active. Это немного многословно, но мы можем использовать nth-of-typewith display: none:

.portrait__img {

display: none;

}

.portrait__img: nth-of-type (1) {

display: block;

}

.portrait: hover.portrait__img: nth-of-type (1),

.portrait: hover.portrait__img: nth-of-type (3) {

display: none;

}

.portrait: hover.portrait__img: nth-of-type (2) {

display: block;

}

.portrait: active.portrait__img: nth-of-type (1),

.portrait: active.portrait__img: nth-of-type (2) {

display: none;

}

.portrait: active.portrait__img: nth-of-type (3) {

display: block;

}

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

Иконки параллакса

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

Значок с угловыми скобками вокруг косой черты.

Хитрость здесь заключается в том, чтобы использовать изображение в качестве фона для нашего элемента, но изменить его размер таким образом, чтобы он располагался в виде мозаики background-repeat:

.portrait {

background-image: url («/code-icon.svg») ;

background-color: hsl (10, 80%, 70%) ;

}

Аккуратный.

Но нам нужен параллакс! Чтобы получить этот эффект параллакса, мы можем обновить background-positionв ответ на движение указателя. И мы можем сопоставить положение указателя с некоторым пределом, который мы определяем.

Начнем с создания утилиты, которая генерирует для нас функцию сопоставления. Возвращаемая функция даст нам результат сопоставления значения в одном диапазоне с другим:

const genMapper = (inputLower, inputUpper, outputLower, outputUpper) => {

const inputRange = inputUpper — inputLower

const outputRange = outputUpper — outputLower

const MAP = input => outputLower + ( ((input — inputLower) / inputRange) * outputRange || 0)

return MAP

}

Найдите минутку, чтобы понять, что здесь происходит. Например, если наш входной диапазон был равен 0, 500а наш выходной диапазон был 0равен 100, каким будет результат вызова возвращаемой функции с 250? Было бы 50:

// Generate a function

genMapper (0, 500, 0, 100)

// Returns a function by going through these steps

const inputRange = 500

const outputRange = 100

const MAP => input => 0 + ( ((input — 0) / 500) * 100)

// If our input value is 250

(250 / 500) * 100

0.5 * 100

// The result!

50

Когда у нас есть служебная функция для генерации функций отображения, нам нужен предел для ее использования. И нам нужно сгенерировать маппер как для горизонтальной, так и для вертикальной осей:

const LIMIT = 25 // The amount our icons can move in pixels in either direction

const getX = genMapper (0, window.innerWidth, -LIMIT, LIMIT)

const getY = genMapper (0, window.innerHeight, -LIMIT, LIMIT)

Заключительная часть связывает это с прослушивателем событий. Мы деструктурируем значение xи yиз события и устанавливаем переменные CSS для портретного элемента. Значение происходит от передачи xи yв соответствующие функции отображения:

const PORTRAIT = document.querySelector ('.portrait’)

document.addEventListener ('pointermove’, ({ x, y }) => {

PORTRAIT.style.setProperty ('—x’, getX (x))

PORTRAIT.style.setProperty ('—y’, getY (y))

})

И теперь у нас есть значки параллакса!

Писк

Последний штрих. Это в названии. Нам нужны скрипы. Обычно я нахожу аудиобайты на таких сайтах, как freesound.org. Однако вы можете получить их в самых разных местах и ​​даже записать их самостоятельно, если хотите.

Неплохая идея создать объект, на который вы можете ссылаться Audio:

const AUDIO = {

IN: new Audio ('/squeak-in.mp3'),

OUT: new Audio ('/squeak-out.mp3'),

}

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

AUDIO.IN.play ()

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

Если пользователь быстро нажимает на портрет много раз подряд, это может привести к нежелательным эффектам. Хитрость заключается в том, чтобы воспроизвести нужный звук и в то же время остановить другой. Чтобы «остановить» фрагмент Audio, мы можем приостановить его и установить currentTimeзначение 0:

PORTRAIT.addEventListener ('pointerdown’, () => {

AUDIO.OUT.pause ()

AUDIO.IN.currentTime = AUDIO.OUT.currentTime = 0

AUDIO.IN.play ()

})

PORTRAIT.addEventListener ('pointerup’, () => {

AUDIO.IN.pause ()

AUDIO.IN.currentTime = AUDIO.OUT.currentTime = 0

AUDIO.OUT.play ()

})

И это дает нам «Скрипучий портрет»!

Это оно!

Вот как вы делаете «Скрипучие портреты». Но действенная вещь здесь — это развлекаться, пробуя новые вещи.

Я мог бы преобразовать пару фигур и оставить их там. Но зачем останавливаться на достигнутом? Почему бы не придумать идею и не повеселиться? Это отличный способ попробовать что-то и изучить методы.

Подводя итог, мы:

создал клипы

преобразовал их с помощью переходов

сделал интерактивные изображения

добавлено аудио

создал параллакс с помощью картографической утилиты

Что вы могли бы сделать с clip-path: path ()? Как бы выглядел ваш «писклявый портрет»? Это могло бы сделать что-то совершенно другое. Я хотел бы увидеть, что вы делаете!

Делитесь нашими материалами с друзьями!

 

 

Заказать разработку сайта