Reputation: 105
I have a container, with an unknown amount of cards in (ranging from 3 to 8).
| -- -- -- |
| CARD CARD CARD |
| -- -- -- |
And when one is clicked, all others disappear and the card clicked needs to move to the left. For example, if the middle card is clicked:
Cards disappear
| -- |
| CARD |
| -- |
Card moves to left (with an animation)
| -- |
| CARD |
| -- |
The cards are able to disappear but I feel my solution isn't great. I cannot move the card to the left.
Here's my solution for the hiding of the cards:
cards.forEach(card => {
card.addEventListener('click', () => {
cards.forEach(card2 => {
if(card2 != card){
card2.style.animation = 'fadeOut 0.2s linear forwards';
}
})
})
})
But I am very unsure how to move the card. Here's the css for the card container and card itself.
.cards{
height: 100%;
width: 100%;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 50px;
position: relative;
}
.card{
height: 100%;
width: 100%;
position: relative;
}
Is this possible with a css animation?
Upvotes: 3
Views: 3865
Reputation: 496
Here is a pretty solid working solution:
var cards = document.querySelectorAll(".card");
function transitionOpacity(){
cards.forEach( el => {
if(el.id != this.id){
el.classList.add("invisible");
}
});
}
function transitionWidth(){
cards.forEach( el => {
if(el.classList.contains("invisible")){
el.classList.add("thin");
}
});
}
cards.forEach( el => {
el.addEventListener("click", transitionOpacity);
el.addEventListener("transitionend", transitionWidth);
});
#main{
width: 100%;
height: 300px;
background-color: grey;
box-sizing: border-box;
}
.card{
height: 100%;
background-color: white;
margin: 2.5%;
width: 20%;
float: left;
opacity: 1;
transition: all .5s;
}
.invisible{
opacity: 0;
}
.thin{
width: 0;
margin-left: 0;
margin-right: 0;
}
<div id = "main">
<div id = "1" class = "card"></div>
<div id = "2" class = "card"></div>
<div id = "3" class = "card"></div>
<div id = "4" class = "card"></div>
</div>
Step 1: Add create html tags Step 2: Create CSS Step 3: Add all elements with card class to array Step 4: Add event listener to all cards to listen for clicks. Step 5: Add event listener to all cards to listen for the end of a transition Step 6: Check ID of clicked element. Hide elements that weren't clicked Step 7: Check classList of all cards that were made invisible and now make those cards shrink
Upvotes: 2
Reputation: 206131
To animate an element to its new position follow this simple steps:
display: none
translate: transform(x, y)
to the old X and Y.transition
to 0, 0 translate: transform(0, 0)
, which is the position this element actually occupies after the other elements were hided from the view.Here's an example of the above list with an extra step to first fade-out the other elements before hiding them, and only than - animate the element:
const animateCards = (card) => {
const fxHide = `display: none;`;
const fxFade = `transition: opacity 0.3s; opacity: 0;`;
const fxMove = `transform: translate(${card.offsetLeft}px, ${card.offsetTop}px);`;
const fxAnim = `transition: transform 0.5s; transform: translate(0, 0);`;
let other; // Just to catch a sibling element as reference
cards.forEach(el => {
if (el === card) return;
if (!other) other = el;
el.addEventListener("transitionend", () => el.style.cssText += fxHide, {once: true});
el.style.cssText += fxFade;
});
other.addEventListener("transitionend", () => {
card.style.cssText += fxMove;
setTimeout(() => card.style.cssText += fxAnim, 0);
}, {once: true});
};
const cards = document.querySelectorAll(".card");
cards.forEach(el => el.addEventListener('click', () => animateCards(el)));
.cards {
height: 100%;
width: 100%;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 50px;
position: relative;
}
.card {
height: 100%;
position: relative;
cursor: pointer;
}
<div class="cards">
<div class="card" style="background-color:#0bf;">1</div>
<div class="card" style="background-color:#f0b;">2</div>
<div class="card" style="background-color:#bf0;">3</div>
</div>
Upvotes: 5