<div class="viewport">
  <div class="js-container"></div>
  <div class="nav">
    <button class="nav__control" type="button">
      <svg xmlns="http://www.w3.org/2000/svg" class="js-navigation js-prev" width="56" height="56" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display: none;"><path d="M11 17l-5-5 5-5M18 17l-5-5 5-5" /></svg>
    </button>
    <button class="nav__control" type="button">
      <svg xmlns="http://www.w3.org/2000/svg" class="js-navigation js-next" width="56" height="56" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 17l5-5-5-5M6 17l5-5-5-5"/></svg>
    </button>
  </div>
</div>
<div class="thumbs">
  <img data-slide="slide-0" class="thumb js-thumb thumb--active" src="https://raw.githubusercontent.com/ivanalbizu/slides-blend-mode/master/img/beauty.jpg" alt="">
  <img data-slide="slide-1" class="thumb js-thumb" src="https://raw.githubusercontent.com/ivanalbizu/slides-blend-mode/master/img/girl.jpg" alt="">
  <img data-slide="slide-2" class="thumb js-thumb" src="https://raw.githubusercontent.com/ivanalbizu/slides-blend-mode/master/img/model.jpg" alt="">
  <img data-slide="slide-3" class="thumb js-thumb" src="https://raw.githubusercontent.com/ivanalbizu/slides-blend-mode/master/img/snow.jpg" alt="">
  <img data-slide="slide-4" class="thumb js-thumb" src="https://raw.githubusercontent.com/ivanalbizu/slides-blend-mode/master/img/woman.jpg" alt="">
</div>
<div class="options">
  <select name="blend-mode" id="blend-mode">
    <option value="unset">unset</option>
    <option value="normal">normal</option>
    <option value="multiply">multiply</option>
    <option value="screen">screen</option>
    <option value="overlay">overlay</option>
    <option value="darken">darken</option>
    <option value="lighten">lighten</option>
    <option value="color-dodge">color-dodge</option>
    <option value="color-burn">color-burn</option>
    <option value="hard-light">hard-light</option>
    <option value="soft-light">soft-light</option>
    <option value="difference">difference</option>
    <option value="exclusion">exclusion</option>
    <option value="hue">hue</option>
    <option value="saturation">saturation</option>
    <option value="color">color</option>
    <option value="luminosity">luminosity</option>
  </select>
  <input name="bg-mode" id="bg-mode" type="color">
</div>
$base-color: rgba(84, 17, 17, .2);
$row: 7;
$col: 11;
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: sans-serif;
}
html, body {height: 100%;}
button {
  background-color: transparent;
  border: 0;
  outline: none;
  cursor: pointer;
}
:root {
  --col: #{$col};
  --row: #{$row};
  --items: 0;
  --timeout: 2000;
}
.js-container {
  display: grid;
  grid-template-columns: repeat(var(--col), minmax(calc(100% / var(--col)), 1fr));
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  right: 0;

  .item {
    z-index: 4;
    transform: scale(0);
    opacity: 0;
  }
}
.viewport {
  position: relative;
  width: 100%;
  height: 550px;
  max-height: 100vh;
  .slide {
    width: inherit;
    height: inherit;
    max-height: inherit;
    position: absolute;
    opacity: 0;
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center;
    &--active {
      opacity: 1;
    }
  }
}

.nav {
  position: absolute;
  width: 100%;
  height: 100%;
  z-index: 5;
  display: flex;
  justify-content: space-between;
  align-items: center;
  &__control {
    display: flex;
    opacity: 0;
    transition: opacity .3s ease;
  }
  &:hover {
    .nav__control {
      background-color: #242424;
      opacity: 1;
      transition: opacity .9s ease, background-color 2s ease;
    }
  }
}

.thumbs {
  display: flex;
  justify-content: center;
  margin: 10px 5px;
  .thumb {
    margin: 0 5px;
  }
}

.options {
  display: flex;
  justify-content: center;
  margin: 15px 15px 20px;
  > * {
    height: 28px;
    border: 1px solid #6f6f6f;
    margin: 1px 5px;
  }
}

.js-animating {
  .thumbs {
    cursor: wait;
  }
  .js-thumb {
    pointer-events: none;
  }
  [class^="js-"] {
    pointer-events: none;
  }
  .item {
    animation-name: particles;
    animation-timing-function: ease-in-out;
  }
}

.thumb {
  cursor: pointer;
  width: 100px;
  max-width: calc(20% - 10px);
  box-shadow: 0 0 7px #000;
  &:hover {
    box-shadow: 0 0 2px #000;
  }
  &--active {
    pointer-events: none;
    box-shadow: 0 0 2px #000;
  }
}

.fade-in {
  animation: fadeIn calc(var(--timeout) * 1ms) ease-in-out 0s forwards;
}
.fade-out {
  animation: fadeOut calc(var(--timeout) * 1ms) ease-in-out 0s forwards;
}


@keyframes fadeIn {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}
@keyframes fadeOut {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
@keyframes particles {
  0% {
    transform: scale(0);
    opacity: 0;
  }
  30% {
    opacity: 1;
    background-color: $base-color;
    transform: scale(.95);
  }
  70% {
    transform: scale(.7);
    opacity: .4;
  }
  100% {
    transform: scale(0);
    opacity: 0;
  }
}
View Compiled
document.addEventListener('DOMContentLoaded', () => {

  const viewport = document.querySelector('.viewport');
  
  const container = document.querySelector('.js-container');
  const thumbs = document.querySelectorAll('.thumbs .thumb');
  const navs = document.querySelectorAll('.js-navigation');
  
  const row = getComputedStyle(document.documentElement).getPropertyValue('--row');
  const col = getComputedStyle(document.documentElement).getPropertyValue('--col');
  const timeout = getComputedStyle(document.documentElement).getPropertyValue('--timeout');
  
  if (container && viewport && thumbs) {
    insertBefore(createFrameSlides(thumbs), container);
    container.appendChild(createFragment(row, col));

    setDelay(timeout);

    thumbs.forEach(anime => {
      anime.addEventListener('click', handlerThumbs.bind(this, timeout), false);
    });

    document.addEventListener('input', handlerCustomBackground, false);
    
    navs.forEach(nav => {
      nav.addEventListener('click', handlerNavigation.bind(this, nav, timeout), false);
    });
  }

});


const createFrameSlides = thumbs => {
  const fragment = new DocumentFragment();
  thumbs.forEach((thumb, index) => {
    const el = elFactory(
      'div',
      { 
        id: `slide-${index}`,
        class: `slide${(index == 0 ? " slide--active" : "")}`,
        style: `background-image: url(${thumb.getAttribute('src')})`
      }
    )
    fragment.appendChild(el);
  })
  
  return fragment;
}


const elFactory = (type, attributes, ...children) => {
  const el = document.createElement(type)

  for (key in attributes) {
    el.setAttribute(key, attributes[key])
  }

  children.forEach(child => {
    if (typeof child === 'string') el.appendChild(document.createTextNode(child))
    else el.appendChild(child)
  })

  return el
}


const insertBefore = (el, referenceNode) => referenceNode.parentNode.insertBefore(el, referenceNode);


const createFragment = (row, col) => {
  let fragment = new DocumentFragment();

  let step;
  let items = -1;
  for (let r = 0; r < row; r++) {     
    for (let c = 0; c < col; c++) {
      if ((row / 2) > r) {
        if ((col / 2) > c) step = r + c;
        else step--;
        if (items < step) items = step;
      } else {
        if ((col / 2) > c) step = row - r - 1 + c;
        else step--;
      }
      
      fragment.appendChild(elFactory('span', { class: `item item--${step}`}));
    }
  }
  document.documentElement.style.setProperty('--items', items);

  return fragment;
}


const setDelay = timeout => {
  let style = document.createElement('style');
  document.head.appendChild(style);
  
  const items = getComputedStyle(document.documentElement).getPropertyValue('--items');

  for (let index = 0; index <= items; index++) {
    const item = `.item--${index} {
      animation-delay: ${index*100}ms;
      animation-duration: ${timeout-index*100}ms;
    }`;    
    style.sheet.insertRule(item);
  }
}


const statusNavigation = el => {
  if (!el.nextElementSibling) document.querySelector('.js-next').style.display = 'none';
  else document.querySelector('.js-next').style.display = 'flex';
  
  if (!el.previousElementSibling) document.querySelector('.js-prev').style.display = 'none';
  else document.querySelector('.js-prev').style.display = 'flex';
}


const handlerThumbs = (timeout) => transitionTo(event.target, timeout);


const handlerNavigation = (nav, timeout) => {
  let active = null;
  if (nav.classList.contains('js-next')) {        
    active = document.querySelector('.thumb--active').nextElementSibling;
  } else {
    active = document.querySelector('.thumb--active').previousElementSibling;
  }

  transitionTo(active, timeout)
}


const transitionTo = (to, timeout) => {
  document.body.classList.add('js-animating');
  document.querySelector('.thumb--active').classList.remove('thumb--active');

  const particles = document.querySelectorAll('.js-container .item');
  particles.forEach(item => item.classList.add('particles'))
  
  to.classList.add('thumb--active');
  statusNavigation(to);
  
  const current = document.querySelector('.slide--active');
  current.classList.add('fade-out');
  
  const slide = document.querySelector('#'+to.getAttribute('data-slide'));
  slide.classList.add('fade-in');
  
  setTimeout(() => {
    document.body.classList.remove('js-animating');
    current.classList.remove(...['fade-out', 'slide--active']);
    slide.classList.remove('fade-in');
    slide.classList.add('slide--active');
    particles.forEach(item => item.classList.remove('particles'));
  }, timeout);
}


const handlerCustomBackground = () => {
  if (event.target.id === 'blend-mode') {
    document.querySelectorAll('.viewport .slide').forEach(slide => {
      slide.style.mixBlendMode = `${event.target.value}`;
    });
  } else if (event.target.id === 'bg-mode') {
    document.querySelector('.viewport').style.backgroundColor = `${event.target.value}`;
  } else {
    return;
  }
}
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.