Matrix 3d transform for obtaining trapezoid? - css

I try to simulate a turn to back effect, as two doors open to back simultaneously. I tried different matrix generators to obtain that trapezoid needed but i didn't have any luck. I know i have to animate an rotateY from 0 to 180 degrees and to keep my transform origin but that trapezoid kills me.

How about using perspective?
demo
HTML:
<div class='doors'>
<div class='door'></div><div class='door'></div>
</div>
Relevant CSS:
.doors { perspective: 35em; }
.door {
display: inline-block;
width: 50%; height: 100%;
transition: 1s;
}
.doors:hover .door:first-child {
transform-origin: 0 50% 0;
transform: rotateY(60deg);
}
.doors:hover .door:last-child {
transform-origin: 100% 50% 0;
transform: rotateY(-60deg);
}

Related

CSS: Changing width/height after rotation in one direction only

My end goal is a draggable, resizable, Scalable, and rotatable element, just like the example on: https://daybrush.com/moveable/ only by using css width,height, and transform: rotate, translate.
Say I have a div with following css:
.rect {
background-color: red;
width: 200px;
height: 100px;
top:100px;
left:100px;
position: absolute;
transform: rotate(0deg);
}
<div class="rect"></div>
If I want to resize the div horizontally to the left, I just change the width by x pixels. If I want to change it to the right I just change the width by x pixels, and translate(-xpx, 0).
But what if I change the angle? From trying a lot of stuff, I found some of the x and y values for translate to the respective angle, however I feel like there is a more straight forward way than just guessing. E.g: For 90deg, if I want to resize to the left by x px I do translate(-x0.5px, x0.5px).
More: what if I want to change both the width & height at the same time?
P.S.: I would rather avoid using libraries, transform: scale or svg
P.P.S:Example to further demonstrate the problem, just changing the width:
.rect {
background-color: red;
width: 200px;
height: 100px;
top:100px;
left:100px;
position: absolute;
transform: rotate(45deg);
animation: expand 5s infinite
}
#keyframes expand {
from {width: 200px;}
to {width: 2000px;}
}
<div class="rect"></div>
Fixed, stretching the left side of the original rectagle (now up since rotated 90deg):
.rect {
background-color: red;
width: 200px;
height: 100px;
top:100px;
left:100px;
position: absolute;
transform: rotate(90deg);
animation: expand 3s infinite
}
#keyframes expand {
from {
width: 200px;
}
to {
width: 800px;
transform: rotate(90deg) translate(-300px, 300px);
}
}
<div class="rect"></div>
You can apply several transformations to the same object and they will be composed in the order that you specify. Move then rotate, is different than rotate then move.
.rect {
background-color: red;
width: 200px;
height: 100px;
top:100px;
left:100px;
position: absolute;
}
.t1 {
background-color: #40d04080;
/* green shaded rectangle: rotate after translation */
transform: translate(2cm, 0) rotate(30deg);
}
.t2 {
background-color: #f0404080;
transform: rotate(30deg);
}
.t3 {
background-color: #4040f080;
/* blue shaded rectangle: translate after rotation */
transform: rotate(30deg) translate(2cm, 0) ;
}
<div class="rect t1"></div>
<div class="rect t2"></div>
<div class="rect t3"></div>

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>

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/

How to avoid sharp jumps between speeds in css animation

I need to create infinite animation that will start with fast rotation ( e.g. 1 second) then gradually slow down (within another e.g. 1 second) and then continue on the very slow speed (for the remaining e.g. 8 seconds). The problem is - rotation speed changes with very sharp jumps - on 10% and 20%.
Can I control transition between animation speeds? I tried to override speed jump by adding more percentages but it just gives second jump after 20% when speed changes.
html {
height: 100%;
}
body {
height: 100%;
background: #333;
display: flex;
align-items: center;
justify-content: center;
}
.bar {
background: cyan;
width: 100px;
height: 10px;
}
.bar {
animation: rotation 10s linear infinite;
}
#keyframes rotation {
0% {
transform: rotate(0deg);
}
10% {
transform: rotate(1600deg);
}
11% {
transform: rotate(1620deg);
}
12% {
transform: rotate(1640deg);
}
13% {
transform: rotate(1660deg);
}
14% {
transform: rotate(1680deg);
}
15% {
transform: rotate(1700deg);
}
16% {
transform: rotate(1720deg);
}
17% {
transform: rotate(1740deg);
}
18% {
transform: rotate(1760deg);
}
19% {
transform: rotate(1800deg);
}
20% {
transform: rotate(1820deg);
}
100% {
transform: rotate(2160deg);
}
}
<div class="bar"></div>
You can use multiple animations: one for the initial spin with deceleration (take a look at the easing functions. In this case I'm using ease-out which mimics basic deceleration) and a second (delayed to run after the first finishes) to be linear. You'll have to play around with the values of degrees and duration to match the speed of rotation from the first animation with the linear speed of the second, otherwise you'll see the speed jump quickly (your problem in the first place). Here's an example:
html {
height: 100%;
}
body {
height: 100%;
background: #333;
display: flex;
align-items: center;
justify-content: center;
}
.bar {
background: cyan;
width: 100px;
height: 10px;
}
.bar {
animation: rotationDecelerate 2s ease-out, rotationLinear 2s linear 2s infinite;
}
#keyframes rotationDecelerate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(2160deg);
}
}
#keyframes rotationLinear {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
<div class="bar"></div>
It's just a matter of fiddling with the numbers.
I removed all the intermediate transformations between 10 and 20%. The animation calculates the position of the element based on timing functions and the sort between the two points.
The reason why you were getting a big jump is that you were trying to control every intermediate step between 10 and 20 but the animation had to be at a certain point at 20%. Let the browser control everything between 10 and 20% since you want a smooth slowdown. The timing function takes into account where you started and where you want to end, so it tries to smooth everything out for you. The more defined every percentage point is, the more stilted the animation will be.
I also played around with the values a little bit. You can put them back how you want them, but I just wanted to see how it would affect the animation if the first sec was 5 rotations, then the next second was 1 rotation, and then last 80% was one rotation. It just seemed proportional to me, and the animation looked smoother. But, I recommend playing with the degrees until you get what you want.
html {
height: 100%;
}
body {
height: 100%;
background: #333;
display: flex;
align-items: center;
justify-content: center;
}
.bar {
background: cyan;
width: 100px;
height: 10px;
}
.bar {
animation: rotation 10s linear infinite;
}
#keyframes rotation {
0% {
transform: rotate(0deg);
}
10% {
transform: rotate(1800deg);
}
20% {
transform: rotate(2160deg);
}
100% {
transform: rotate(2520deg);
}
}
<div class="bar"></div>

Rotate 45-degree element around vertical axis

I've got a series of elements, as shown in the image below:
They are rotated 45 degrees to one side (the content inside -45 degrees, to remain upright).
Now I'd like to rotate each element around a vertical axis, going through the element's center. RotateY doesn't work, as it is at a 45-degree angle.
How would you go about doing this?
The trick is to set this rotation before the 45 degrees rotation:
Notice also that to make the rotation behave really as expect, you need to set it to 0 in the base state
.container {
width: 200px;
height: 200px;
margin: 100px;
border: solid 1px;
transform: rotateY(0deg) rotate(45deg); /* needs Y at 0 deg to behave properly*/
transition: transform 2s;
}
.container:hover {
transform: rotateY(180deg) rotate(45deg); /* notice the order */
}
.inner {
margin: 50px;
transform: rotate(-45deg);
}
<div class="container">
<div class="inner">INNER</div>
</div>
This is how I interpret the question. I'm not very happy with the demo since it needs a lot of structure.
But maybe you can verify the behavior?
Basically I use a wrapper to rotate on the y-axis.
It is key to set the transform origin to the center.
The additional wrapper is used to prevent a flickering on mouse hover.
https://jsfiddle.net/nm59mqky/1/
.tile {
transform: rotateY(0);
transform-origin: center center;
}
.wrapper:hover .tile {
transform: rotateY(180deg);
}
I dont know exactly what your code looks like, but for a simple spinning tile (div) i would try something like this:
#keyframes rotate-vertical {
0% {
transform: rotate3d(0, 1, 0, 0deg);
}
100% {
transform: rotate3d(0, 1, 0, 360deg);
}
}
body {
padding: 20px;
}
.tile {
width: 65px;
height: 65px;
background-color: red;
text-align: center;
transform: rotate3d(0, 0, 1, 45deg);
display: inline-block;
}
.turndiv {
width: 65px;
}
.turndiv:hover {
animation: rotate-vertical 1.1s ease-out;
}
<div class="turndiv">
<div class="tile">
</div>
</div>
You could just do it with transform: rotate3d(); and without a parent div, but to keep it easy i did it like this.

Resources