css animation transform - keep arbitrary rotation - css

I have a CSS animation, for example, like this:
#keyframes my-animation {
0% { opacity: 0; visibility: visible; transform: scale(0,0); }
50% { transform: scale(1.15, 1.15); }
100% { transform: none; }
}
And I want to apply it to a DIV that has an arbitrary rotation e.g. like this:
<div style="width:100px; height:100px; transform: rotate(45deg)"/>
When I apply the CSS animation, keyframes have another transform attribute that only sets scale. As a result, my DIV is rotated back to 0 during the animation and, at the end, it is restored back to 45 degree rotation.
But I want it to keep its arbitrary original rotation. So the question is: is there a way to specify in transform property of the keyframes that it should keep existing (arbitrary) rotation?
Something like transform: scale(1.15, 1.15) rotate(keep) ?

Use CSS variables
.x {
transform: rotate(var(--r,0deg));
height: 50px;
width: 50px;
display:inline-block;
background: green;
animation: my-animation 5s;
margin: 20px;
}
#keyframes my-animation {
0% {
opacity: 0;
transform: scale(0) rotate(var(--r,0deg));
}
50% {
transform: scale(1.15) rotate(var(--r,0deg));
}
}
<div class="x" style="--r:80deg"></div>
<div class="x" ></div>
<div class="x" style="--r:60deg"></div>
Or like below so you can append any transformation to the one defined in the keyframes
:root {
--r: rotate(0deg); /* Use any null transform (ex: translate(0), skew(0deg), etc)*/
}
.x {
transform: var(--r);
height: 50px;
width: 50px;
display:inline-block;
background: green;
animation: my-animation 5s;
margin: 20px;
}
#keyframes my-animation {
0% {
opacity: 0;
transform: scale(0) var(--r);
}
50% {
transform: scale(1.15) var(--r);
}
}
<div class="x" style="--r:rotate(80deg) skew(20deg)"></div>
<div class="x" ></div>
<div class="x" style="--r:rotate(60deg) translate(20px,20px)"></div>

Here's a simple solution without variables - I would just wrap your div and do the scaling on the wrapper, keeping the inner div rotated arbitrarily. Trivial, but does the trick I think.
.box {
height: 50px;
width: 50px;
background: green;
margin: 50px;
}
.scale-me {
animation: my-animation;
animation-duration: 10s;
}
#keyframes my-animation {
0% {
opacity: 0;
transform: scale(0);
}
50% {
transform: scale(1.15);
}
}
<div class="scale-me">
<div class="box" style="transform: rotate(45deg)"></div>
<div class="box" style="transform: rotate(60deg)"></div>
<div class="box" style="transform: rotate(120deg)"></div>
</div>

Related

How to re-use animations in CSS at different points within the keyframes?

My intention is to make a parent square which contain four smaller child cubes. I would want an animation to have those four smaller cubes move around within the parent cube. I first make one cube and move it around like so:
.parent {
background-color: aliceblue;
height: 400px;
width: 400px;
margin: 25px;
padding: 25px;
}
.child{
background: black;
position: absolute;
height:100px;
width:100px;
animation: move_around 5s ease-in-out infinite backwards;
}
#keyframes move_around {
0% {
transform: translateX(0%);
}
25% {
transform:translateY(300%);
}
50% {
transform:translateY(300%) translateX(300%);
}
75% {
transform: translateX(300%);
}
}
<div class="parent">
<div class='child'></div>
</div>
However, my intention is to make four of those little cubes, and I want them to start at each corner. Of course I could manually add another cube by adding another child and adding a new custom animation to it, like so:
.parent {
background-color: aliceblue;
height: 400px;
width: 400px;
margin: 100px;
padding: 25px;
}
.child{
background: black;
position: absolute;
height:100px;
width:100px;
}
.top {
animation: move_around 5s ease-in-out infinite backwards
}
.bot {
animation: move_around_bot 5s ease-in-out infinite backwards
}
#keyframes move_around {
0% {
transform: translateX(0%);
}
25% {
transform:translateY(300%);
}
50% {
transform:translateY(300%) translateX(300%);
}
75% {
transform: translateX(300%);
}
}
#keyframes move_around_bot {
0% {
transform:translateY(300%) translateX(300%);
}
25% {
transform: translateY(0%) translateX(300%);
}
50% {
transform: translateY(0%) translateX(0%)
}
75% {
transform: translateX(0%) translateY(300%);
}
100% {
transform:translateY(300%) translateX(300%);
}
}
<div class="parent">
<div class='child top'></div>
<div class='child bot'></div>
</div>
However, this does not seem like the best way. Now I have two, with more then double the amount of lines. Would it need double again the amount of lines for four cubes? What if I want even more cubes? My approach does not seem very usable in this way.
I realized that the second cube here is identical to the first cube, except that its animation is basically 50% of the frames 'ahead'. Is there a way to add a 3rd, 4th or Nth cube that are 25%, 75% or X% of the frames 'ahead'?
You could use animation-delay: -1.25s for the second cube, -2.5s for the third and -3.75s for the last one.
You could make something like:
.parent img:nth-child(1){
animation-delay: 0s; /* change this to something else for each */
}
To change the animation-delay, change the seconds u start at, and to change the specific cube you want, change the parameter at the top to something like:
.parent img:nth-child(2){
Yes. animation-delay will work.
.parent {
background-color: aliceblue;
height: 400px;
width: 400px;
margin: 25px;
padding: 25px;
}
.parent .child:nth-child(1){
animation-delay: 0s;
}
.parent .child:nth-child(2){
animation-delay: -1.25s;
}
.parent .child:nth-child(3){
animation-delay: -2.5s;
}
.parent .child:nth-child(4){
animation-delay: -3.75s;
}
.child{
background: black;
position: absolute;
height:100px;
width:100px;
animation: move_around 5s ease-in-out infinite backwards;
}
#keyframes move_around {
0% {
transform: translateX(0%);
}
25% {
transform:translateY(300%);
}
50% {
transform:translateY(300%) translateX(300%);
}
75% {
transform: translateX(300%);
}
}
<div class="parent">
<div class='child'></div>
<div class='child'></div>
<div class='child'></div>
<div class='child'></div>
</div>

Make an image spin, and as it spins over a div, change it's color... maybe with a mask?

I have a circle logo, with text on the outside, and a small circle in the middle. I plan to make the logo spin using some CSS3. That's relatively easily.
The tricky bit is that I want to make the logo change to BLACK when it's over a pink div, and change to WHITE as it moves over the black part...
I think this is achieved with a mask or a filter, but I just cannot work out how to do it...
I've setup a codepen with a basic example:
https://codepen.io/anon/pen/JQYQdp
<div class="main-header">
<div class="spinning">
<img src="https://i.ibb.co/pKVwqhY/test-logo.png" alt="test-logo" border="0">
</div>
</div>
<div class="pink">
</div>
CSS:
.main-header {
width:100%;
background-color:black;
height:200px;
}
.pink {
width:100%;
background-color:pink;
height:200px;
}
.spinning {
position:absolute;
z-index:2000;
height:200px;
width:200px;
top:100px;
right:0;
-webkit-animation:spin 4s linear infinite;
-moz-animation:spin 4s linear infinite;
animation:spin 4s linear infinite;
}
#-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } }
#-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }
#keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }
As the text of the image spins over the PINK background, I want that part of the text to be black, whilst the top half is still white...
mix-blend-mode will get you most of the way.
The mix-blend-mode CSS property sets how an element's content should blend with the content of the element's parent and the element's background.
MDN
.main-header {
width: 100%;
background-color: black;
height: 200px;
}
.pink {
width: 100%;
background-color: pink;
height: 200px;
}
.spinning {
mix-blend-mode: difference;
position: absolute;
z-index: 2000;
height: 200px;
width: 200px;
top: 100px;
right: 10px;
-webkit-animation: spin 4s linear infinite;
-moz-animation: spin 4s linear infinite;
animation: spin 4s linear infinite;
}
#-moz-keyframes spin {
100% {
-moz-transform: rotate(360deg);
}
}
#-webkit-keyframes spin {
100% {
-webkit-transform: rotate(360deg);
}
}
#keyframes spin {
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
<div class="main-header">
<div class="spinning">
<img src="https://i.ibb.co/pKVwqhY/test-logo.png" alt="test-logo" border="0">
</div>
</div>
<div class="pink">
</div>

How does rotation combined with translation work inside CSS animation?

I saw this animation on codepen, and I don't know why it's written this way to have this effect, but I think it's going to have the effect of rotating 360deg clockwise, 360deg counterclockwise, instead of bouncing up and down or left and right
I'm particularly puzzled with these Keyframe animation
#keyframes move{
from {
transform: rotate(360deg) translateX(1.125em) rotate(-360deg);
}
to {
transform: rotate(-360deg) translateX(1.125em) rotate(360deg);
}
}
Results the following
https://i.stack.imgur.com/9oWnw.gif
From the specification we can see how the broswer should deal with interpolation between transform values. In this case we use this:
If from- and to-transform have the same number of transform functions,
each transform function pair has either the same name, or is a
derivative of the same primitive: Interpolate each transform function
pair as described in Interpolation of transform functions. The
computed value is the resulting transform function list.
So the browser will change the first rotate from 360deg to -360deg and the same for the last rotate while translateX will kept the same. We will then have the following steps:
transform: rotate(360deg) translateX(1.125em) rotate(-360deg);
transform: rotate(350deg) translateX(1.125em) rotate(-350deg);
transform: rotate(340deg) translateX(1.125em) rotate(-340deg);
....
transform: rotate(0) translateX(1.125em) rotate(0);
....
....
transform: rotate(-360deg) translateX(1.125em) rotate(360deg);
Now we need to understand how rotate(-adeg) translateX(b) rotate(adeg) works. First you may notice that the rotation won't have any visual effect on the element since we deal with a circle, it will simply affect how the translation will work and more precisely it's the first rotation that is important (the one in the left).
.container {
width: 50px;
height: 50px;
margin: 50px;
border:2px solid;
}
.box {
width: 50px;
height: 50px;
background: red;
border-radius: 50%;
animation: move 2s linear infinite;
}
.alt {
animation: move-alt 2s linear infinite;
}
#keyframes move {
from {
transform: rotate(360deg) translateX(1.125em) rotate(-360deg);
}
to {
transform: rotate(-360deg) translateX(1.125em) rotate(360deg);
}
}
#keyframes move-alt {
from {
transform: rotate(360deg) translateX(1.125em);
}
to {
transform: rotate(-360deg) translateX(1.125em);
}
}
<div class="container">
<div class="box">
</div>
</div>
<div class="container">
<div class="box alt">
</div>
</div>
As you can see both animation are equivalent visually.
Now the effect is as follow: each time we rotate the X-axis and then we translate our element consider the new rotated axis. It's like we rotate the coordinate system then we translate OR its like we do the translation once (since it's the same) then we keep rotating the coordinate system thus we have a rotation at the end.
Now if we consider the opposite transform nothing will happen visually:
.container {
width: 50px;
height: 50px;
margin: 50px;
border: 2px solid;
}
.box {
width: 50px;
height: 50px;
background: red;
border-radius: 50%;
animation: move 2s linear infinite;
}
#keyframes move {
from {
transform: translateX(1.125em) rotate(-360deg);
}
to {
transform: translateX(1.125em) rotate(360deg);
}
}
<div class="container">
<div class="box">
</div>
</div>
In this case we translate the coordinate system by the same translation then we rotate our circle. If we change it to a square we will see the effect
.container {
width: 50px;
height: 50px;
margin: 50px;
border: 2px solid;
}
.box {
width: 50px;
height: 50px;
background: red;
animation: move 2s linear infinite;
}
#keyframes move {
from {
transform: translateX(1.125em) rotate(-360deg);
}
to {
transform: translateX(1.125em) rotate(360deg);
}
}
<div class="container">
<div class="box">
</div>
</div>
And here is how your initial animation will look with a square:
.container {
width: 50px;
height: 50px;
margin: 50px;
border: 2px solid;
}
.box {
width: 50px;
height: 50px;
background: red;
animation: move 2s linear infinite;
}
#keyframes move {
from {
transform:rotate(360deg) translateX(1.125em) rotate(-360deg);
}
to {
transform:rotate(-360deg) translateX(1.125em) rotate(360deg);
}
}
<div class="container">
<div class="box">
</div>
</div>
We rotate the coordinate system, we translate our element then we rotate the element so it's like we rotate our the element inside a bigger one that is also rotating in the opposite direction.
If you change the timing function to something else than linear you will have the same rotation but it won't be linear, it will be slower/faster in some interval:
.container {
width: 50px;
height: 50px;
margin: 50px;
border: 2px solid;
}
.box {
width: 50px;
height: 50px;
background: red;
animation: move 2s ease-in-out infinite;
}
#keyframes move {
from {
transform:rotate(360deg) translateX(1.125em) rotate(-360deg);
}
to {
transform:rotate(-360deg) translateX(1.125em) rotate(360deg);
}
}
<div class="container">
<div class="box">
</div>
</div>
This is a simplified explanation, you may check this answer if you want more details about how we deal with multiple function inside transform and how the order is important: Simulating transform-origin using translate

CSS slider with arrows using animation

I am trying to achieve a CSS only slider.
When hovering left and right arrows, the slider has to slide. Of course.
I tried something using animation-play-state, animation-fill-mode (to keep the positions) and animation-direction but I'm not able to fully make it work.
Starting with animation-play-state: paused, hovering the arrows changes it to running.
On hover of the right arrow, everything is fine. We can hover, leave, hover again.
But, as soon as I hover the left arrow (that changes the animation-direction to reverse), it's broken.
Simplified snippet:
.wrapper {
overflow: hidden;
position: relative;
width: 500px;
}
.arrows {
z-index: 2;
position: absolute;
top: 0;
height: 100%;
background: #ddd;
opacity: 0.66;
}
.arrows:hover {
opacity: 1;
}
.arrow-l {
left: 0;
}
.arrow-r {
right: 0;
}
.sliding {
height: 160px;
width: 2000px;
background: linear-gradient(to bottom right, transparent 49.9%, gray 50.1%);
animation: slide 2s linear;
animation-play-state: paused;
animation-fill-mode: both;
}
.arrows:hover~.sliding {
animation-play-state: running;
}
.arrow-l:hover~.sliding {
animation-direction: reverse;
}
#keyframes slide {
0% {
transform: translate(0px, 0);
}
100% {
transform: translate(-1500px, 0);
}
}
<div class="wrapper">
<div class="arrows arrow-l">[ ← ]</div>
<div class="arrows arrow-r">[ → ]</div>
<div class="sliding"></div>
</div>
Can someone help me understand what is happening, and correct this unwanted behaviour?
The main issue here is that changing the direction will keep the current state of the animation BUT it will consider the new direction. Let's take an easy example:
Suppose you have an animation from left:0 to left:100%. If you first run the animation untill left:80% and then you change the direction to reverse you will have left:20%!
Why?
Because with the default direction you reached the 80% (left:80%) of the animation and 80% of the same animation with reverse direction is simply left:20%.
Hover on reverse and you will see that the position of the box is jumping to switch to the new state considering the new direction. It's obvious when the animation ends and you will be switching between the first and last state:
.sliding {
width:100px;
height:100px;
background:red;
left:0%;
position:relative;
animation:slide 5s linear forwards;
animation-play-state:paused;
}
.arrows {
margin:20px;
}
.arrow-r:hover~.sliding {
animation-play-state: running;
}
.arrow-l:hover~.sliding {
animation-direction: reverse;
}
#keyframes slide {
0% {
left: 0%;
}
100% {
left: 100%;
}
}
<div class="wrapper">
<div class="arrows arrow-r">move normal</div>
<div class="arrows arrow-l">reverse !!</div>
<div class="sliding"></div>
</div>
There is no fix for this since it's the default behavior of animation, but instead you can rely on transition to obtain a similar effect. The trick is to play with the duration that you increase/decrease to create the needed effect.
Here is an idea:
.wrapper {
overflow: hidden;
position: relative;
width: 500px;
}
.arrows {
z-index: 2;
position: absolute;
top: 0;
height: 100%;
background: #ddd;
opacity: 0.66;
}
.arrows:hover {
opacity: 1;
}
.arrow-l {
left: 0;
}
.arrow-r {
right: 0;
}
.sliding {
height: 160px;
width: 2000px;
background: linear-gradient(to bottom right, transparent 49.9%, gray 50.1%);
transition:all 2000s linear; /*This will block the current state*/
}
.arrow-r:hover ~ .sliding {
transform: translate(-1500px, 0);
transition:all 2s;
}
.arrow-l:hover ~ .sliding {
transform: translate(0px, 0);
transition:all 2s;
}
<div class="wrapper">
<div class="arrows arrow-l">[ ← ]</div>
<div class="arrows arrow-r">[ → ]</div>
<div class="sliding"></div>
</div>

Zoom-in Zoom-out img automatically using css only

I have a working demo. just hover the img and there is the effect I want to have.
http://jsfiddle.net/jxgjhzer/1/
As you can see in css file, I don't use any css animation.
Just using CSS transform, I want my img to achieve same effect without hovering it. It should happen automatically.
So how to zoom-in and zoom-out automatically (without animation if possible)?
Code goes here:
.galleryImg{
height:150px;
width:100%;
transform-origin: 50% 50%;
transition: transform 30s linear;
}
.galleryImg:hover{
transform: scale(2) rotate(0.1deg);
}
that's very simple. you can see DEMO on this link on jsfiddle.net
<div class="cardcontainer">
<img class="galleryImg" src="https://www.google.com/logos/doodles/2014/2014-winter-olympics-5710368030588928-hp.jpg">
</div>
#keyframes zoominoutsinglefeatured {
0% {
transform: scale(1,1);
}
50% {
transform: scale(1.2,1.2);
}
100% {
transform: scale(1,1);
}
}
.cardcontainer img {
animation: zoominoutsinglefeatured 1s infinite ;
}
use animation
.galleryImg{
height:150px;
width:100%;
animation:move 3s infinite ease-in-out;
}
#keyframes move{
0%{
transform: scale(1) rotate(0deg);
}
100%{
transform: scale(2) rotate(0.1deg);
}
}
The below css code will help you out for zoom out effect on hover the particular image. Try this code its very useful to you
figure {
width: 300px;
height: 200px;
margin: 0;
padding: 0;
background: #fff;
overflow: hidden;
}
figure:hover+span {
bottom: -36px;
opacity: 1;
}
.hover04 figure img {
width: 400px;
height: auto;
-webkit-transition: .3s ease-in-out;
transition: .3s ease-in-out;
}
.hover04 figure:hover img {
width: 300px;
}
Refer the html code here.
<div class="hover04 column">
<div>
<figure><img src="1.jpeg" /></figure>
<span>Hover Text</span>
</div>
</div>

Resources