Delayed animation timing for different elements in a CSS 3D flip? - css

So I have the basic setup for a CSS flip in this fiddle here: http://jsfiddle.net/6r82fzk6/
What this is: A CSS 3D Flip (container, card, front & back elements) with child elements on the front & back. The flip occurs on :hover for demonstration.
What I'm trying to achieve: To get the back element to transition slower than everything else. So by the time the card flips and the back side is visible, the child element of the back face (#be) is halfway through its transition.
What I have so far: Code snippet below. You may open the JSFiddle link to see it in action. Its the black gradient element I'm aiming to delay.
#container {
perspective: 800px;
position: relative;
width: 300px;
height: 300px;
margin: 1px auto;
}
#card {
transform-style: preserve-3d;
transition: all 1s ease-in-out;
position: relative;
}
#container:hover #card {
transform: rotateY(180deg);
}
#front,
#back {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 300px;
backface-visibility: hidden;
transform-style: preserve-3d;
}
#front {
background: red;
z-index: 2;
}
#back {
transform: rotateY(180deg);
background: blue;
}
#fe,
#be {
position: absolute;
top: 20px;
left: 20px;
transform: translateZ(50px);
}
#fe {
width: 50px;
height: 50px;
background: gold;
box-shadow: 0 0 4px black;
}
#be {
width: 260px;
height: 260px;
box-shadow: 0 4px 8px -2px rgba(0, 0, 0, 0.6), 0 1px 3px whitesmoke inset;
background: linear-gradient(to top, rgba(0, 0, 0, 0.65) 0%, rgba(0, 0, 0, 0) 100%);
}
<!-- Outside container -->
<div id="container">
<!-- Card being flipped -->
<div id="card">
<!-- Front face -->
<div id="front">
<!-- Front Child element -->
<div id="fe"></div>
</div>
<!-- Back face -->
<div id="back">
<!-- Back Child element -->
<div id="be"></div>
</div>
</div>
</div>
To clarify: This is not production code, its more for testing and understanding. I'm exploratory like that.

You can not do it in you current setup.
This is because you are not moving the front or the back, but the container.
If you want them to move differently, you have to move them directly instead of the container
#container:hover #front {
transform:rotateY(180deg);
}
#container:hover #back {
transform:rotateY(360deg);
}
#front {
transition:all 1s ease-in-out;
}
#back {
transition:all 2s ease-in-out;
}
demo

Related

moving div from outside to inside the div and out again in pure css not using keyframe

content1.className = 'start';
window.getComputedStyle(document.getElementById('content1')).opacity;
content1.style.marginLeft = "0px";
content1.className = 'transition1';
.main {
width: 300px;
height: 250px;
top: 0px;
left: 0px;
overflow: hidden;
position: relative;
background-color: grey;
cursor: pointer;
}
#content1 {
background-color: red;
width: 300px;
height: 250px;
top: 0px;
left: 0px;
margin-left: -300px;
}
.start {
opacity: 0
}
.transition1 {
opacity: 1;
visibility: hidden;
/*margin-left: -300px !important;*/
-webkit-transition: margin-left 1.5s ease 1.5s, margin-left 1.5s ease 1.5s, visibility 1.5s ease 1.5s
}
<div id="main" class="main">
<div id="content1" class="content1 hidden">
</div>
</div>
I want the red div to start from outside and go into the grey div slowly then after a few seconds it would go out slowly again. I tried using transition but it seems to now work.
My guess is timing is wrong?
UPDATE
I have the above now What I lack is the timing to show the red div then go out again to left. I have set a visibility but I think there is a way to just use margins?
If you're wanting to do this without keyframes, then I have two ideas.
First idea is to add the transition css property to the actual #content1 element. Because as you're removing the .transition1 class, you're taking away the transition details.
If that doesn't work, then you might need to break this into 4 different "states".
That is:
Start State: Red div starts unseen
Start-to-End Transition State: .transition1 class gets added
End State: A class is added to ensure that the red div has the same margin from the .transition1 even after the .transition1 class gets taken away.
End-to-State Transition State: Essentially do the opposite of what you did in the .transition1 class.
EDIT:
Maybe ignore the "4 steps" because I likely was overthinking what you were asking.
I'm not 100% sure why you wouldn't want a keyframe, but I've added a few options you can reference depending on your overall use case. Each of these rely on some sort of trigger or event. In my case, a click. But this can be determined by any sort of event.
var main2 = document.getElementById('main2');
var content2 = document.getElementById('content2');
main2.addEventListener('click', function() {
content2.classList.toggle('active');
});
var main4 = document.getElementById('main4');
var content4 = document.getElementById('content4');
main4.addEventListener('click', function() {
content4.classList.add('animate');
setTimeout(function() {
content4.classList.remove('animate');
}, 1500)
});
.main {
width: 300px;
height: 250px;
position: relative;
background-color: grey;
cursor: pointer;
overflow: hidden;
}
#content1 {
position: absolute;
background-color: red;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
transform: translate(-100%, 0);
-webkit-transition: transform 1.5s ease;
}
.main:hover #content1 {
transform: translate(0, 0);
}
/* Toggle Option */
#content2 {
position: absolute;
background-color: red;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
transform: translate(-100%, 0);
-webkit-transition: transform 1.5s ease;
}
#content2.active {
transform: translate(0, 0);
}
/* SetTimeout Option */
#content4 {
position: absolute;
background-color: red;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
transform: translate(-100%, 0);
-webkit-transition: transform 1.5s ease;
}
#content4.animate {
transform: translate(0, 0);
}
<h2>Hover Option</h2>
<p>Animation happens on hover and disappears after hover</p>
<div class="main">
<div id="content1">
</div>
</div>
<h2>Toggle Option</h2>
<p>Animation happens on click and disappears on second click</p>
<div id="main2" class="main">
<div id="content2">
</div>
</div>
<h2>SetTimeout Option</h2>
<p>Animation happens on click and disappears after 1 second</p>
<div id="main4" class="main">
<div id="content4">
</div>
</div>

Growing "blast" of light animation from center of page

Using CSS I'd like to animate a radial-gradient circle to expand the full length and width of the page (to fully white) and then reverse this animation (return to original state). This should look like a gradual "blast" of white from the center and fade to fully white once reaching full width/height, however my white background starts transitioning too early. How do I achieve this?
scss
.container {
display: flex;
justify-content: center;
flex-direction: column;
text-align: center;
background: black;
height: 100vh;
}
.flash-container {
animation: grow 5s 2s linear forwards;
width: 20px;
height: 20px;
z-index: 4;
#flash {
background: radial-gradient(circle, white, transparent 10%);
width: 100%;
height: 100%;
position: absolute;
border-radius: 100%;
}
}
#keyframes grow {
to {
transform: scale(1000);
background: white;
}
}
html
<div class="container">
<div class="flash-container">
<div class="flash"></div>
</div>
</div>
Jsfiddle: https://jsfiddle.net/zv3bmw8j/2/
I updated your CSS to use the box-shadow method as I quoted above. This would need more tweaks to do as it was being built on a hover method. Just change the percentage value from 0% - 100% and you should be solid. I also made a change to the HTML format and removed the inner flash div.
https://jsfiddle.net/q9n6adLp/
.flash-container {
animation: grow 5s 2s linear forwards;
width: 20px;
height: 20px;
z-index: 4;
margin: 0 auto;
box-shadow: 0 0 30vw 40vw rgba(241,244,0,1);
.flash {
background: radial-gradient(circle, white, transparent 10%);
width: 100%;
height: 100%;
position: absolute;
border-radius: 100%;
}
}

How can I "tranform:translate" relative to a previous translate?

I have the following working code which I am attempting to simplify:
[tt] {
position: relative;
}
[tt]::after {
bottom: 100%;
content: attr(tt);
padding: 5px;
background: #333;
color: #fff;
}
[tt]::before,
[tt]::after {
position: absolute;
/* Middle 3 */
left: 50%;
transform: translate(-50%, 50%);
}
/* First 3 */
[tt]:nth-child(-n+3)::before,
[tt]:nth-child(-n+3)::after {
transform: translate(0 , 50%);
}
/* Last 3 */
[tt]:nth-last-child(-n+3)::before,
[tt]:nth-last-child(-n+3)::after {
transform: translate(-100%, 50%);
}
/* add animation */
[tt]:hover::before,
[tt]:hover::after {
animation: tt-move1 100ms ease-out forwards;
display: block;
}
[tt]:nth-child(-n+3):hover::before,
[tt]:nth-child(-n+3):hover::after {
animation: tt-move2 100ms ease-out forwards;
}
[tt]:nth-last-child(-n+3):hover::before,
[tt]:nth-last-child(-n+3):hover::after {
animation: tt-move3 100ms ease-out forwards;
}
#keyframes tt-move1 {
to {
transform: translate(-50%, 0);
}
}
#keyframes tt-move2 {
to {
transform: translate(0, 0);
}
}
#keyframes tt-move3 {
to {
transform: translate(-100%, 0);
}
}
/*For working demo*/
div {
/*won't work unless set relative, Something that happens in [tt]*/
top:100px;
margin: 10px;
float:left;
width: 20px;
height: 20px;
border: black solid 3px;
}
<div tt="tt1"></div>
<div tt="tt2"></div>
<div tt="tt3"></div>
<div tt="tt4"></div>
<div tt="tt5"></div>
<div tt="tt6"></div>
<div tt="tt7"></div>
<div tt="tt8"></div>
<div tt="tt9"></div>
The above code has a specific animation for each different type of element, something which seems unnecessary. To my knowledge, I am simply applying the same transform to each element (moving the element up along the y-axis) so I expected that the following should also work:
[tt] {
position: relative;
}
[tt]::after {
bottom: 100%;
content: attr(tt);
padding: 5px;
background: #333;
color: #fff;
}
[tt]::before,
[tt]::after {
position: absolute;
/* Middle 3 */
left: 50%;
transform: translate(-50%, 50%);
}
/* First 3 */
[tt]:nth-child(-n+3)::before,
[tt]:nth-child(-n+3)::after {
transform: translate(0 , 50%);
}
/* Last 3 */
[tt]:nth-last-child(-n+3)::before,
[tt]:nth-last-child(-n+3)::after {
transform: translate(-100%, 50%);
}
/*****************Changed code*******************/
/* add animation */
[tt]:hover::before,
[tt]:hover::after {
animation: tt-move 100ms ease-out forwards;
display: block;
}
#keyframes tt-move {
to {
transform: translateY(0);
}
}
/*///////////////Changed code/////////////////*/
/*For working demo*/
div {
/*won't work unless set relative, Something that happens in [tt]*/
top:100px;
margin: 10px;
float:left;
width: 20px;
height: 20px;
border: black solid 3px;
}
<div tt="tt1"></div>
<div tt="tt2"></div>
<div tt="tt3"></div>
<div tt="tt4"></div>
<div tt="tt5"></div>
<div tt="tt6"></div>
<div tt="tt7"></div>
<div tt="tt8"></div>
<div tt="tt9"></div>
After some research, I now understand that transform: translateY(Δy); is the same as saying transform: translate(0,Δy); which is causing the unexpected result. Unfortunately that was the only method I have been able to find that looks like it is supposed to do what I wanted.
I am looking for a method to transform:translate that allows the x-axis of a previous transform:translate to stay the same, while only changing the y-axis.
Is there a different way to accomplish this simplification? Or am I stuck using the repetitious code from above?
When you animate transform you have to add any already set values or else they will temporary be overwritten.
In this case you could animate the bottom instead, which will give the output you want.
[tt] {
position: relative;
}
[tt]::after {
bottom: 100%;
content: attr(tt);
padding: 5px;
background: #333;
color: #fff;
}
[tt]::before,
[tt]::after {
position: absolute;
/* Middle 3 */
left: 50%;
transform: translate(-50%, 50%);
}
/* First 3 */
[tt]:nth-child(-n+3)::before,
[tt]:nth-child(-n+3)::after {
transform: translate(0 , 50%);
}
/* Last 3 */
[tt]:nth-last-child(-n+3)::before,
[tt]:nth-last-child(-n+3)::after {
transform: translate(-100%, 50%);
}
/*****************Changed code*******************/
/* add animation */
[tt]:hover::before,
[tt]:hover::after {
animation: tt-move 100ms ease-out forwards;
}
#keyframes tt-move {
to {
bottom: 170%;
}
}
/*///////////////Changed code/////////////////*/
/*For working demo*/
div {
/*won't work unless set relative, Something that happens in [tt]*/
top:100px;
margin: 10px;
float:left;
width: 20px;
height: 20px;
border: black solid 3px;
}
<div tt="tt1"></div>
<div tt="tt2"></div>
<div tt="tt3"></div>
<div tt="tt4"></div>
<div tt="tt5"></div>
<div tt="tt6"></div>
<div tt="tt7"></div>
<div tt="tt8"></div>
<div tt="tt9"></div>

What can I use to replace translate3d

So, the code transform: translate3d(0,0,0); makes position:fixed; not work. and by removing it, I am now allowed to use position:fixed; again. one problem, my navigation bar was using the transform code to open, what other way can I use to make it do the same?
heres the code with the transform code, keep in mind this have been removed.
.nav-content {
flex: 1;
box-shadow: 0 0 5px rgba(0,0,0,1);
transform: translate3d(0,0,0);
transition: transform .3s;
}
.nav-content.isOpen {
transform: translate3d(220px,0,0);
}
.nav-content.isClosed {
transform: translate3d(0,0,0);
}
Transforms establish a containing block even for fixed elements. There is no workaround. Either don't use transforms or fixed positioning becomes somewhat useless.
In this case, if you are only using translate3d to translate in X direction, you can just use relative positioning with a left offset.
.nav-content {
position: relative;
left: 0;
transition: left .3s;
}
.nav-content.isOpen {
left: 220px;
}
.nav-content {
position: relative;
left: 0;
transition: left .3s;
height: 200vh;
border: 3px solid blue;
}
:checked ~ .nav-content {
left: 220px;
}
.fixed {
position: fixed;
}
<input type="checkbox" id="toggle" />
<label for="toggle">Toggle</label>
<div class="nav-content">
<div class="fixed">I am fixed</div>
</div>

CSS animate circle border filling with color

I'm new to learning about CSS animations.
I have a circle with an arc going around it, but I want to make it leave a trail behind. The idea is I'd use this to visually show how many credits somebody has used e.g. 75 / 100 credits used, the circle border becomes 3/4 colored-in.
I have a fiddle to show the arc stopping at the top. What I need is a way to
1) Make it stop at different points depending on the number of credits (can I use the 0%, 50% etc. inside keyframes somehow, like adding a class via jQuery?)
2) Leave a trail behind, so it fills with color.
.circle {
/* code - pls see fiddle */
#keyframes animation {
0% {transform: rotate(0);}
50% {transform: rotate(180deg);}
100% {transform: rotate(360deg);}
}
There is a very easy to follow, informative and detailed tutorial on exactly how to achieve this (and more) by Anders Ingemann, which can be found here.
Its a fairly complex operation- so I'll simply distil the final stage from the tutorial here
Demo Fiddle
HTML
<div class="radial-progress">
<div class="circle">
<div class="mask full">
<div class="fill"></div>
</div>
<div class="mask half">
<div class="fill"></div>
<div class="fill fix"></div>
</div>
<div class="shadow"></div>
</div>
<div class="inset"></div>
</div>
CSS/LESS
.radial-progress {
#circle-size: 120px;
#circle-background: #d6dadc;
#circle-color: #97a71d;
#inset-size: 90px;
#inset-color: #fbfbfb;
#transition-length: 1s;
#shadow: 6px 6px 10px rgba(0, 0, 0, 0.2);
margin: 50px;
width: #circle-size;
height: #circle-size;
background-color: #circle-background;
border-radius: 50%;
.circle {
.mask, .fill, .shadow {
width: #circle-size;
height: #circle-size;
position: absolute;
border-radius: 50%;
}
.shadow {
box-shadow: #shadow inset;
}
.mask, .fill {
-webkit-backface-visibility: hidden;
transition: -webkit-transform #transition-length;
transition: -ms-transform #transition-length;
transition: transform #transition-length;
}
.mask {
clip: rect(0px, #circle-size, #circle-size, #circle-size/2);
.fill {
clip: rect(0px, #circle-size/2, #circle-size, 0px);
background-color: #circle-color;
}
}
}
.inset {
width: #inset-size;
height: #inset-size;
position: absolute;
margin-left: (#circle-size - #inset-size)/2;
margin-top: (#circle-size - #inset-size)/2;
background-color: #inset-color;
border-radius: 50%;
box-shadow: #shadow;
}
}
Example jQuery (could be substituted with CSS)
$('head style[type="text/css"]').attr('type', 'text/less');
less.refreshStyles();
var transform_styles = ['-webkit-transform', '-ms-transform', 'transform'];
window.randomize = function () {
var rotation = Math.floor(Math.random() * 180);
var fill_rotation = rotation;
var fix_rotation = rotation * 2;
for (i in transform_styles) {
$('.circle .fill, .circle .mask.full').css(transform_styles[i], 'rotate(' + fill_rotation + 'deg)');
$('.circle .fill.fix').css(transform_styles[i], 'rotate(' + fix_rotation + 'deg)');
}
}
setTimeout(window.randomize, 200);
$('.radial-progress').click(window.randomize);

Resources