Анимация контейнера с изображением при наведении мыши с использованием перспективы и преобразования

Анимация контейнера с изображением при наведении мыши с использованием перспективы и преобразования

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

Вот окончательная версия:

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

Настройка

Во-первых, нам нужен контейнер с еще одним внутренним элементом. Контейнер поможет нам с перспективой.

Современные тенденции и подходы в веб-разработке

Узнайте алгоритм быстрого профессионального роста с нуля в сайтостроении

Узнать подробнее
<div id="container">
  <div id="inner"></div>
</div>

Для демонстрационных целей давайте поместим карточку точно по середине экрана:

body {
  /* Полная ширина и высота экрана */
  width: 100%;
  min-height: 100vh;
 
  /* Устанавливаем контейнер по центру экрана */
  display: flex;
  justify-content: center;
  align-items: center;
 
  margin: 0;
  background-color: rgb(220, 220, 220);
}

#container {
  /* Это вступает в игру позже */
  perspective: 40px;
}

#inner {
  width: 20em;
  height: 18em;
  background-color: white
}

Это дает нам белую карточку, расположенную прямо в центре светло-серого фона. Обратите внимание, что мы установили перспективу для #container на 40px, это пока ничего не делает, потому что мы не создали никаких преобразований. Это будет рассмотрено позже в разделе JavaScript.

Давайте начнем писать скрипты

Вот, что мы делаем:

var container = document.getElementById('container');
var inner = document.getElementById('inner');
 
var onMouseEnterHandler = function(event) {
  update(event);
};
var onMouseLeaveHandler = function() {
  inner.style = "";
};
var onMouseMoveHandler = function(event) {
  if (isTimeToUpdate()) {
 update(event);
  }
};

container.onmouseenter = onMouseEnterHandler;
container.onmouseleave = onMouseLeaveHandler;
container.onmousemove = onMouseMoveHandler;

И вот, что все эти вещи делают (или будут делать):

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

Функция обновления: мы еще не создали ее, но целью этой фуекции будет обновление 3D-вращения нашего #inner div.

Функция времени для обновления: это еще одна функция, которую мы еще не создали, но она возвращает значение true, когда потребуется обновление. Это способ уменьшить количество вызовов функции update() и повысить производительность скрипта.

Событие: это объект JavaScript, который описывает событие, которое произошло.

Вышеприведенный код:

Обновляет 3D-поворот #inner div, как только мышь входит в контейнер.

Обновляет 3D-поворот #inner div, когда наступит соответствующее время — когда мышь перемещается по контейнеру.

Сбрасывает стиль #inner div, когда мышь покидает контейнер.

Пришло время для обновления?

Давайте добавим функцию, которая решает, когда нужно обновить 3D-поворот div #inner.

var counter = 0;
var updateRate = 10;
var isTimeToUpdate = function() {
  return counter++ % updateRate === 0;
};

Когда counter достигнет updateRate, будет выполнено обновление. На этом этапе вы можете попробовать заменить функцию обновления на console.log() и поэкспериментировать с updateRate, чтобы увидеть, как все это работает.

Современные тенденции и подходы в веб-разработке

Узнайте алгоритм быстрого профессионального роста с нуля в сайтостроении

Узнать подробнее

Мышь

Далее нам нужен объект мыши. Это немного сложнее. Тем не менее, это не так сложно понять, но код может показаться пугающим, особенно если вы новичок в JavaScript.

// Init
var container = document.getElementById('container');
var inner = document.getElementById('inner');
// Mouse 
var mouse = {
  _x: 0,
  _y: 0,
  x: 0,
  y: 0,
  updatePosition: function(event) {
 var e = event || window.event;
 this.x = e.clientX - this._x;
 this.y = (e.clientY - this._y) * -1;
  },
  setOrigin: function(e) {
 this._x = e.offsetLeft + Math.floor(e.offsetWidth/2);
 this._y = e.offsetTop + Math.floor(e.offsetHeight/2);
  },
  show: function() { return '(' + this.x + ', ' + this.y + ')'; }
}
// Track the mouse position relative to the center of the container.
mouse.setOrigin(container);

Опять же, давайте разберем этот код:

show(): отображает текущую позицию мыши (если вы хотите выполнить некоторую отладку в консоли браузера).

setOrigin(e): Устанавливает координаты (0,0) для нашего объекта мыши в центре элемента (e).

updatePosition(): обновляет текущую позицию нашего объекта мыши относительно (0,0).

Последняя строка кода ouse.setOrigin(container) привязывает координаты (0,0) нашего объекта мыши к центру контейнера. Вот пример, который иллюстрирует это.

Идея состоит в том, чтобы добавить дополнительное вращения для #inner div, когда вы перемещаете мышь дальше от центра контейнера.

Обновляем стили для позиции мыши

Вот функция обновления:

var update = function(event) {
  mouse.updatePosition(event);
  updateTransformStyle(
 (mouse.y / inner.offsetHeight/2).toFixed(2),
 (mouse.x / inner.offsetWidth/2).toFixed(2)
  );
};

var updateTransformStyle = function(x, y) {
  var style = "rotateX(" + x + "deg) rotateY(" + y + "deg)";
  inner.style.transform = style;
  inner.style.webkitTransform = style;
  inner.style.mozTransform = style;
  inner.style.msTransform = style;
  inner.style.oTransform = style;
};

update(): обновляет положение мыши и стиль #inner div.

updateTransformStyle(): обновляет стиль для каждого вендорного префикса.

Мы закончили?

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

А, верно! Мы указали ему обновлять вращение #inner div каждый раз, когда счетчик достигает updateRate. Это создает неуклюжий переход между обновлениями. Как мы это решим? Переходы CSS.

Добавление переходов

#inner {
  transition: transform 0.5s;
}

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

Обратите внимание, что изменение размера страницы приведет к некоторым проблемам, так как изменяется позиция контейнера на странице. Решение состоит в том, чтобы повторно отцентрировать объект мыши в контейнере после изменения размера страницы.

Заключение

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

Автор: Mihai Ionescu

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

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

Современные тенденции и подходы в веб-разработке

Узнайте алгоритм быстрого профессионального роста с нуля в сайтостроении

Узнать подробнее

Курс по Flexbox

Изучите работу с Flexbox

Смотреть курс

Метки:

Похожие статьи:

Комментарии Вконтакте:

Комментарии Facebook:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Я не робот.

Spam Protection by WP-SpamFree