JSFiddle - React, Tailwind, and code Playground
by sazakharov
HTML
<div class="grid">
<div class="grid_inner">
<div class="item image1"></div>
<div class="item image2"></div>
<div class="item image3"></div>
<div class="item image4"></div>
<div class="item image5"></div>
<div class="item image6"></div>
<div class="item image7"></div>
<div class="item image8"></div>
<div class="item image9"></div>
<div class="item image10"></div>
<div class="item image11"></div>
<div class="item image12"></div>
<div class="item image13"></div>
<div class="item image14"></div>
<div class="item image15"></div>
<div class="item image16"></div>
<div class="item image17"></div>
<div class="item image18"></div>
<div class="item image19"></div>
<div class="item image20"></div>
<div class="item image21"></div>
</div>
</div>
CSS
* {
box-sizing: border-box;
}
html, body {
height: 100%;
overflow: hidden;
}
body {
margin: 0;
display: flex;
}
.grid {
width: 90%;
margin: auto;
padding: 10px;
position: relative;
overflow: hidden;
background-color: #333;
}
.grid_inner {
display: flex;
flex-wrap: wrap;
margin: -10px 0 0 -10px;
}
.item {
margin: 10px 0 0 10px;
width: calc(25% - 10px);
height: 100px;
transform: translate(0, 0);
cursor: pointer;
background-repeat: no-repeat;
background-size: cover;
background-position: 50% 50%;
}
.item-opened {
z-index: 999;
}
.image1, .image10, .image21, .image7 {
background-image: url('https://images.unsplash.com/photo-1494256997604-768d1f608cac?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=801&q=80');
}
.image2, .image9, .image20, .image14 {
background-image: url('https://images.unsplash.com/photo-1526336024174-e58f5cdd8e13?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=334&q=80');
}
.image3, .image15, .image12, .image13 {
background-image: url('https://images.unsplash.com/photo-1518843025960-d60217f226f5?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=334&q=80');
}
.image4, .image11, .image19 {
background-image: url('https://images.unsplash.com/photo-1496890666403-e6cf521841e6?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEzMDA0fQ&auto=format&fit=crop&w=1500&q=80');
}
.image5, .image8, .image17 {
background-image: url('https://images.unsplash.com/photo-1516125073169-9e3ecdee83e7?ixlib=rb-1.2.1&auto=format&fit=crop&w=1500&q=80');
}
.image6, .image18, .image16 {
background-image: url('https://images.unsplash.com/photo-1466618786657-4df462be674e?ixlib=rb-1.2.1&auto=format&fit=crop&w=1500&q=80');
}
JavaScript
const grid = document.querySelector('.grid');
const items = document.querySelectorAll('.grid .item');
const onSelect = (function(items, transitionDuration = 0) {
let opened = null;
let neighbors = [];
let closingTimer = null;
items = Array.from(items);
items.forEach(el => {
el.style.transitionDuration = transitionDuration + 'ms';
el.style.transitionProperty = 'transform';
});
function calcBox(el) {
const parrentBox = el.offsetParent.getBoundingClientRect();
const elBox = el.getBoundingClientRect();
return {
top: elBox.top - parrentBox.top,
left: elBox.left - parrentBox.left,
right: parrentBox.right - elBox.right,
bottom: parrentBox.bottom - elBox.bottom,
};
}
function dublicateItem(originEl) {
const cloneEl = originEl.cloneNode(true);
cloneEl.classList.add('item-opened');
cloneEl.style.margin = 0;
cloneEl.style.width = 'auto';
cloneEl.style.height = 'auto';
cloneEl.style.position = 'absolute';
cloneEl.style.transitionDuration = transitionDuration + 'ms';
cloneEl.style.transitionProperty = 'top, left, right, bottom';
const cloneBox = calcBox(originEl);
cloneEl.style.top = cloneBox.top + 'px';
cloneEl.style.left = cloneBox.left + 'px';
cloneEl.style.bottom = cloneBox.bottom + 'px';
cloneEl.style.right = cloneBox.right + 'px';
originEl.parentElement.insertBefore(cloneEl, originEl);
originEl.style.visibility = 'hidden';
return { originEl, cloneEl };
}
function openItem(target) {
opened = dublicateItem(target);
const parrentRect = target.offsetParent.getBoundingClientRect();
const targetRect = opened.cloneEl.getBoundingClientRect();
const targetCx = targetRect.left - targetRect.width / 2;
const targetCy = targetRect.top - targetRect.height / 2;
neighbors = items.filter(el => el !== target);
for (let i = 0; i < neighbors.length; i++) {
const el = neighbors[i];
const rect =...