Zoom для карточки товара

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

sneakers under the magnifying glass

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

Black Panther Figure

В этой статье я расскажу, как сделать похожий эффект и использовать его в своих дальнейших проектах. Рассмотрим три составные части: HTML, CSS, Javascript.

HTML

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

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

<div class="container">
  <div class="preview">
    <img src="item.jpg" data-zoom-img="item3x.jpg" alt="item">
  </div>
  <div class="zoom">
  </div>
</div>

CSS

Тут тоже всё просто, совсем немного стилей. Укажите размер для обёртки zoom. Присвойте обёртке overflow: hidden, теперь любой контент, выходящий за её границы, будет скрыт.

.container {
  position: relative;
}
.preview img {
  width: 400px;
  cursor: pointer;
}
.zoom {
  width: 400px;
  height: 400px;
  overflow: hidden;
  position: absolute;
  top: 60px;
  right: -460px;
  pointer-events: none;
}
.zoom img {
  position: absolute;
}

Любой CSS пример на Frontext предполагает то, что у вас уже подключены Normalize.css и Autoprefixer. Не забывайте об этом.

Изучив CSS код, вы наверное уже поняли, как это работает: мы будем ловить события мыши на превью и перемещать увеличенное изображение товара внутри обёртки.

Schema

Javascript

А вот тут уже будет посложнее. Выполним работу в несколько этапов:

Инициализация

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

const preview = document.querySelector(".preview img"),
  zoom = document.querySelector(".zoom");

const zoomHandler = () => {
  // Doing things  
}

const zoomInit = () => {
  const zoomImg = document.createElement("img");
  zoomImg.src = preview.dataset.zoomImg;
  zoomImg.alt = preview.alt;
  zoom.append(zoomImg);
  document.addEventListener("mousemove", zoomHandler);
};

preview.addEventListener("mouseenter", zoomInit);

Обратите внимание на то, что был создан новый элемент, где src это значение, указанное в data-атрибуте ранее. Так мы реализовали ленивую загрузку увеличенного изображения.

Уничтожение

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

const zoomDestroy = () => {
  const zoomImg = document.querySelector(".zoom img");
  zoomImg.remove();
  document.removeEventListener("mousemove", zoomHandler);
};

preview.addEventListener("mouseleave", zoomDestroy);

Обработчик

Немного вычислений:

  1. Для начала нужно отслеживать движение курсора. Для этого есть event.clientX и event.clientY. Но ведь необходимы значения только в пределах области превью, а значит, от event.clientX и event.clientY мы будем вычитать расстояние от левого и верхнего края окна браузера соответственно.
  2. Не хотелось бы перемещать увеличенное изображение дальше его фактического размера, поэтому найдём максимальные пределы перемещения для осей x и y. Для этого надо вычесть ширину и высоту обёртки из ширины и высоты изображения.
  3. Если показатель движения курсора меньше допустимых пределов, то присвоим необходимый инлайн стиль. Обработчик готов.
const zoomHandler = (event) => {
  const zoomImg = document.querySelector(".zoom img"),
    maxX = zoomImg.offsetWidth - zoom.offsetWidth,
    maxY = zoomImg.offsetHeight - zoom.offsetHeight,
    curX = event.clientX - preview.getBoundingClientRect().left,
    curY = event.clientY - preview.getBoundingClientRect().top,
    x = curX < maxX ? curX : maxX,
    y = curY < maxY ? curY : maxY;
  zoomImg.style = `left: -${x}px; top: -${y}px;`;
};

Три этапа соединяем в один скрипт, и можно сказать, что наша работа закончена. Zoom готов!

const preview = document.querySelector(".preview img"),
  zoom = document.querySelector(".zoom");

const zoomHandler = (event) => {
  const zoomImg = document.querySelector(".zoom img"),
    maxX = zoomImg.offsetWidth - zoom.offsetWidth,
    maxY = zoomImg.offsetHeight - zoom.offsetHeight,
    curX = event.clientX - preview.getBoundingClientRect().left,
    curY = event.clientY - preview.getBoundingClientRect().top,
    x = curX < maxX ? curX : maxX,
    y = curY < maxY ? curY : maxY;
  zoomImg.style = `left: -${x}px; top: -${y}px;`;
};

const zoomInit = () => {
  const zoomImg = document.createElement("img");
  zoomImg.src = preview.dataset.zoomImg;
  zoomImg.alt = preview.alt;
  zoom.append(zoomImg);
  document.addEventListener("mousemove", zoomHandler);
};

const zoomDestroy = () => {
  const zoomImg = document.querySelector(".zoom img");
  zoomImg.remove();
  document.removeEventListener("mousemove", zoomHandler);
};

preview.addEventListener("mouseenter", zoomInit);
preview.addEventListener("mouseleave", zoomDestroy);

Итог

У меня получился такой вот классный зум-эффект.

Codepen

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

На этом всё. Надеемся, вы узнали что-то новое и сможете применить полученные знания в своих проектах. Спасибо, что читаете нас, подписывайтесь и получайте новые статьи о фронтенде от Frontext.

Наши рекомендации
К сожалению, тут пока ничего нет.