CSS animation in a column - css

I have many div stacked up in a column. When top div is destroyed lower divs will naturally come up and vice versa. I want that transition to be smooth.
How do I achieve this? Do I apply CSS animation class to each inserted div? I am confused. Pls advice. Thanks.
$add = document.getElementById('add');
$remove = document.getElementById('remove');
$parent = document.getElementById('parent');
let i = 0
$add.onclick = function() {
let el = document.createElement("DIV");
let text = document.createTextNode("Hello " + i);
el.appendChild(text);
$parent.insertBefore(el, $parent.firstElementChild);
i++;
}
remove.onclick = function() {
$parent.removeChild($parent.firstElementChild);
}
<button id="add" onclick="myFunction()">Add child on top</button>
<button id="remove" onclick="removeChlid()">remove child on top</button>
<div id="parent">
</div>

Animation can be achieved using css if we are adding element.
In case of removing we need to fisrt add class before removing to start animation and then remove element from DOM when animation is done. In example there is the same 500m delay, of course it can be done also checking animationEnd event in js.
$add = document.getElementById('add');
$remove = document.getElementById('remove');
$parent = document.getElementById('parent');
let i = 0
$add.onclick = function(){
let el = document.createElement("DIV");
el.className='test';
let text = document.createTextNode("Hello "+ i );
el.appendChild(text);
$parent.insertBefore(el, $parent.firstElementChild);
i++;
}
remove.onclick = function(){
$parent.firstElementChild.className += ' remove-animation';
setTimeout(() => {
$parent.removeChild($parent.firstElementChild);
}, 500)
}
.test {
max-height: auto;
animation: test-animation 0.5s;
transition: max-height 0.5s;
margin-bottom: 5px;
overflow: hidden;
}
.remove-animation {
animation: remove-animation 0.5s;
}
#keyframes test-animation {
0% { max-height: 0; }
100% { max-height: 25px }
}
#keyframes remove-animation {
0% { max-height: 25px; }
100% { max-height: 0 }
}
<button id="add" onclick="myFunction()">Add child on top</button>
<button id="remove" onclick="removeChlid()">remove child on top</button>
<div id="parent">
</div>

Related

How to make the color of a div change permanently after it has been clicked in react.js

This is the grid that I have
Once a square has been clicked, the color changes to red. - This is done using active class
I would like the change to the background color of the div tag to remain permanent after the square has been clicked.
Code
Board.js
{board.map((row, rowIdx) => (
<div key={rowIdx} className="row">
{row.map((cell, cellIdx) => (
<div key={cellIdx} className="cell"></div>
))}
</div>
))}
Board.css
.row {
height: 30px;
margin: 10px;
transition: transform 0.1s;
}
.cell:hover {
transform: scale(1.4);
}
.cell {
width: 30px;
height: 30px;
outline: 1px solid rgb(134, 154, 189);
display: inline-block;
background-color: seagreen;
margin: 5px;
transition: transform 0.2s;
}
.row :active {
background-color: red;
}
.cell :active { // Does not do anything
background-color: blue;
}
Once another square is clicked, the previosly clicked one does not remain active, you can do this by adding another class with your desired style, and using state to track the squares that have been clicked.
const [boardIndeces, setBoardIndeces] = useState(initArray(board));
const initArray = arr => {
let rows = [];
for (let i = 0; i < arr.length; i++) {
let row = [];
const currBoard = arr[i];
for (let z = 0; z < currBoard.length; z++) {
row[z] = false;
}
rows[i] = row;
}
return rows;
};
const onCellClick = (rowIdx, cellIdx) => {
if (!(boardIndeces[rowIdx] && boardIndeces[rowIdx][cellIdx])) {
boardIndeces[rowIdx][cellIdx] = true;
setBoardIndeces([...boardIndeces]);
}
};
{
board.map((row, rowIdx) => (
<div key={rowIdx}>
{row.map((cell, cellIdx) => (
<div
key={cellIdx}
className={
boardIndeces[rowIdx].includes(cellIdx)
? 'your_active_class'
: 'your_inactive_class'
}
onClick={() => onCellClick(rowIdx, cellIdx)}
></div>
))}
</div>
));
}
You can use a checkbox if you don't want to use React
HTML
<input type="checkbox" id="color" name="color">
<label id="color-div" for="color">
<!-- the div you want to change color -->
</label>
CSS
#color {
display: none
}
#color:checked + #color-div { /* + in CSS is the sibling combinator */
background-color: #fffff /* your background color */
}
What you're basically doing is making an invisible checkbox and toggling it with the label, when it's toggled you do the changes to the CSS
Remember the CSS combinators only work in elements after the HTML element it's being applied to

Is it possible to create scroll in generic transition Stylus mixin?

JavaScript:
const show = entries => entries[0].isIntersecting ? entries[0].classList.remove('is-hidden') : null;
const observer = new IntersectionObserver(show, {threshold:0});
Array.from(document.querySelectorAll('.js-hidden')).forEach(element => observer.observe(element));
I want to play fade in animation when '.js-hidden' class are removed like below... but this code are not working:
HTML:
<div class="my-component js-hidden is-hidden">
<p class="text text-1">Hello</p>
<p class="text text-2">World</p>
</div>
Stylus:
fadeIn(duration=1s, delay=0s) {
opacity: 1;
transition: opacity duration ease delay;
&.is-hidden { // <- yeah, this is wrong... but, any ideas? I want to apply transition both element and pseudo element.
opacity: 0;
}
}
.my-component {
.text,
&::before,
&::after {
fadeIn();
}
.text-2 {
transition-delay: .3s;
}
&::before {
content: 'foo';
transition-delay: .5s;
}
&::after {
content: 'bar';
transition-delay: .7s;
}
}
And, if the fade in elements are more nested?
<div class="my-component js-hidden is-hidden">
<div class="wrapper-1">
<div class="wrapper-2">
<p class="text text-1">Hello</p>
<p class="text text-2">World</p>
</div>
</div>
</div>
I want to apply transition both element and pseudo element. but I don’t know what should I do...
Thanks.
Finally...
Thank you Andy.
Finally I arrived the code below. XD
JavaScript:
const show = entries => entries[0].isIntersecting ? entries[0].target.classList.remove('is-hidden') : null;
const observer = new IntersectionObserver(show, {threshold:0});
Array.from(document.querySelectorAll('.js-hidden')).forEach(element => observer.observe(element));
HTML:
<div class="my-component js-hidden is-hidden">
<p class="text text-1">Hello</p>
<p class="text text-2">World</p>
<p class="text text-3">Hello</p>
<p class="text text-4">World</p>
<p class="text text-5">Hello</p>
<p class="text text-6">World</p>
<p class="text text-7">Hello</p>
<p class="text text-8">World</p>
<p class="text text-9">Hello</p>
</div>
Stylus:
fadeIn(target, duration=1s, delay=0s, property=all, easing=ease) {
{target} {
opacity: 1;
transition: duration property easing delay;
}
&.is-hidden {
{target} {
opacity: 0;
}
}
}
.my-component {
duration = .3s;
delay = 1s;
fadeIn('.text', duration:duration, delay:delay);
fadeIn('&::before', duration:duration, delay:delay);
fadeIn('&::after', duration:duration, delay:delay);
interval = duration;
amount = 9;
for i in 2..amount {
.text-{i} {
transition-delay: (interval * (i - 2) + duration + delay)s;
}
}
&::before {
content: 'FOOOOOOOOOOOOOOO';
transition-delay: (interval * ((amount + 1) - 2) + duration + delay)s;
}
&::after {
content: 'BARRRRRRRRRRRRRR';
transition-delay: (interval * ((amount + 2) - 2) + duration + delay)s;
}
}
First, it seems you're looking for a transition, not an animation. I'm not a Stylus expert, but know IntersectionObserver and CSS pretty well. I have the basic demo working now.
Some notes on the adjusted fadeIn function.
is-hidden is a class that exists in the DOM from the beginning, so cue the transition when it's not there
use a delegate pattern from transitions—that is, have the change in the parent affect the children (don't listen for a class for each child/pseudo element)
fadeIn(duration=1s, delay=0s) {
.text,
&::before,
&::after {
opacity: 0;
transition: 0.5s opacity ease;
}
&:not(.is-hidden) {
.text,
&::before,
&::after {
opacity: 1;
}
}
}
Also, I couldn't get your JavaScript to work due to some errors and rewrote it to suit the demo. Here's the rewritten JavaScript:
const components = document.querySelectorAll(".my-component");
const observer = new IntersectionObserver(components => {
components.forEach(component => {
if (component.intersectionRatio > 0) {
component.target.classList.remove("is-hidden")
} else {
component.target.classList.add("is-hidden")
}
})
});
Array.from(document.querySelectorAll(".js-hidden")).forEach(element =>
observer.observe(element)
);
CodePen Demo

Use CSS transition only for increasing value

In my code, I want to use the transition only when the width turns wider.
When the width decrease I don't want any animation.
can I do with CSS only? Add/remove classes is not an option for me.
function changeCss() {
document.getElementById('squareId').style.width = "300px";
}
function reset() {
document.getElementById('squareId').style.width = "100px";
}
.square {
background-color: red;
width: 100px;
height: 100px;
transition: width 1s linear;
}
<div id="squareId" class="square"></div>
<button onclick="changeCss()">increase</button>
<button onclick="reset()">decrease</button>
JSFiddle
Adjust the transition at the same time in the JS code:
window.changeCss = function() {
document.getElementById('squareId').style.transition = "width 1s linear";
document.getElementById('squareId').style.width = "300px";
}
window.reset = function() {
document.getElementById('squareId').style.transition = "none";
document.getElementById('squareId').style.width = "100px";
}
.square {
background-color: red;
width: 100px;
height: 100px;
}
<div id="squareId" class="square">
</div>
<button onclick="changeCss()">increase</button>
<button onclick="reset()">decrease</button>

transition for translateY(0) working, but not translateY(-50px)

I'm having some trouble with a transition on a transform. I'm making a tic-tac-toe game like in the freecodecamp front-end challenges: https://codepen.io/freeCodeCamp/full/KzXQgy.
I've been able to create most layout things no problem, but am having an issue with my transition on a div that shows which players' turn it is after hitting the reset button. Right now I'm just working on two player mode, so I click two players, then X or O, and then the tic-tac-toe board shows up and a div transform: translateY(-50px) to indicate whether it's Player 1 or Player 2's turn (based on a random number variable I set up). The first time through the div transition's perfectly. Then I hit the Reset All div and it takes me back to the beginning to choose how many players again. And the div transitions the transform: translateY(0) perfectly back to it's starting position. Where I'm struggling is, now when I cycle through the options again, if it's Player 1 or Player 2's turn again, the transition never happens and the div just transforms -50px up with the translateY.
I've tried everything I could think of, JS setting up the transition, resetting the transition, moving the transition to be on different classes, adding and removing a class that only has a transition on it. Can't figure it out, but the weird thing is, whenever I hit the "Reset All", the transform transitions back to 0px normally. Here's my codepen: https://codepen.io/rorschach1234/pen/dZMaJg?editors=0111. I know it's still very rough, but just can't figure out this transition problem. Really appreciate any help. Thanks everyone!
My relevant Html:
<div class="container">
<div class="turns">
<div class="turns__left turns__box"></div>
<div class="turns__right turns__box"></div>
</div>
</div>
My relevant CSS:
.turns {
width: 100%;
display: flex;
position: absolute;
justify-content: space-around;
top: 0;
left: 0;
z-index: -1;
&__box {
width: 40%;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-size: 1.3em;
font-family: sans-serif;
transition: transform 1s .3s ease;
}
&__left {
background-color: $color-turn-left;
//transition: transform 1s .3s ease;
}
&__right {
background-color: $color-turn-right;
//transition: transform 1s .3s ease;
}
}
My Javascript:
let numOfPlayers = document.querySelectorAll(".player .choices h2");
let playerScreen = document.querySelector(".player");
let markerScreen = document.querySelector(".markers");
let singlePlayer = true;
let backBtn = document.querySelector(".markers__back");
let gameScreen = document.querySelector(".game");
let playerOne; let playerTwo; let activePlayer;
let turnBoxes = document.querySelectorAll(".turns__box");
let resetBtn = document.querySelector(".scoreboard__reset");
game();
function game() {
playerModeSelection();
markerSelection();
}
function boardChange(active, inactive) {
inactive.style.opacity = "0";
inactive.style.zIndex = "0";
active.style.opacity = "1";
active.style.zIndex = "1";
}
//One or Two player Selection & transition to Marker Selector
function playerModeSelection() {
for (let i = 0; i < numOfPlayers.length; i++) {
numOfPlayers[i].addEventListener("click", function() {
if(i === 1) {
singlePlayer = false;
}
boardChange(markerScreen, playerScreen);
})
}
}
function markerSelection() {
//Back Button Functionality
backBtn.addEventListener("click", function() {
boardChange(playerScreen, markerScreen);
})
//Listen for choice of X or O
for (let i = 0; i < markers.length; i ++) {
markers[i].addEventListener("click", function() {
boardChange(gameScreen, markerScreen);
if (i === 1) {
playerArr = ["O", "X"];
}
//Starts Two Player Game; Here begin is the function that calls transition
if(!singlePlayer) {
twoPlayerMode();
}
})
}
}
function twoPlayerMode() {
activePlayer = Math.floor(Math.random() * 2);
turnBoxes[activePlayer].textContent = "Go Player " + (activePlayer + 1) + "!";
turnBoxes[activePlayer].style.transform = "translateY(-50px)";
resetBtn.addEventListener("click", function() {
boardChange(playerScreen, gameScreen);
turnBoxes[activePlayer].style.transform = "translateY(0px)";
})
}

Queued CSS animations using delay or keyframes that can be interrupted smoothly

First, a fiddle: http://jsfiddle.net/AATLz/
The essence here is that there's a set of animations queued using -webkit-transition-delay. First element 0.4s, second 0.8s, third 1.4s, etc. They're queued last to first by default, and first to last when the parent has the 'expanded' class (toggled with that button).
This means that the animation when '.expanded' is added brings the boxes out one by one, and in reverse when the class is removed.
That's dandy. The problems start to arise when the class is toggled mid-animation. If you toggle, say, after the second box has animated, there's a delay before they start animating back, because a couple delay timers are being waited out.
Delays are obviously a bit clunky here.
The two alternatives I have in mind are 1) CSS keyframe animations, which I'm not entirely sure of how to activate on multiple elements in succession, and 2), JS controlled timing - using something like jQuery Transit. I'm not sure which would be more capable/graceful or if I'm missing another option.
Any input would be awesome!
jsfiddle: http://jsfiddle.net/Bushwazi/fZwTT/
Changed it up a bit. Control the timing with js. Animations with css.
CSS:
* {
margin:0;
padding:0;
}
#container {
background: orange;
height: 100px;
position: relative;
width: 100px;
}
.box {
height: 100px;
left: 0;
position: absolute;
top: 0;
width: 100px;
-webkit-transition:all 0.5s ease-in-out 0s;
-moz-transition:all 0.5s ease-in-out 0s;
-o-transition:all 0.5s ease-in-out 0s;
transition:all 0.5s ease-in-out 0s;
-webkit-transform: translate3d(0,0,0);
}
.box-1 {
background: red;
}
.box-2 {
background: green;
}
.box-3 {
background: yellow;
}
.box-4 {
background: blue;
}
.box-1 .box-1 {
left:100px;
}
.box-2 .box-2 {
left:200px;
}
.box-3 .box-3 {
left:300px;
}
.box-4 .box-4 {
left:400px;
}
HTML:
<div id="container" class="box-0" data-status="default" data-box="0">
<div class="box box-1"></div>
<div class="box box-2"></div>
<div class="box box-3"></div>
<div class="box box-4"></div>
</div>
<button id="ToggleAnim">Toggle</button>
JS:
(function(){
var testies = {
to: 0,
init: function(){
$button = $('#ToggleAnim');
$anim_elm = $('#container');
$(function(){
testies.el();
});
},
el: function(){ // el ==> event listeners
$button.on('click', testies.toggleBoxes);
},
toggleBoxes: function(evt){
var status = $anim_elm.attr('data-status'),
pos = $anim_elm.attr('data-box');
window.clearTimeout(testies.to);
// if default ==> build
// if killing ==> build
// if building ==> kill
// if done ==> kill
if(status == 'build' || status == 'done'){
testies.kill();
} else {
testies.build();
}
evt.preventDefault();
},
build: function(){
bpos = $anim_elm.attr('data-box');
if(bpos < 4){
bpos++;
$anim_elm.attr('data-status', "build").attr('data-box', bpos).addClass('box-' + bpos);
testies.to = window.setTimeout(testies.build, 500);
}
if(bpos == 4)$anim_elm.attr('data-status', "done");
console.log('BUILD: ' + bpos);
},
kill: function(){
kpos = $anim_elm.attr('data-box');
if(kpos > 0){
db = kpos - 1;
$anim_elm.attr('data-status', "kill").attr('data-box', db).removeClass('box-' + kpos);
testies.to = window.setTimeout(testies.kill, 500);
}
console.log('KILL: ' + kpos);
if(kpos == 0)$anim_elm.attr('data-status', "default")
}
}
testies.init();
})();

Resources