Stop animation from replaying when parent switches from display:none to block - css

I have a set of tabs that each contain a child element that animates. What happens when I click each tab is that the animation of the child element within the tab runs. I do not want it to run. I want the animation to run the first time then not replay when it's parent switch from display:none to display:block.
In the example I made below I have 2 parent divs, each with a child div that animates over to the right. When each parent is set to block the animation replays, I do not want that to happen. I want each child to stay positioned over to the right. How can I make that happen?
$(".toggler").on("click", function() {
$(".parent").toggleClass("active");
});
.parent {
display: none;
cursor: pointer;
}
.child {
width: 100px;
height: 100px;
background-color: red;
position: relative;
animation: move 200ms cubic-bezier(.91, .8, .54, 1.39);
}
.active {
display: block;
}
.child.red {
background-color: red;
}
.child.blue {
background-color: blue;
}
#keyframes move {
from {
left: 0;
}
to {
left: 180px;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a class="toggler">Click this</a>
<div class="parent active">
<div class="child red"></div>
</div>
<div class="parent">
<div class="child blue"></div>
</div>
Fiddle Demo

Yes, animations will restart every time the display value is changed from none to something else.
As per W3C Spec: (emphasis is mine)
Setting the display property to ‘none’ will terminate any running animation applied to the element and its descendants. If an element has a display of ‘none’, updating display to a value other than ‘none’ will start all animations applied to the element by the ‘animation-name’ property, as well as all animations applied to descendants with display other than ‘none’.
There is no direct way to prevent this from happening because that is the intended behavior. You can workaround the situation by using other methods to hide the element instead of using display: none.
Following are a few suggestions on how the element could be hidden without display: none. It is not mandatory to use only one of the following workarounds, it could be some other way also as long as it doesn't involve changing the display property of the element.
Using height: 0, width: 0, overflow: hidden to hide the element.
$(".toggler").on("click", function() {
$(".parent").toggleClass("active");
});
.parent {
height: 0;
width: 0;
overflow: hidden;
cursor: pointer;
}
.child {
width: 100px;
height: 100px;
background-color: red;
position: relative;
animation: move 200ms cubic-bezier(.91, .8, .54, 1.39) forwards;
}
.active {
height: auto;
width: auto;
overflow: visible;
}
.child.red {
background-color: red;
}
.child.blue {
background-color: blue;
}
#keyframes move {
from {
left: 0;
}
to {
left: 180px;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a class="toggler">Click this</a>
<div class="parent active">
<div class="child red"></div>
</div>
<div class="parent">
<div class="child blue"></div>
</div>
Adding a container, using position: absolute and opacity: 0 to hide the element.
$(".toggler").on("click", function() {
$(".parent").toggleClass("active");
});
.container {
position: relative;
}
.parent {
position: absolute;
opacity: 0;
cursor: pointer;
}
.child {
width: 100px;
height: 100px;
background-color: red;
position: relative;
animation: move 200ms cubic-bezier(.91, .8, .54, 1.39) forwards;
}
.active {
opacity: 1;
}
.child.red {
background-color: red;
}
.child.blue {
background-color: blue;
}
#keyframes move {
from {
left: 0;
}
to {
left: 180px;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a class="toggler">Click this</a>
<div class='container'>
<div class="parent active">
<div class="child red"></div>
</div>
<div class="parent">
<div class="child blue"></div>
</div>
</div>
Adding a container, using position: absolute and visibility: hidden to hide the element.
$(".toggler").on("click", function() {
$(".parent").toggleClass("active");
});
.container {
position: relative;
}
.parent {
position: absolute;
visibility: hidden;
cursor: pointer;
}
.child {
width: 100px;
height: 100px;
background-color: red;
position: relative;
animation: move 200ms cubic-bezier(.91, .8, .54, 1.39) forwards;
}
.active {
visibility: visible;
}
.child.red {
background-color: red;
}
.child.blue {
background-color: blue;
}
#keyframes move {
from {
left: 0;
}
to {
left: 180px;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a class="toggler">Click this</a>
<div class='container'>
<div class="parent active">
<div class="child red"></div>
</div>
<div class="parent">
<div class="child blue"></div>
</div>
</div>
Adding a container, using position: absolute and z-index to hide the element.
$(".toggler").on("click", function() {
$(".parent").toggleClass("active");
});
.container {
position: relative;
}
.parent {
position: absolute;
z-index: -1;
cursor: pointer;
}
.child {
width: 100px;
height: 100px;
background-color: red;
position: relative;
animation: move 200ms cubic-bezier(.91, .8, .54, 1.39) forwards;
}
.active {
z-index: 1;
}
.child.red {
background-color: red;
}
.child.blue {
background-color: blue;
}
#keyframes move {
from {
left: 0;
}
to {
left: 180px;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a class="toggler">Click this</a>
<div class='container'>
<div class="parent active">
<div class="child red"></div>
</div>
<div class="parent">
<div class="child blue"></div>
</div>
</div>

Related

Emulating flipbook-vue, but without Javascript and images

I'm trying to emulate flipbook-vue component, but with pure CSS.
I would like to combine that component with this CSS example on CodePen.
On the flipbook-vue side, I like how the book remains centered when the first page opens, is that possible to do with CSS only? I tried, but the book doesn't expand as the cover rotates.
Also, do the pages need to go backwards like on CodePen example?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test page flip</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
width: 100vw;
height: 100vh;
overflow: hidden;
text-align: center;
}
div {
height: 100%;
}
#book {
border: 1px solid blue;
display: inline-block;
background: #eee;
text-align: center;
}
div.page {
border: 1px solid red;
width: 40vw;
height: 60%;
}
div.page.flipped {
transition: transform 1s;
transform: rotateY(180deg);
transform-origin: left center;
}
</style>
<script>
window.onload = () => {
setTimeout(flipPage, 1000);
}
flipPage = () => {
document.getElementById('page-1').classList.add('flipped');
}
</script>
</head>
<body>
<div id="book">
<div class="page" id="page-1">
PAGE 1
</div>
<div class="page" id="page-2">
PAGE 2
</div>
</div>
</body>
</html>
I think I'm happy enough with the solution I came up with
var page = 1;
var timerId = null;
window.onload = () => {
timerId = setInterval(flipPage, 1000);
}
toggleClass = (id, cssClass) => {
document.getElementById(id).classList.toggle(cssClass);
}
flipPage = () => {
if (page === 1) {
toggleClass('book', 'two-pages');
} else if (page === 8) {
toggleClass('book', 'closed');
toggleClass('book', 'two-pages');
clearInterval(timerId);
}
toggleClass('page-' + page, 'flipped');
page ++;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--page-width: 40vw;
--transition-speed: 2s;
}
body {
width: 100vw;
height: 100vh;
overflow: hidden;
perspective: 400vw;
background: #ccc;
}
body, .page > div {
display: flex;
align-items: center;
justify-content: center;
}
#book, .page {
width: var(--page-width);
height: 80vh;
}
#book {
transform-style: preserve-3d;
backface-visibility: visible;
flex-shrink: 0;
transition: var(--transition-speed) all ease;
position: relative;
margin: 0 auto;
}
#book.two-pages {
width: calc(2 * var(--page-width));
}
#book.closed {
width: calc(3 * var(--page-width));
}
.front, .back {
background: navy;
}
.page {
background: white;
border: 1px solid red;
position: absolute;
right: 0;
}
div.page.flipped {
transform: rotateY(180deg);
transition: transform var(--transition-speed);
transform-origin: left center;
}
.page > div {
position: absolute;
width: 100%;
height: 100%;
}
.page > div.back-face {
opacity: 0;
}
.page.flipped > div.front-face {
transition-property: opacity;
transition-delay: calc(0.3 * var(--transition-speed));
opacity: 0;
}
.page.flipped > div.back-face {
opacity: 0;
}
.page.flipped > div.back-face {
transition-property: opacity;
transition-delay: calc(0.3 * var(--transition-speed));
opacity: 1;
}
#page-1.flipped {
transform: rotateY(-180.04deg);
}
#page-2.flipped {
transform: rotateY(-180.03deg);
}
#page-3.flipped {
transform: rotateY(-180.02deg);
}
#page-4.flipped {
transform: rotateY(-180.01deg);
}
#page-5.flipped {
transform: rotateY(-180.0deg);
}
#page-6.flipped {
transform: rotateY(-179.99deg);
}
#page-7.flipped {
transform: rotateY(-179.98deg);
}
#page-8.flipped {
transform: rotateY(-179.97deg);
}
<div id="book" class="book">
<div class="page back" id="page-8">
<div class="front-face">PAGE 8</div>
<div class="back-face">BYE</div>
</div>
<div class="page page6" id="page-7">
<div class="front-face">PAGE 7</div>
<div class="back-face"></div>
</div>
<div class="page page5" id="page-6">
<div class="front-face">PAGE 6</div>
<div class="back-face"></div>
</div>
<div class="page page4" id="page-5">
<div class="front-face">PAGE 5</div>
<div class="back-face"></div>
</div>
<div class="page page3" id="page-4">
<div class="front-face">PAGE 4</div>
<div class="back-face"></div>
</div>
<div class="page page2" id="page-3">
<div class="front-face">PAGE 3</div>
<div class="back-face"></div>
</div>
<div class="page page1" id="page-2">
<div class="front-face">PAGE 2</div>
<div class="back-face"></div>
</div>
<div class="page front" id="page-1">
<div class="front-face">HELLO</div>
<div class="back-face">TO</div>
</div>
</div>

css transform rotate flickering/not working

I ran into this issue where I am trying to rotate this div on hover, but when I hover, it tries to hover but then it goes back to the normal position. could you please help?
here is my fiddle: https://jsfiddle.net/Lcb7okfn/
.section-tours{
background-color:pink;
padding:5rem 0 50rem 0;
}
.center-text{
background-color:blue;
padding:30px 0;
}
.col-1-of-3{
width: calc((100%-20px)/3);
}
.card{
background-color: orange;
height:15rem;
transition: all .8s;
perspective: 1000px;
-moz-perspective: 1000px;
}
.card:hover{
transform: rotateY(180deg);
}
Apply the hover to a parent element and also move the perspective declaration to the parent:
.section-tours {
background-color: pink;
padding: 5rem 0 50rem 0;
}
.center-text {
background-color: blue;
padding: 30px 0;
}
h2 {
padding: 0;
margin: 0;
}
.col-1-of-3 {
width: calc((100%-20px)/3);
perspective: 1000px;
}
.card {
background-color: orange;
height: 15rem;
transition: all .8s;
}
.col-1-of-3:hover .card {
transform: rotateY(180deg);
}
<section class="section-tours">
<div class="center-text">
<h2>
Most popular tours
</h2>
</div>
<div class="row">
<div class="col-1-of-3">
<div class="card">
<div class="card class_side">
TEXT
</div>
</div>
</div>
<div class="col-1-of-3">
</div>
<div class="col-1-of-3">
</div>
</div>
</section>

Why doesn't it work when I hover on the image?

I'm sure this is incredibly stupid once I get a hint, but I can't see why the hover doesn't work. I added the jQuery just to check whether or not it works with a click.
$(document).on("click", ".figure", function() {
$(".popover").css("opacity", "1");
})
.container {
position: relative;
}
.popover {
background-color: blue;
position: absolute;
top: 0;
left: 200px;
opacity: 0;
transition: opacity 0.5s ease-in-out 0s;
}
.figure:hover .popover {
opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='container'>
<div class='figure'>
<img src='https://placehold.it/100' />
</div>
<div class='popover'>
<p>
Bla bla
</p>
</div>
</div>
Because your .popover div is not a child of .figure div.
Used + selector for this
$(document).on("click", ".figure", function() {
$(".popover").css("opacity", "1");
})
.container {
position: relative;
}
.popover {
background-color: blue;
position: absolute;
top: 0;
left: 200px;
opacity: 0;
transition: opacity 0.5s ease-in-out 0s;
}
.figure:hover + .popover {
opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='container'>
<div class='figure'>
<img src='https://placehold.it/100' />
</div>
<div class='popover'>
<p>
Bla bla
</p>
</div>
</div>
Change :
.figure:hover .popover {
opacity: 1;
}
To :
.figure:hover + .popover {
opacity: 1;
}
Try changing classes into id´s and than make hover.
JSFiddle link
#figure:hover + #popover {
opacity:1;
}

CSS :focus not working

I tried using :focus CSS pseudo-class in my project. I want to change the color of the element where I click on it. Now when I click my element change color only where it is active and after mouse up it return to old color. After second click I want it back to old color. I'm using Chrome.
Demo here
.row {
display: inline-block;
border: 1px solid grey;
height: 200px;
width: 200px;
line-height: 1em;
background: grey;
margin: 5px;
opacity: 0.1;
}
.row:active,
.row:focus {
background: orange;
}
<div id="main" class="container">
<div class="row" id="row0">
</div>
</div>
If you want a real focus state to a div element, you can add a tabindex attribute to it.
.row {
display:inline-block;
border:1px solid grey;
height:200px;
width: 200px;
line-height:1em;
background: grey;
margin: 5px;
opacity: 0.1;
}
.row:active, .row:focus { background: orange; }
<div id="main" class="container">
<div class="row" tabindex="1" id="row0">
</div>
</div>
If you want toggle the color with clicking the same div element, you have to use javascript (jQuery):
jQuery('#row0').click(function() {
$(this).toggleClass('orange');
});
.row {
display:inline-block;
border:1px solid grey;
height:200px;
width: 200px;
line-height:1em;
background: grey;
margin: 5px;
opacity: 0.1;
}
.row.orange { background: orange; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="main" class="container">
<div class="row" id="row0">
</div>
</div>
Following Andy Tschiersch's answer, I would suggest using tabindex = "0" (which is its default value) instead of tabindex = "1".
See: https://developer.mozilla.org/fr/docs/Web/HTML/Global_attributes/tabindex
<div id="main" class="container">
<div class="row" id="row0" tabindex="0" >
</div>
</div>
You can emulate the toggle effect with a CSS trick by adding a hidden checkbox input.
See it here
HTML :
<div id="main" class="container">
<input type="checkbox" />
<div class="row" id="row0">
</div>
</div>
CSS :
.container { position: relative; }
input { position: absolute; left: 0; right: 0; top: 0; bottom: 0; width: 200px; height: 200px; z-index: 1; opacity: 0; display: block; }
input:checked + .row { background: orange; }
.row {
display:inline-block;
border:1px solid grey;
height:200px;
width: 200px;
line-height:1em;
background: grey;
margin: 5px;
opacity: 0.1;
}
.row:active, .row:focus { background: orange; opacity:1 }
<div id="main" class="container">
<div class="row" tabindex="1" id="row0">
</div>
</div>
Please try this...
What you are looking for is :visited, but this doesn't work on a div. You should use the a-tag for it (including href="#").
.row:active, .row:visited { background: orange; }
Check the fiddle below:
http://jsfiddle.net/uuyNH/32/
Edit: Vincent G's answer seems to do more what you want though, since you can remove the background color by clicking away.

CSS : Apply background to full width in a div with a fixed width

My page is divided in rows with limited width. (<div class='row'>)
I would like to apply a background (color) to each row, but I would like the back ground not to take into consideration the width limit of the div, is there a way to achieve this ?
Thanks!
Were you going for something like this? It'd be easier to answer your question if you provided a fiddle or atleast some code so we can help you with your problem.
I came to this solution:
<div class="row1">
...
</div>
<div class="row2">
...
</div>
.row1 {
background-color: red;
width: 100%;
height: 50%;
}
.row2 {
background-color: pink;
width: 100%;
height: 50%;
}
You can run it here: JSFiddle
This is possible with a pseudo-element, no need for additional HTML.
.wrapper {
width: 50%;
margin: auto;
}
[class^=row] {
height: 50px;
position: relative;
margin-bottom: 10px;
}
[class^=row]:before {
content: '';
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
height: 100%;
width: 100vw;
background: purple;
z-index: -1;
}
.row1 {
background-color: red;
}
.row2 {
background-color: pink;
}
<div class="wrapper">
<div class="row1">...</div>
<div class="row2">...</div>
</div>
You may be better to place each row inside a .container-fluid div with a {min-width: 100%} and a custom class for the colour you need
.container-fluid {
min-width: 100%
}
.row {
max-width: 300px;
margin: 0 auto;
padding: 10px;
}
.red {
background-color: red;
}
.green {
background-color: green;
}
.blue {
background-color: blue;
}
<div class="container-fluid red">
<div class="row">
<p>Row Content 1</p>
</div>
</div>
<div class="container-fluid green">
<div class="row">
<p>Row Content 2</p>
</div>
</div>
<div class="container-fluid blue">
<div class="row">
<p>Row Content 3</p>
</div>
</div>

Resources