I have some javascript which will change the col-span-{x}
class of a div to correctly give the element its width on the page. I would like this change to be animated over a second instead of an instant jump.
<div >...</div>
CodePudding user response:
As per the Tailwind docs, col-span-{number}
classes are setting the grid-column
CSS property (MDN), namely class names col-span-1 and col-span-2 correspond to grid-column: span 1 / span 1;
and grid-column: span 2 / span 2;
.
These grid-column shorthand property and its values are not animatable. So, you have to fight the headwind of animating the widths yourself, in a tedious way like this:
- clone the animated grid cell element and its next neighbour
- add transition: width 1s; to the style of clones
- put the clones exactly over their originals using element.getBoundingClientRect() for their pixel position and dimensions
- change the col-span-{number} class names in the origin elements as needed
- get the pixel position and dimensions of the originals with new col-span-{number} classes
- feed new widths to the clone elements
- on the transitionend event, remove the clones and show the originals
- Deal with the literal edge-cases when you change the col-span-{number} on an edgemost item.
Well, here's a demo that needs refactoring and resembles the good old Masonry layout.
let grid;
const hide = (elem) => {
elem.style.opacity = 0;
}
const show = (elem) => {
elem.style.opacity = 1;
}
const animateWidth = (elem) => {
const gridRect = grid.getBoundingClientRect();
const targetRect = elem.getBoundingClientRect();
const clone = elem.cloneNode();
clone.style.pointerEvents = 'none';
clone.innerHTML = elem.innerHTML ' clone';
clone.classList.add('clone');
clone.style.position = 'absolute';
clone.style.zIndex = 999;
clone.style.transition = 'width 1s, left 1s, top 1s';
const oldWidth = targetRect.width;
clone.style.width = oldWidth 'px';
const top = targetRect.y - gridRect.y;
clone.style.top = top ? top 'px' : 0;
const left = targetRect.x - gridRect.x;
clone.style.left = left ? left 'px' : 0;
grid.appendChild(clone);
hide(elem);
let nextSibling;
let nextSiblingClone;
if (elem.nextSibling && !elem.nextSibling.classList.contains('clone')) {
nextSibling = elem.nextSibling;
nextSiblingClone = createAndGetNextSiblingClone(elem.nextSibling);
}
elem.classList.toggle('col-span-1');
elem.classList.toggle('col-span-2');
const newWidth = elem.getBoundingClientRect().width;
clone.style.width = newWidth ? newWidth 'px' : 0;
const newLeft = elem.getBoundingClientRect().x - gridRect.x;
clone.style.left = newLeft ? newLeft 'px' : 0;
const newTop = elem.getBoundingClientRect().y - gridRect.y;
clone.style.top = newTop ? newTop 'px' : 0;
if (nextSibling) {
const nextSiblingRect = nextSibling.getBoundingClientRect();
const nextSiblingLeft = nextSiblingRect.x - gridRect.x;
nextSiblingClone.style.left = nextSiblingLeft ? nextSiblingLeft 'px' : 0;
const nextSiblingTop = nextSiblingRect.y - gridRect.y;
nextSiblingClone.style.top = nextSiblingTop ? nextSiblingTop 'px' : 0;
}
clone.ontransitionend = (event) => {
show(elem);
if (event && event.target && event.target.parentNode) {
event.target.parentNode.removeChild(event.target);
}
}
}
const createAndGetNextSiblingClone = (elem) => {
const gridRect = grid.getBoundingClientRect();
const targetRect = elem.getBoundingClientRect();
const clone = elem.cloneNode();
clone.innerHTML = elem.innerHTML ' clone';
clone.classList.add('clone');
clone.style.position = 'absolute';
clone.style.zIndex = 999;
clone.style.transition = 'left 1s, top 1s';
clone.style.pointerEvents = 'none';
clone.style.width = targetRect.width ? targetRect.width 'px' : 0;
const top = targetRect.y - gridRect.y;
clone.style.top = top ? top 'px' : 0;
const left = targetRect.x - gridRect.x;
clone.style.left = left ? left 'px' : 0;
grid.appendChild(clone);
hide(elem);
clone.ontransitionend = (event) => {
show(elem);
if (event && event.target && event.target.parentNode) {
event.target.parentNode.removeChild(event.target);
}
}
return clone;
}
const onGridItemClick = (event) => {
animateWidth(event.target);
}
const displayTheGrid = () => {
grid = document.getElementById('grid');
'lightgreen lightblue #dabaf9 beige #ffbbbb #f9daba #99cefa'
.split(' ')
.forEach((color, index) => {
const gridItem = document.createElement('div');
gridItem.innerHTML = index;
gridItem.style.backgroundColor = color;
grid.appendChild(gridItem);
gridItem.onclick = onGridItemClick;
});
}
window.addEventListener('DOMContentLoaded', displayTheGrid);
* {
box-sizing: border-box;
}
#grid {
display: grid;
grid-template-columns: 20fr 20fr 20fr 20fr 20fr;
grid-gap: 10px;
margin-top: 10px;
position: relative;
}
#grid > div {
border-radius: 6px;
padding: 10px;
background-color: silver;
}
.col-span-1 {
grid-column: span 1 / span 1;
}
.col-span-2 {
grid-column: span 2 / span 2;
}
<!-- https://stackoverflow.com/questions/74571960 -->
<div id="grid"></div>
CodePudding user response:
I don't know if with only transition
property applied you can perform an animation on col-span.
Try to use transition-all
instead of transition