#extend class animations cancel each other out - css

I'm trying to create a loading animation where the outer ring spins to the right, while the inner one spins to the left.
This is all the CSS code:
html {
height: 100%;
}
.loadingCircle {
width: 100px;
height: 100px;
border: solid 5px transparent;
border-top: solid 5px blue;
border-radius: 50%;
transform-origin: center center;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
.loadingCircleOuter {
#extend .loadingCircle;
animation: circleSpinOuter 2s linear infinite;
}
.loadingCircleInner {
#extend .loadingCircle;
height: 80px;
width: 80px;
animation: circleSpinInner 2s linear infinite;
}
#keyframes circleSpinOuter {
0% {
transform: rotateZ(0deg);
}
100% {
transform: rotateZ(360deg);
}
}
#keyframes circleSpinInner {
0% {
transform: rotateZ(0deg);
}
100% {
transform: rotateZ(-360deg);
}
}
Doing this results in the inner circle not spinning at all.
If I comment out the animation of the outer circle the inner one spins properly and making the inner circle spin twice as fast is enough to cancel the out the spin of the outer animation and add the proper spin to the left to it (oddly enough, only to it and not to the outer one, that one is still spinning correctly to the right).
It's clear that the outer animation is applied to both circles, but why?
I don't understand why it's behaving like that, changing the color of the outer circle does not apply the change to both circles, why does it alter the animation for both though?
Am I doing something horribly wrong?

Related

Collapsing a div with Animation: how to improve this code?

I'm trying to make a div that appear and disappear on touch, like the navigation bar of android phones.
Should I use transition for this or is animation ok? In the fiddle example i use the mouse click and the setTimeout to simulate the touches and the auto disappear if you dont touch the screen for some seconds.
.custom-row{
position: fixed;
width: 100%;
height: 50px;
bottom: -100px;
left: 0px;
background-color: yellow;
opacity: 0;
}
.slidein {
animation: slidein 1s ease-in forwards;
}
.slideout {
animation: slideout 1s ease-in forwards;
}
#keyframes slidein {
0% {
}
100% {
bottom: 0px;
opacity: 1;
}
}
#keyframes slideout {
0% {
bottom: 0px;
opacity: 1;
}
100% {
bottom: -100px;
opacity: 0;
}
}
https://jsfiddle.net/1rm64q8z/1/
For this use case, transition seems to be a better solution. With animation, alerting position is a compute-intensive approach. The CSS will also be much more readable and scalable with transitions in this case.
const bar = document.getElementById("bottom-bar");
bar.addEventListener("click", (el) => {
el.target.classList.toggle("slide-out");
setTimeout(() => {
el.target.classList.toggle("slide-out");
el.target.classList.toggle("slide-in");
}, 2000)
})
body {
overflow: hidden;
}
#bottom-bar {
position: absolute;
bottom: 0px;
left: 0px;
width: 100%;
background: yellow;
padding: 16px;
text-align: center;
transform-origin: bottom;
transition: transform 0.4s ease-in-out;
}
.slide-in {
transform: translateY(0%);
}
.slide-out {
transform: translateY(100%);
}
<div id="bottom-bar">
Hello
</div>
The performance of CSS transitions and animations should be almost the same as they are both hardware accelerated so on most modern browsers the behaviour should be the same.
Animations are often used to create a more complex series of movements and they do not lift the rendering process to the GPU and resulting in being slower than transitions.
This article gives a great breakdown of when to use animations vs transitions.

CSS Transition : large div disappears completely while animating

I have some problems with a CSS transition effect. I don't understand why, but it isn't working. Here is a demo that isn't working :
https://codyhouse.co/demo/ink-transition-effect/index.html
Here is an article about how this effect was done (before, when it did work) :
https://codyhouse.co/gem/ink-transition-effect
The code I'm working on to debug is this one :
https://codepen.io/1019/pen/YzxzNGX
HTML file :
<body>
CSS ANIMATIONS TEST
<div class='cd-transition-layer'>
<div class="bg-layer"></div>
</div>
</body>
CSS file :
.cd-transition-layer {
position: fixed;
top: 0;
left: 0;
z-index: 30;
height: 100%;
width: 100%;
}
.cd-transition-layer .bg-layer {
position: absolute;
left: 50%;
top: 50%;
z-index: 15;
transform: translateY(-50%) translateX(-2%);
height: 100%;
width: 2500%;
background: url('https://i.imgur.com/9uDdPAP.png') no-repeat 0 0;
background-size: 100% 100%;
animation: cd-sprite 5s steps(24);
animation-fill-mode: forwards
}
.cd-transition-layer.opening .bg-layer {
z-index: 15;
animation: cd-sprite .8s steps(24);
animation-fill-mode: forwards
}
#keyframes cd-sprite {
0% {
transform: translateY(-50%) translateX(-2%)
}
100% {
transform: translateY(-50%) translateX(-98%)
}
}
Can you please help me find what is wrong ?
Thank you !
EDIT : Okay, weird : it seems the div just completely disappears during the animation before reappering. If I keep focus on the div in the inspector, it stays there. Is it because it's too long (2500% width) ?
Moving large divs
It seems that animating a large div over the screen very fast can cause a render/flicker in webkit based browsers.
If i have to guess, it's probably due to performance reasons, where the browser cuts off things thats are not in the viewport. when moving to the next frame, it will not have the pixels ready to be rendered, resulting in a flicker.
It becomes more apparent when you remove the steps(24) from the animation.
The div will slide over the screen, and at some point just stop being visible.
Using background-position instead
When animating, instead of moving a div over the screen, we can also opt to move only the background instead.
background: url("https://i.imgur.com/9uDdPAP.png") no-repeat;
background-size: 2500% 100%; /* Size is needed to stretch 1 frame to fit the div */
background-position: 0% 0%; /* we can start from frame 0 */
animation: cd-sprite 1s steps(24);
/* the animation is the same, we only move the background instead. (in 24 steps) */
#keyframes cd-sprite {
0% {
background-position: 0% 0%;
}
100% {
background-position: 100% 0%;
}
}
* {
box-sizing: border-box;
}
.cd-transition-layer {
position: fixed;
top: 0;
left: 0;
z-index: 30;
height: 100%;
width: 100%;
}
.cd-transition-layer .bg-layer {
position: absolute;
left: 50%;
top: 50%;
z-index: 15;
height: 100%;
width: 100%;
background: url("https://i.imgur.com/9uDdPAP.png") no-repeat;
background-size: 2500% 100%;
background-position: 4.16% 0%;
transform: translateY(-50%) translateX(-50%);
animation: cd-sprite 1s steps(24) infinite;
animation-direction: alternate;
animation-delay: 1s;
animation-fill-mode: forwards;
border: 36px solid red;
}
#keyframes cd-sprite {
0% {
background-position: 0% 0%;
}
100% {
background-position: 100% 0%;
}
}
<body>
<div class='cd-transition-layer'>
<div class="bg-layer"></div>
</div>
</body>

How can you use CSS to animate a rolling element across the screen repeatedly?

This is my first time asking a question on here and I've found questions that are somewhat similar, but haven't worked for my issue.
I am trying to spin a word across the screen from off-screen left to off-screen right. The center of the word should be it's rotation point (ie word spins in place from left side of screen to right). I have tried using variations of translateX and rotate, but it either rotates in place or moves left to right. When it does move from the left to right off the screen, it keeps extending the bounds of my screen and stretching it before it loops back to the left side. Any ideas how I can solve this? Seems simple, but I'm terrible with animations.
.move {
position: absolute;
animation: moveword 10s infinite linear;
}
.spin {
position: absolute;
animation: spin 7s infinite linear;
}
#keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
#keyframes moveword {
from {
left: -10%;
}
to {
left: 95%;
}
}
Based on code that you provide, I assume you could make something like this.
overflow: hidden needs to be applied to separate element, not the <body> because it restricts scrolling.
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.page {
position: relative;
width: 100vw;
height: 100vh;
overflow: hidden;
}
.word {
position: absolute;
top: 5px;
left: 5px;
animation: word-anim 10s infinite linear;
}
#keyframes word-anim {
0% {
transform: translateX(0px) rotateZ(0deg);
}
70% {
transform: translateX(70vw) rotateZ(360deg);
}
100% {
transform: translateX(100vw) rotateZ(360deg);
}
}
<div class="page">
<span class="word">A word</span>
</div>

How to animate a ripple effect of a gradient flowing across a background image in CSS

Not quite a pulse animation -- but somewhat similar (not radial, but linear) -- I am trying to create the effect of sort of a lens flare if you turn a piece of glass and see a band of light swipe across it, in CSS. So say you have a regular background image, or a seamless repeating background image, in CSS. Now you want to animate across that image a rectangular band of light that is sort of a "fade-in ... full light ... fade-out" gradient of white light. So you have a linear-gradient sort of like transparent, semi-transparent-white, white, semi-transparent-white, transparent that flows across the background image (seamless/repeating background image, or regular background image), repeatedly flowing across like it was a pool of water in constant motion.
Wondering if this sort of thing is possible in CSS, and how to do it.
Maybe it is simply an animated linear-gradient mask (which I am not familiar with but have heard of). Not sure.
Basically animating a semitransparent linear gradient like this (just the line part, and imagine it was a simple rectangle).
Are you looking for something like below:
body {
margin:0;
height:100vh;
background:
linear-gradient(to right,transparent 33%,white,transparent 66%),
url(https://picsum.photos/id/10/800/800) center;
background-size:300% 100%,cover;
animation:change 2s linear infinite;
}
#keyframes change {
from { /*Use "to" to change the direction */
background-position:right,center;
}
}
html {
background:#fff;
}
Related to get more details about the calculation:Using percentage values with background-position on a linear gradient
NOt sure if this is what you are looking for. Here it is a shot!
.ripple{
width: 50px;
height: 50px;
display: block;
position: relative;
background-color: #00ccff;
border-radius: 100%;
opacity: 0.5;
}
.ripple:before, .ripple:after{
content: '\0020';
width: 0;
height: 0;
position: absolute;
top: 50%;
left: 50%;
border-radius: 100%;
border: 2px solid #0088ee;
transform: translate(-50%, -50%);
}
.ripple:before{
animation: ripple-one 2.5s infinite;
}
.ripple:after{
animation: ripple-one 3.5s infinite;
}
#keyframes ripple-one{
0%{
width: 0;
height: 0;
opacity: 1;
}
100% {
width: 100%;
height: 100%;
opacity: 0;
}
}
#keyframes ripple-two{
0%{
width: 0;
height: 0;
opacity: 1;
}
100% {
width: 100%;
height: 100%;
opacity: 0;
}
}
<label class="ripple"></label>

CSS Animation - drawing line from left to right on mouseenter, then disappearing left to right on mouseleave

I'm trying to animate a line that underlines from left to right on 'mouseenter' and then to disappear from left to right on 'mouseleave' instead of the current behaviour where it disappears right to left.
Example of what I'm trying to achieve (but with animations not transitions):
https://jsfiddle.net/1gyksyoa/
I have tried to reverse the 'draw' animation but this doesn't achieve what I'm trying to accomplish.
#keyframes draw-reverse {
100% {
width: 0;
background-color: red;
}
0% {
width: 47px;
background-color: red;
}
}
I have put together this to give a better understanding of the problem;
https://jsfiddle.net/Lq560be9/
Currently, I have the line animating from left to right as desired on 'mouseenter', but on 'mouseleave' it disappears from right to left, whereas I am trying to get the line to also disappear from left to right.
But the problem isn't animation's ability it's the properties that you're animating. Instead of animating the width of an object you should animate its "X" position using translate. (this is much more performant too)
Simply put you need to MOVE the bar from left to center to right instead of trying to scale it.
(there's lots of code here to show the different states the only one you really need to follow is .ex4)
document.querySelector('#animate').addEventListener('mouseenter', function(){
this.classList.toggle('over');
})
document.querySelector('#animate').addEventListener('mouseleave',function(){
this.classList.toggle('out');
})
.example {
margin: 30px auto;
padding: 10px;
background: #dadada;
max-width: 50%;
position: relative;
}
.example:after {
content:'';
position: absolute;
width: 50%;
height: 5px;
background-color: #333;
left:0;
bottom:0;
}
.ex1:after {
transform: translateX(-100%);
}
.ex3:after {
transform: translateX(200%);
}
.ex4 {
overflow: hidden;
}
.ex4:after {
transform: translateX(-100%);
}
.ex4.over:after {
animation: animate-in 1s ease-in-out 1 normal forwards;
}
.ex4.out:after {
animation: animate-out 1s ease-in-out 1 normal forwards;
}
#keyframes animate-in {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(0);
}
}
#keyframes animate-out {
0% {
transform: translateX(0);
}
100% {
transform: translateX(200%);
}
}
<div class="example ex1">Object State 1</div>
<div class="example ex2">Object State 2</div>
<div class="example ex3">Object State 3</div>
<div id="animate" class="example ex4">Full example (hover)</div>
As a follow on from above, an alternative solution without using the translate property.
The new animation for mouseleave is;
#keyframes draw-reverse {
0% {
width: 47px;
}
25% {
width: calc(100% - 16px);
}
26% {
width: auto;
right: 8px;
left: 8px;
}
100% {
width: auto;
right: 8px;
left: calc(100% - 8px);
}
}
Full solution can be seen here - https://jsfiddle.net/1wq25tg7/

Resources