<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;
}
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.