Галерея с интересными эффектами

Описание.

Простая галерея для сайта с интересными эффектами.

В этом слайдере реализовано следующее:

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

Демо

Код

HTML

<div class="gallery">
    <div class="gallery__item show">
      <img src="img/photo01.jpg">
    </div>
    <div class="gallery__item">
      <img src="img/photo02.jpg">
    </div>
    <div class="gallery__item">
      <img src="img/photo03.jpg">
    </div>
    <div class="gallery__item">
      <img src="img/photo04.jpg">
    </div>
    <div class="gallery__item">
      <img src="img/photo05.jpg">
    </div>
    <div class="gallery__item">
      <img src="img/photo06.jpg">
    </div>
    <div class="gallery__item">
      <img src="img/photo07.jpg">
    </div>
    <div class="gallery__item">
      <img src="img/photo08.jpg">
    </div>
  </div>

  <div class="gallery__nav">
    <div class="gallery__prev">
      <svg>
        <use href="#arrowG"></use>
      </svg>
    </div>
    <div class="gallery__next">
      <svg>
        <use href="#arrowG"></use>
      </svg>
    </div>
  </div>

  <svg style="display: none">
    <symbol id="arrowG" viewBox="0 0 22 8">
      <path stroke-linecap="round" stroke-width="1.5" d="M21.24 4H.76m0 0L4.17.73M.76 4l3.41 3.27"></path>
    </symbol>
  </svg>

SCSS

.gallery {
  display: flex;
  flex-direction: row;
  width: 170px;
  margin: 0 auto;
  transition: transform 0.5s ease-in-out;
  gap: 5px;
}

.gallery__item {
  flex-shrink: 0;
  flex-basis: 16px;
  overflow: hidden;
  transform: skewX(-11deg);
  transition: flex-basis 0.5s ease-in-out;

  &.show {
    flex-basis: 170px;
  }

  & img {
    position: relative;
    top: 50%;
    left: 50%;
    width: 220px;
    height: auto;
    transform: translate(-50%, -50%) skewX(11deg);
  }
}


.gallery__nav {
  display: flex;
  justify-content: center;
  margin-top: 9px;
  gap: 15px;
}

.gallery__prev,
.gallery__next {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 48px;
  height: 48px;
  cursor: pointer;
  transition: opacity .25s ease-in-out;

  & svg {
    display: block;
    width: 48px;
    height: 48px;
    transition: stroke .25s ease-in-out;
    stroke: #222629;
  }

  &.disable {
    cursor: default;
    opacity: .5;
  }

  &:not(.disable):hover svg {
    stroke: #e63e21;
  }
}

.gallery__next svg {
  transform: scale(-1, 1);
}


@media (min-width: 990px) {
  .gallery {
    width: 306px;
    margin-left: 0;
    transform: translateX(0) !important;
  }

  .gallery__item {
    &.show {
      flex-basis: 400px;
    }

    & img {
      width: 500px;
    }
  }
}

JS

const galleryItems = document.querySelectorAll('.gallery__item');
const prevButton = document.querySelector('.gallery__prev');
const nextButton = document.querySelector('.gallery__next');
const gallery = document.querySelector('.gallery');
let currentItem = 0;
let isStart;
var isHover = true;
const widthClose = gallery.querySelector('.gallery__item:not(.show)').clientWidth;

const showItem = index => {
  galleryItems.forEach((item, idx) => {
    item.classList.toggle('show', idx === index);
  });
  updateNavButtons();
  shiftGallery();
};

const shiftGallery = () => {
  if (window.innerWidth <= 990) {
    const gap = parseInt(window.getComputedStyle(gallery).gap);
    const shift = currentItem === 0 ? 0 : (gap + widthClose) * (currentItem - 1);

    gallery.style.transform = `translateX(-undefinedpx)`;
  }
}

const updateNavButtons = () => {
  prevButton.classList.toggle('disable', currentItem === 0);
  nextButton.classList.toggle('disable', currentItem === galleryItems.length - 1);
};

const nextItem = () => {
  if (currentItem < galleryItems.length - 1) {
    currentItem++;
    showItem(currentItem);
  }
};

const prevItem = () => {
  if (currentItem > 0) {
    currentItem--;
    showItem(currentItem);
  }
};

const startAutoPlay = () => {
  nextButton.removeEventListener('mouseleave', startAutoPlay);
  prevButton.removeEventListener('mouseleave', startAutoPlay);

  isStart = setInterval(() => {
    if (currentItem < galleryItems.length - 1) {
      nextItem();
    } else {
      currentItem = 0;
      showItem(currentItem);
    }
  }, 2000);
};

const stopAutoPlay = () => {
  clearInterval(isStart);
};

const onMousChangeGalery = (evt) => {
  stopAutoPlay();

  if (!isHover && evt.target.dataset.galeryId !== currentItem) {
    return;
  }
  currentItem = parseInt(evt.target.dataset.galeryId ? evt.target.dataset.galeryId : currentItem);

  showItem(currentItem);
  updateNavButtons();

  isHover = false;
  window.setTimeout(() => {
    isHover = true;
  }, 500);
}

galleryItems.forEach((item, idx) => {
  item.dataset.galeryId = idx;

  item.addEventListener('mouseenter', onMousChangeGalery);
  item.addEventListener('mouseleave', startAutoPlay);
});

nextButton.addEventListener('click', () => {
  stopAutoPlay();
  nextItem();
  nextButton.addEventListener('mouseleave', startAutoPlay);
});

prevButton.addEventListener('click', () => {
  stopAutoPlay();
  prevItem();
  prevButton.addEventListener('mouseleave', startAutoPlay);
});

startAutoPlay();
updateNavButtons();
shiftGallery();
Объявление

Если вы хотите обучаться вместе со мной, то приглашаю вас на индивидуальные курсы HTML Academy: «Профессиональная вёрстка сайтов» или «Адаптивная вёрстка и автоматизация».

Просто спросите у менеджера меня — наставника Зиновьева Александра. Обучение проходит в помесячном индивидуальном формате, и вы можете начать в любое удобное для вас время.

Кроме того, в HTML Academy вы получите профессию и даже сможете устроиться на работу с новой профессией.