От автора: недавно один из моих учеников спросил меня, можно ли создать элемент на экране, который можно вращать в любую сторону при помощи мыши или касаний. На первом семестре я рассказываю только о HTML5 и CSS, поэтому ответ был «нет, без JavaScript нельзя». Но в этом решении всего пара строк JS, и в нем очень интересно используются CSS переменные.
Объекты в пространстве
Разметка демо состоит всего из одного элемента:
1 |
<img src="dasha.jpg" srcset="dasha-2x.jpg 2x" alt> |
(Вы можете поместить на странице сколь угодно много элементов, я же оставил всего один для простоты и ясности).
Тегу body заданы свойства margin: 0 и min-height: 100vh. Для центрирования элементов на странице используется flexbox:
1 2 3 4 5 6 7 8 9 10 |
body { min-height: 100vh; display: flex; justify-content: center; align-items: center; perspective: 60vw; margin: 0; --mouseX: 0deg; --mouseY: 0deg; } |
Кроме того, была задана CSS 3D перспектива, а также две CSS переменные. Переменные используются для стилизации изображения:
1 2 3 4 5 6 |
img { width: 80vmin; height: 80vmin; transform: rotateX(calc(var(--mouseY))) rotateY(calc(var(--mouseX))); } |
Обратите внимание, что, так как мы используем больше одной переменной в свойстве transform, их необходимо обернуть в функцию calc(), чтобы не было ошибок синтаксиса. В ближайшее время, когда свойства rotateX и Y станут нативными свойствами CSS, использовать функцию calc() будет необязательно.
У изображения должны быть заданы высота и ширина, иначе flexbox растянет его.
Отслеживание позиции
Код JS начинается с нахождения изображения:
1 |
const img = document.getElementsByTagName("img")[0]; |
Обычно CSS переменные задаются в CSS и используются внутри стилей, но их можно задавать и через JS при помощи setProperty. Я сделал это в функции, которая берет текущую позицию указателя мыши, определяет высоту и ширину окна браузера (делит их пополам), после чего на основе этой информации определяется правильный угол наклона изображения:
1 2 3 4 5 6 |
function sway(xPos, yPos) { let wh = window.innerHeight / 2, ww = window.innerWidth / 2; document.body.style.setProperty("--mouseX", (xPos - ww) / 25+"deg"); document.body.style.setProperty("--mouseY", (yPos - wh) / 25+"deg"); } |
Функция инициируется как движением мыши, так и касанием:
1 2 3 4 5 6 7 8 9 10 11 |
document.addEventListener("mousemove", function(e) { sway(e.clientX,e.clientY); }) document.addEventListener("touchmove", function(e) { e.preventDefault(); var touch = e.targetTouches[0]; if (touch) { sway(touch.pageX, touch.pageY); } }); |
Обратите внимание, что значения в переменных поменяны местами: движение по оси Х поворачивает изображение по оси У и наоборот.
Сила переменных
Как отметила Лея Вероу в своей последней презентации на конференции по CSS, почти универсальная поддержка CSS переменных на сегодняшний день позволяет стилям вернуться к их главенствующей роли – к представлению. JS же может занять свою традиционную роль поведения. Кроме того, CSS переменные создают бесшовную связь между CSS и JS.
Если вам нужна поддержка в MS Edge и IE (и если вы хотите обойти текущие ограничения в Firefox), функцию можно было бы написать на JS:
1 2 3 |
function sway(xPos, yPos) { img.style.transform = "rotateX("+(yPos - wh) / 25+"deg) rotateY("+(xPos - ww) / 25 +"deg)"; } |
Помимо исходного кода я еще создал CodePen демо к этому уроку.
Источник: //thenewcode.com/
Редакция: Команда webformyself.