ZorNet.Ru — сайт для вебмастера » JavaScript и jQuery » Красивый адаптивный слайдер в 3D формате

Красивый адаптивный слайдер в 3D формате

Красивый адаптивный слайдер в 3D формате
Оригинально выполнен по своим характеристикам адаптированный слайдер, который идет в формате 3D, где при наведении курсора происходят эффекты. Данный слайдер отлично адаптивен под все мобильные устройства, это от самого большого просмотра, до малого экрана мобильного гаджет. На всех приборах будет корректно отображается, что для мобильного пользователя это просто большой плюс. Где также можно самостоятельно переводить снимке, но по умолчанию встроен автоматический перевод.

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

Переменные:

--z-distance - отвечает за данную дистанцию оси Z от фона до слайдера;
--from-left - идет первым кадром;
--mobile-bkp - самая большая ширина браузера, где автоматически слайдер будет переходить в мобильный режим просмотра (данное значение нужно также установить в строке @media only screen and (max-width: 650px);

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

Адаптивный слайдер с использованием чистого JS

Установка:

HTML

Код
<div class="posmutagan" id="posmutagan">  
  <div class="perevovas-kaganku" id="perevovas-kaganku">
  <div class="ankasuges-img">
  <div class="ankasuges-img-item ankasuges-img-item-active" data-id="1"><img src="http://zornet.ru/_fr/56/6531099.jpg"/></div>
  <div class="ankasuges-img-item" data-id="2"><img src="http://zornet.ru/_fr/56/s3410582.jpg"/></div>
  <div class="ankasuges-img-item" data-id="3"><img src="http://zornet.ru/_fr/56/s7319179.jpg"/></div>
  <div class="ankasuges-img-item" data-id="4"><img src="http://zornet.ru/_fr/56/s7545559.jpg"/></div>
  <div class="ankasuges-img-item" data-id="5"><img src="http://zornet.ru/_fr/56/s3179532.jpg"/></div>
  <div class="ankasuges-img-item" data-id="6"><img src="http://zornet.ru/_fr/56/s4931948.jpg"/></div>
  </div>
  <div class="ankasuges-text">
  <div class="ankasuges-text-item ankasuges-text-item-active" data-id="1">
  <div class="ankasuges-text-item-head">
  <h3>Первый</h3>
  </div>
  <div class="ankasuges-text-item-info">
  <p>Здесь идет описание</p>
  </div>
  </div>
  <div class="ankasuges-text-item" data-id="2">
  <div class="ankasuges-text-item-head">
  <h3>Второй</h3>
  </div>
  <div class="ankasuges-text-item-info">
  <p>Второе описание</p>
  </div>
  </div>
  <div class="ankasuges-text-item" data-id="3">
  <div class="ankasuges-text-item-head">
  <h3>Продвижение</h3>
  </div>
  <div class="ankasuges-text-item-info">
  <p>Скрипты сайта</p>
  </div>
  </div>
  <div class="ankasuges-text-item" data-id="4">
  <div class="ankasuges-text-item-head">
  <h3>Коды для портала</h3>
  </div>
  <div class="ankasuges-text-item-info">
  <p>Установка стилистики</p>
  </div>
  </div>
  <div class="ankasuges-text-item" data-id="5">
  <div class="ankasuges-text-item-head">
  <h3>Дизайн сайта</h3>
  </div>
  <div class="ankasuges-text-item-info"></div>
  </div>
  <div class="ankasuges-text-item" data-id="6">
  <div class="ankasuges-text-item-head"></div>
  <div class="ankasuges-text-item-info">
  <p>Оформление</p>  
  </div>
  </div>  
  </div>
  </div>
  <div class="slider__nav">
  <div class="slayden-akosmo-arrows">
  <div class="slayden-akosmo-arrow slayden-akosmo-arrow-left" id="left">Лево</div>
  <div class="slayden-akosmo-arrow slayden-akosmo-arrow-right" id="right">Право</div>
  </div>
  <div class="slayden-akosmo-dots" id="slayden-akosmo-dots">
  <div class="slayden-akosmo-dot slayden-akosmo-dot-active" data-id="1"></div>
  <div class="slayden-akosmo-dot" data-id="2"></div>
  <div class="slayden-akosmo-dot" data-id="3"></div>
  <div class="slayden-akosmo-dot" data-id="4"></div>
  <div class="slayden-akosmo-dot" data-id="5"></div>
  <div class="slayden-akosmo-dot" data-id="6"></div>
  </div>
  </div>
</div>

CSS

Код
:root {
  --z-distance: 150px;
  --from-left: 1;
  --mobile-bkp: 650px;
  --slider-height: 600px;
}
.posmutagan *,  
.posmutagan *::before,  
.posmutagan *::after {
  box-sizing: border-box;
}
.posmutagan {
  width: 100%;
  margin: 20px 0;
  height: var(--slider-height);
  display: flex;
  perspective: 1000px;
  transform-style: preserve-3d;
  position: relative;  
}
.posmutagan::before,  
.posmutagan::after {
  content: '';
  left: 0;
  top: 0;
  display: block;
  position: absolute;
  width: 100%;
  height: var(--slider-height);
  background-position: center;
  background-size: cover;
  will-change: opacity;
  z-index: -1;
  box-shadow: 0 0 0 50vmax rgba(0, 0, 0, 0.3) inset;
}
.posmutagan::before {
  background-image: var(--img-prev);
}
.posmutagan::after {
  transition: opacity 0.7s;
  opacity: 0;
  background-image: var(--img-next);
}
.slider--bg-next::after {
  opacity: 1;
}
.perevovas-kaganku {
  margin: auto;
  width: 65%;
  height: 65%;
  will-change: transform;
  transform-style: preserve-3d;
  pointer-events: none;
  transform: translateZ(var(--z-distance));
}
.ankasuges-img {
  overflow: hidden;
  position: absolute;
  width: 100%;
  height: calc(100% - 50px);
  z-index: 0;
  box-shadow: 0 0 30px #000;
}
.ankasuges-img-item {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  will-change: transform;
  transition-timing-function: ease-in;
  visibility: hidden;
}
.ankasuges-img-item img {
  display: block;
  position: relative;
  left: -30px;
  top: -30px;
  width: calc(100% + 60px);
  max-width: calc(100% + 60px);
  height: calc(100% + 60px);
  object-fit: cover;
  will-change: transform;
}
.ankasuges-img-item-active {
  z-index: 20;
  visibility: visible;
}
.ankasuges-img-item-subactive {
  z-index: 15;
  visibility: visible;
}
.ankasuges-img-item-next {
  transform: translateX(100%);
}
.ankasuges-img-item-prev {
  transform: translateX(-100%);
}
.ankasuges-img-item-transit {
  transition: transform 0.7s, opacity 0.7s;
}
.ankasuges-text {
  position: relative;
  height: 100%;
}
.ankasuges-text-item {
  position: absolute;
  width: 100%;
  height: 100%;
  padding: 10px;
  perspective: 1000px;
  transform-style: preserve-3d;
}
.ankasuges-text-item > * {
  overflow: hidden;
  position: absolute;
}
.ankasuges-text-item h3,  
.ankasuges-text-item p {
  transition: transform 0.35s ease-out;
  overflow: hidden;
  padding: 10px 20px;
  margin: 0;
  font-family: 'Roboto Condensed', sans-serif;
  font-weight: normal;
  text-align: center;
}
.ankasuges-text-item h3 {
  background-color: rgba(191, 226, 255, 0.9);
  font-size: 30px;
  text-transform: uppercase;
  color: #000;
  position: relative;
  transform: translateX(-100%);  
}
.ankasuges-text-item p {
  color: #FFF;
  font-size: 20px;
  background-color: rgba(51, 122, 183, 0.9);
  transform: translateX(100%);
}
.ankasuges-text-item h3::before,  
.ankasuges-text-item p::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  transform: translateX(0);
  transition: transform 0.35s ease-out 0.28s;
}
.ankasuges-text-item-head {
  top: -10px;
  left: -10px;
  transform: translateZ(20px);
}
.ankasuges-text-item-info {
  bottom: 40px;
  right: 0;
  max-width: 75%;
  min-width: min-content;
  transform: translateZ(20px);
}
.ankasuges-text-item-active h3,  
.ankasuges-text-item-active p {
  transform: translateX(0);
}
.ankasuges-text-item-active h3::before {
  transform: translateX(102%);
}
.ankasuges-text-item-active p::before {
  transform: translateX(-102%);
}
.ankasuges-text-item-backwards h3::before,  
.ankasuges-text-item-backwards p::before {
  transition: transform 0.35s ease-in;
}
.ankasuges-text-item-backwards h3,  
.ankasuges-text-item-backwards p {
  transition: transform 0.35s ease-in 0.35s;
}
.slider__nav {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: var(--slider-height);
  text-align: center;
}
.slayden-akosmo-arrows {
  display: flex;
  justify-content: space-between;
  width: 100%;
  position: absolute;
  top: 0;
  left: 0;
  height: var(--slider-height);
}
.slayden-akosmo-arrow {
  height: calc(var(--slider-height) - 100px);
  width: 50vw;
  text-indent: -9999px;
  white-space: nowrap;
}
.slayden-akosmo-arrow-left {
  --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='60' height='60' viewBox='0 0 4 4'%3E %3Cpolyline points='3 1 1 2 3 3' stroke='white' stroke-width='.6' stroke-opacity='.6' fill='none'%3E%3C/polyline%3E %3C/svg%3E");
  cursor: var(--arrow) 30 30, auto;
}
.slayden-akosmo-arrow-right {
  --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='60' height='60' viewBox='0 0 4 4'%3E %3Cpolyline points='1 1 3 2 1 3' stroke='white' stroke-width='.6' stroke-opacity='.6' fill='none'%3E%3C/polyline%3E %3C/svg%3E");
  cursor: var(--arrow) 30 30, auto;
}
.slayden-akosmo-dots {
  top: calc(var(--slider-height) - 80px);
  display: inline-flex;
  position: relative;
  padding: 12px;
  pointer-events: none;
}
.slayden-akosmo-dots::before {
  content: '';
  position: absolute;
  left: 22px;
  top: 12px;
  width: 20px;
  height: 20px;
  background-color: rgba(51, 122, 183, 0.9);
  transition: transform 0.7s ease-out;
  transform: translateX(calc(40px * (var(--from-left) - 1)));
}
.slayden-akosmo-dot {
  margin: 0 10px;
  width: 20px;
  height: 20px;
  border: 2px solid rgba(191, 226, 255, 0.9);
  cursor: pointer;
  pointer-events: all;
  display: inline-block;
  transition: border-color 0.3s ease-out;
}
.slayden-akosmo-dot:hover {
  border-color: rgba(255, 255, 255, 1);
}
.slayden-akosmo-dot:active {
  border-color: rgba(255, 255, 255, 1);
}
@media only screen and (max-width: 650px) {
  .slider::before,
  .slider::after {
  display: none;
  }
  .perevovas-kaganku {
  width: 100%;
  height: var(--slider-height);
  transform: translateZ(0);
  }
  .ankasuges-img {
  height: 100%;
  box-shadow: none;
  }  
  .ankasuges-text-item-info {
  bottom: 116px;
  left: 50%;
  transform: translate(-50%, 0);
  }
  .ankasuges-text-item-info p {
  padding: 20px;
  }
  .ankasuges-text-item-head {
  top: 40px;
  left: 40px;
  transform: translateZ(0);
  }
  .ankasuges-text-item-head h3 {
  font-size: 26px;
  }
  .slayden-akosmo-dots {
  background-color: rgba(0, 0, 0, 0.3);
  }
  .slayden-akosmo-arrow {
  width: 10%;
  position: relative;
  cursor: auto;
  height: var(--slider-height);
  }
  .slayden-akosmo-arrow::before {
  content: '';
  background-image: var(--arrow);
  background-size: cover;
  width: 40px;
  height: 40px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  }
  .slayden-akosmo-arrow-left {
  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.7) 0, transparent 100%);
  }
  .slayden-akosmo-arrow-left:active {
  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.9) 0, transparent 100%);
  }
  .slayden-akosmo-arrow-right {
  background-image: linear-gradient(to left, rgba(0, 0, 0, 0.7) 0, transparent 100%);
  }
  .slayden-akosmo-arrow-right:active {
  background-image: linear-gradient(to left, rgba(0, 0, 0, 0.9) 0, transparent 100%);
  }
  /* Фикс для ресайза */  
  .perevovas-kaganku,
  .ankasuges-img-item img {
  transform: none!important;
  }  
}

JS

Код
function lerp({ x, y }, { x: targetX, y: targetY }) {
  const fraction = 0.1;  
  x += (targetX - x) * fraction;
  y += (targetY - y) * fraction;
  return { x, y };
}
class Slider {
  constructor (el) {
  const imgClass = this.IMG_CLASS = 'ankasuges-img-item';
  const textClass = this.TEXT_CLASS = 'ankasuges-text-item';
  const activeImgClass = this.ACTIVE_IMG_CLASS = `${imgClass}-active`;
  const activeTextClass = this.ACTIVE_TEXT_CLASS = `${textClass}-active`;
  this.el = el;
  this.contentE0 = document.getElementById('posmutagan');
  this.contentEl = document.getElementById('perevovas-kaganku');
  this.onMouseMove = this.onMouseMove.bind(this);
  this.activeImg = el.getElementsByClassName(activeImgClass);
  this.activeText = el.getElementsByClassName(activeTextClass);
  this.images = el.getElementsByTagName('img');
  document.getElementById('slayden-akosmo-dots').addEventListener('click', this.onDotClick.bind(this));
  document.getElementById('left').addEventListener('click', this.prev.bind(this));
  document.getElementById('right').addEventListener('click', this.next.bind(this));
  window.addEventListener('resize', this.onResize.bind(this));
  this.onResize();
  this.length = this.images.length;
  this.lastX = this.lastY = this.targetX = this.targetY = 0;
  }
  onResize () {
  const htmlStyles = getComputedStyle(document.documentElement);
  const mobileBreakpoint = htmlStyles.getPropertyValue('--mobile-bkp');
  const isMobile = this.isMobile = matchMedia(`only screen and (max-width: ${mobileBreakpoint})`).matches;
  this.halfWidth = this.contentE0.offsetWidth / 2;
  this.halfHeight = this.contentE0.offsetHeight / 2;
  this.zDistance = htmlStyles.getPropertyValue('--z-distance');
  if (!isMobile && !this.mouseWatched) {
  this.mouseWatched = true;
  this.el.addEventListener('mousemove', this.onMouseMove);
  this.el.style.setProperty(
  '--img-prev',  
  `url(${this.images[+this.activeImg[0].dataset.id - 1].src})`
  );
  this.contentEl.style.setProperty('transform', `translateZ(${this.zDistance})`);
  } else if (isMobile && this.mouseWatched) {
  this.mouseWatched = false;
  this.el.removeEventListener('mousemove', this.onMouseMove);
  this.contentEl.style.setProperty('transform', 'none');
  }
  }
  getMouseCoefficients ({ clientX, clientY } = {}) {
  const halfWidth = this.halfWidth;
  const halfHeight = this.halfHeight;
  const xCoeff = ((clientX || this.targetX) - halfWidth) / halfWidth;
  const yCoeff = (halfHeight - (clientY || this.targetY)) / halfHeight;
  return { xCoeff, yCoeff }
  }
  onMouseMove ({ clientX, clientY }) {  
  this.targetX = clientX - this.contentE0.getBoundingClientRect().left;
  this.targetY = clientY - this.contentE0.getBoundingClientRect().top;
  if (!this.animationRunning) {
  this.animationRunning = true;
  this.runAnimation();
  }
  }
  runAnimation () {
  if (this.animationStopped) {
  this.animationRunning = false;
  return;
  }
  const maxX = 10;
  const maxY = 10;
  const newPos = lerp({
  x: this.lastX,
  y: this.lastY
  }, {
  x: this.targetX,
  y: this.targetY
  });
  const { xCoeff, yCoeff } = this.getMouseCoefficients({
  clientX: newPos.x,  
  clientY: newPos.y
  });  
  this.lastX = newPos.x;
  this.lastY = newPos.y;
  this.positionImage({ xCoeff, yCoeff });  
  this.contentEl.style.setProperty('transform', `
  translateZ(${this.zDistance})
  rotateX(${maxY * yCoeff}deg)
  rotateY(${maxX * xCoeff}deg)
  `);
  if (this.reachedFinalPoint) {
  this.animationRunning = false;
  } else {
  requestAnimationFrame(this.runAnimation.bind(this));  
  }
  }
  get reachedFinalPoint () {
  const lastX = ~~this.lastX;
  const lastY = ~~this.lastY;
  const targetX = this.targetX;
  const targetY = this.targetY;
  return (lastX == targetX || lastX - 1 == targetX || lastX + 1 == targetX)  
  && (lastY == targetY || lastY - 1 == targetY || lastY + 1 == targetY);
  }
  positionImage ({ xCoeff, yCoeff }) {
  const maxImgOffset = 1;
  const currentImage = this.activeImg[0].children[0];
  currentImage.style.setProperty('transform', `
  translateX(${maxImgOffset * -xCoeff}em)
  translateY(${maxImgOffset * yCoeff}em)
  `);  
  }
  onDotClick ({ target }) {
  if (this.inTransit) return;
  const dot = target.closest('.slayden-akosmo-dot');
  if (!dot) return;
  const nextId = dot.dataset.id;
  const currentId = this.activeImg[0].dataset.id;
  if (currentId == nextId) return;
  this.startTransition(nextId);
  }
  transitionItem (nextId) {
  function onImageTransitionEnd (e) {
  e.stopPropagation();
  nextImg.classList.remove(transitClass);
  self.inTransit = false;
  this.className = imgClass;
  this.removeEventListener('transitionend', onImageTransitionEnd);
  }
  const self = this;
  const el = this.el;
  const currentImg = this.activeImg[0];
  const currentId = currentImg.dataset.id;
  const imgClass = this.IMG_CLASS;
  const textClass = this.TEXT_CLASS;
  const activeImgClass = this.ACTIVE_IMG_CLASS;
  const activeTextClass = this.ACTIVE_TEXT_CLASS;
  const subActiveClass = `${imgClass}-subactive`;
  const transitClass = `${imgClass}-transit`;
  const nextImg = el.querySelector(`.${imgClass}[data-id='${nextId}']`);
  const nextText = el.querySelector(`.${textClass}[data-id='${nextId}']`);
  let outClass = '';
  let inClass = '';
  this.animationStopped = true;
  nextText.classList.add(activeTextClass);
  el.style.setProperty('--from-left', nextId);
  currentImg.classList.remove(activeImgClass);
  currentImg.classList.add(subActiveClass);
  if (currentId < nextId) {
  outClass = `${imgClass}-next`;
  inClass = `${imgClass}-prev`;
  } else {
  outClass = `${imgClass}-prev`;
  inClass = `${imgClass}-next`;
  }
  nextImg.classList.add(outClass);
  requestAnimationFrame(() => {
  nextImg.classList.add(transitClass, activeImgClass);
  nextImg.classList.remove(outClass);
  this.animationStopped = false;
  this.positionImage(this.getMouseCoefficients());
  currentImg.classList.add(transitClass, inClass);
  currentImg.addEventListener('transitionend', onImageTransitionEnd);
  });
  if (!this.isMobile)
  this.switchBackgroundImage(nextId);
  }
  startTransition (nextId) {
  function onTextTransitionEnd(e) {
  if (!e.pseudoElement) {
  e.stopPropagation();
  requestAnimationFrame(() => {
  self.transitionItem(nextId);
  });
  this.removeEventListener('transitionend', onTextTransitionEnd);
  }
  }
  if (this.inTransit) return;
  const activeText = this.activeText[0];
  const backwardsClass = `${this.TEXT_CLASS}-backwards`;
  const self = this;  
  this.inTransit = true;
  activeText.classList.add(backwardsClass);
  activeText.classList.remove(this.ACTIVE_TEXT_CLASS);
  activeText.addEventListener('transitionend', onTextTransitionEnd);
  requestAnimationFrame(() => {
  activeText.classList.remove(backwardsClass);
  });
  }
  next () {
  if (this.inTransit) return;
  let nextId = +this.activeImg[0].dataset.id + 1;
  if (nextId > this.length)
  nextId = 1;
  this.startTransition(nextId);
  }
  prev () {
  if (this.inTransit) return;
  let nextId = +this.activeImg[0].dataset.id - 1;
  if (nextId < 1)
  nextId = this.length;
  this.startTransition(nextId);
  }
  switchBackgroundImage (nextId) {
  function onBackgroundTransitionEnd (e) {
  if (e.target === this) {
  this.style.setProperty('--img-prev', imageUrl);
  this.classList.remove(bgClass);
  this.removeEventListener('transitionend', onBackgroundTransitionEnd);
  }
  }
  const bgClass = 'slider--bg-next';
  const el = this.el;
  const imageUrl = `url(${this.images[+nextId - 1].src})`;
  el.style.setProperty('--img-next', imageUrl);
  el.addEventListener('transitionend', onBackgroundTransitionEnd);
  el.classList.add(bgClass);
  }
}
const sliderEl = document.getElementById('posmutagan');
const slider = new Slider(sliderEl);
let timer = 0;
function autoSlide () {
  requestAnimationFrame(() => {
  slider.next();
  });
  timer = setTimeout(autoSlide, 4000);
}
function stopAutoSlide () {
  clearTimeout(timer);
  this.removeEventListener('touchstart', stopAutoSlide);
  this.removeEventListener('mousemove', stopAutoSlide);  
}
sliderEl.addEventListener('mousemove', stopAutoSlide);
sliderEl.addEventListener('touchstart', stopAutoSlide);
timer = setTimeout(autoSlide, 4000);

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

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

Демонстрация
25 Июля 2020 Загрузок: 3 Просмотров: 905 Комментариев: (0)

Поделиться в социальных сетях

Материал разместил

Оставь свой отзыв

Комментарии: 0
avatar