Rotate child div perpendicular to parent div in 3D space - html

html {
font-size: 0.7rem;
}
div div {
top: 5rem;
background-color: #444;
transform-origin: top center;
}
.rotate_x {
animation-name: rotate_x;
}
#keyframes rotate_x {
0% {
transform: rotateX( 0deg );
}
100% {
transform: rotateX( 360deg );
}
}
.rotate_y {
animation-name: rotate_y;
}
#keyframes rotate_y {
0% {
transform: rotateY( 0deg );
}
100% {
transform: rotateY( 180deg );
}
}
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
animation-duration: 5s;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
html, body {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
}
body {
perspective: 5rem;
}
div {
position: relative;
top: -1.5rem;
width: 5rem;
height: 5rem;
background-color: #222;
border-radius: 0.5rem;
}
</style>
<div class='rotate_y'>
<div class='rotate_x'>
</div>
</div>
The gray bottom div doesn't appear to be rotating out perpendicular to the black top div as intended. Instead the bottom gray div appears to shrink until it has a negative value and gets inverted. The desired result is for the bottom gray div to rotate up as if on a hinge; making a 'L' shape in 3D space
before it comes all the way up and flips around to do the same on the other side. As the parent div rotates 360 degrees.
How can I make the bottom div create an 'L' shape as it connects with it's parent div?

You need to set transform-style and make the perspective a bit bigger:
html {
font-size: 0.7rem;
}
div div {
top: 5rem;
background-color: #444;
transform-origin: top center;
}
.rotate_x {
animation-name: rotate_x;
}
#keyframes rotate_x {
0% {
transform: rotateX( 0deg );
}
100% {
transform: rotateX( 360deg );
}
}
.rotate_y {
animation-name: rotate_y;
transform-style:preserve-3d; /* HERE */
}
#keyframes rotate_y {
0% {
transform: rotateY( 0deg );
}
100% {
transform: rotateY( 180deg );
}
}
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
animation-duration: 5s;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
html, body {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
}
body {
perspective: 15rem;
}
div {
position: relative;
top: -1.5rem;
width: 5rem;
height: 5rem;
background-color: #222;
border-radius: 0.5rem;
}
</style>
<div class='rotate_y'>
<div class='rotate_x'>
</div>
</div>

Related

Split Animation Like 🎊 Emoji CSS

i want to make a animation for a circle that splits open on two sides:
kind of like the 🎊 emoji flipped upside down. I have two half circle elments and i put them next to each other. I tryed to animate one of the sides but its not really what im going for, i wanted the split to pivot on the bottom of the semi-circle not in the middle. Since the circle is split and right next to each other in two when you rotate one of the halfs it overlaps, i didnt attempt to fix it yet (i was think move it to the left/right over the animation but i dont know...).
.circlecontainer {
display: flex;
justify-content: center;
align-items: center;
}
.halfright {
width: 150px;
height: 300px;
border-top-right-radius: 150px;
border-bottom-right-radius: 150px;
background: orange;
}
.halfleft {
width: 150px;
height: 300px;
border-top-left-radius: 150px;
border-bottom-left-radius: 150px;
background: orange;
animation: splitleft 3s;
}
#keyframes splitleft {
0% {
transform: rotate(-0deg)
}
100% {
transform: rotate(-90deg)
}
}
<div class="circlecontainer">
<div class="halfleft"></div>
<div class="halfright"></div>
</div>
thats it! I hope this makes sense since its hard to explain...
You're looking for transform-origin
.circlecontainer {
display: flex;
justify-content: center;
align-items: center;
}
.halfright {
width: 150px;
height: 300px;
border-top-right-radius: 150px;
border-bottom-right-radius: 150px;
background: orange;
animation: splitright 3s;
transform-origin: bottom left;
}
.halfleft {
width: 150px;
height: 300px;
border-top-left-radius: 150px;
border-bottom-left-radius: 150px;
background: orange;
animation: splitleft 3s;
transform-origin: bottom right;
}
#keyframes splitleft {
0% {
transform: rotate(-0deg)
}
100% {
transform: rotate(-90deg)
}
}
#keyframes splitright {
0% {
transform: rotate(0deg)
}
100% {
transform: rotate(90deg)
}
}
<div class="circlecontainer">
<div class="halfleft"></div>
<div class="halfright"></div>
</div>
Transforms will always rotate, scale, etc. from the center of the div (by default). In this case you want to pivot from where the circles meet at the bottom, use transform-origin to do this:
.circlecontainer {
display: flex;
justify-content: center;
align-items: center;
}
.halfright {
width: 150px;
height: 300px;
border-top-right-radius: 150px;
border-bottom-right-radius: 150px;
background: orange;
transform-origin: bottom left; /* THIS ONE!! */
animation: splitright 3s forwards;
}
.halfleft {
width: 150px;
height: 300px;
border-top-left-radius: 150px;
border-bottom-left-radius: 150px;
background: orange;
transform-origin: bottom right; /* THIS ONE!! */
animation: splitleft 3s forwards;
}
#keyframes splitleft {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(-90deg);
}
}
#keyframes splitright {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(90deg);
}
}
<div class="circlecontainer">
<div class="halfleft"></div>
<div class="halfright"></div>
</div>

Is there a way that I can make the second animation not get overwritten?

So I've tried separating the animations with a comma and having them on the same transform but it still doesn't work.
* {
margin: 0px;
padding: 0px;
box-sizing: border-box;
}
html, body {
width: 100%;
height: 100%;
}
.container {
width: 100%;
height: 100%;
background: silver;
display: flex;
justify-content: center;
align-items: center;
}
.box {
width: 20%;
height: 20%;
background-color: pink;
transform: rotate(0deg) translatey(0px);
animation: wavy 3s linear infinite alternate,
float 3s linear infinite alternate;
}
#keyframes wavy {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(-10deg);
}
100% {
transform: rotate(10deg);
}
}
#keyframes float {
0% {
transform: translatey(0px);
}
50% {
transform: translatey(-20px);
}
100% {
transform: translatey(0px);
}
}
<div class="container">
<div class="box"></div>
</div>
And here's a link to the codepen:
https://codepen.io/FaroukHamadi/pen/OJOWWKW
Yes - add an id to the div and set that animation on the specified id. For your example, I called it #box
EDIT ~ the id solution I had previously worked flawlessly UNLESS there are two transforms being used in the keyframe which is your case. What I would suggest is just combining the two animations into one animation and using more % increments. So instead of 0, 50, and 100, you can use 0, 25, 50, 75, 100 - to combine the two and have it seem like they are "alternating"
* {
margin: 0px;
padding: 0px;
box-sizing: border-box;
}
html, body {
width: 100%;
height: 100%;
}
.container {
width: 100%;
height: 100%;
background: silver;
display: flex;
justify-content: center;
align-items: center;
}
.box {
width: 20%;
height: 20%;
background-color: pink;
transform: rotate(0deg) translatey(0px);
animation: wavy-float 3s linear infinite alternate;
}
#keyframes wavy-float {
0% {
transform: rotate(0deg):
}
25% {
transform: rotate(-20deg);
}
50% {
transform: translateY(-20px);
}
75% {
transform: rotate(20deg);
}
100% {
transform: translateY(20px)
}
}
<div class="container">
<div class="box"></div>
</div>

TranslateZ() is ignored for span element

The span element; the child of the div element in the snippet below is behaving unexpectedly. The span element's background-color is set to #0dd and it's transform properties are set to scale( 0.5 ) translateZ( 5rem ). The scale value is respected and shrinks the element to half size; the translateZ value however is ignored and doesn't change the position of the element.
The desired result is for the span element to be pushed forwards away from it's parent div. Why is translateZ ignored here and how can we translate span in the Z direction?
* {
box-sizing: border-box;
transform-style: preserve-3d;
margin: 0;
padding: 0;
}
html, body {
height: 100%;
}
body, span {
display: flex;
justify-content: center;
align-items: center;
}
body {
perspective: 30rem;
}
section, div, span {
position: absolute;
width: 10rem;
height: 10rem;
}
div, span {
opacity: 0.5;
background-color: #000;
}
div span {
transform: scale( 0.5 ) translateZ( 5rem );
background-color: #0dd;
}
<style>
.rotate_y {
animation-name: rotateY;
animation-duration: 10s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
#keyframes rotateY {
0% {
transform: rotateY( 0deg );
}
100% {
transform: rotateY( 360deg );
}
}
</style>
<section class='rotate_y'>
<div>
<span></span>
</div>
</section>
UPDATE: Seems to behave properly on IOS. Issue is with desktop Chrome.
The opacity seems to be the culprit but don't know why. It's probably a bug so use transparent background instead:
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
height: 100vh;
margin: 0;
perspective: 30rem;
display: flex;
justify-content: center;
align-items: center;
}
.rotate_y * {
display: block;
background-color: rgba(0,0,0,0.5);
width: 10rem;
height: 10rem;
transform-style: preserve-3d;
}
.rotate_y span {
transform: scale( 0.5) translateZ( 5rem);
background-color: rgba(0,221,221,0.5);
}
.rotate_y {
transform-style: preserve-3d;
animation-name: rotateY;
animation-duration: 10s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
#keyframes rotateY {
0% {
transform: rotateY( 0deg);
}
100% {
transform: rotateY( 360deg);
}
}
<section class='rotate_y'>
<div>
<span></span>
</div>
</section>

Why does adding opacity break 3D CSS animations?

This is my base animation. Everything here works fine unless 1 line of code is added to the div, div::before, div::after { } selector.
*, * ::before, * ::after {
transform-style: preserve-3d;
margin: 0; padding: 0;
box-sizing: border-box;
animation-duration: 10s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
html { overflow: hidden; background-color: #eee; }
html, body, main {
height: 100%;
color: #999;
font-family: Arial;
text-align: center;
text-transform: uppercase;
}
main, div, div::before, div::after {
display: flex;
justify-content: center;
align-items: center;
}
body {
perspective: 20rem;
}
div, div::before, div::after {
position: absolute;
transform-origin: center center -5rem;
width: 10rem; height: 10rem;
border-style: solid;
border-color: #ccc;
border-width: 1rem;
background-color: rgb( 221, 221, 221, 0.75 );
}
<style>
div::before {
transform: rotateX( 90deg ); content: 'top';
}
div::after {
transform: rotateX( -90deg ); content: 'bottom';
}
div > div {
transform: rotateY( 180deg );
transform-origin: center center center;
}
div > div::before {
transform: rotateY( 90deg ); content: 'right';
}
div > div::after {
transform: rotateY( -90deg ); content: 'left';
}
.rotate_y { animation-name: rotate_y; }
#keyframes rotate_y {
0% { transform: rotateY( 0deg ); } 100% { transform: rotateY( 360deg ); }
}
.rotate_x { animation-name: rotate_x; animation-duration: 200s; }
#keyframes rotate_x {
0% { transform: rotateX( 0deg ) scale( 1 ); }
100% { transform: rotateX( 360deg ) scale( -6 ); }
}
</style>
<main class='rotate_x'>
<div class='rotate_y'>
front <div>back</div>
</div>
</main>
When the following code is added all of the selected elements proceed to disappear except for the non-pseudo elements.
div, div::before, div::after {
opacity: 0.9;
}
Below is a demonstration with a comment in the CSS following the new line of code added:
*, * ::before, * ::after {
transform-style: preserve-3d;
margin: 0; padding: 0;
box-sizing: border-box;
animation-duration: 10s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
html { overflow: hidden; background-color: #eee; }
html, body, main {
height: 100%;
color: #999;
font-family: Arial;
text-align: center;
text-transform: uppercase;
}
main, div, div::before, div::after {
display: flex;
justify-content: center;
align-items: center;
}
body {
perspective: 20rem;
}
div, div::before, div::after {
position: absolute; transform-origin: center center -5rem;
width: 10rem; height: 10rem;
border-style: solid;
border-color: #ccc;
border-width: 1rem;
background-color: rgb( 221, 221, 221, 0.75 );
opacity: 0.9; /* this is the only line that has changed from the first snippet */
}
<style>
div::before {
transform: rotateX( 90deg ); content: 'top';
}
div::after {
transform: rotateX( -90deg ); content: 'bottom';
}
div > div {
transform: rotateY( 180deg );
transform-origin: center center center;
}
div > div::before {
transform: rotateY( 90deg ); content: 'right';
}
div > div::after {
transform: rotateY( -90deg ); content: 'left';
}
.rotate_y { animation-name: rotate_y; }
#keyframes rotate_y {
0% { transform: rotateY( 0deg ); } 100% { transform: rotateY( 360deg ); }
}
.rotate_x { animation-name: rotate_x; animation-duration: 200s; }
#keyframes rotate_x {
0% { transform: rotateX( 0deg ) scale( 1 ); }
100% { transform: rotateX( 360deg ) scale( -6 ); }
}
</style>
<main class='rotate_x'>
<div class='rotate_y'>
front <div>back</div>
</div>
</main>
All of the pseudo elements are gone. Also the 'front' and 'back' divs have been flattened. The whole animation breaks.
Why does this behavior occur and is it possible to implement the opacity property on a 3D CSS animation. If so; how?

CSS animation not behaving as expected

Problem
I've made a simple css animation, but it's not behaving as I expect it.
The idea is for the animation to draw a straight line (from top downwards) , and the disappear (also from the top downwards).
The start of the line moves down a bit, as the animation starts, then up again to stay at set position (same goes for the bottom at the end of the animation).
Question
How do I get the start of the line to stay at one position instead of 'bouncing' down and up?
Expected behavior
Actual behavior
Code
.lineWrapper {
width: 1px;
height: 300px;
margin: auto;
position: relative;
}
.lineWrapper .line {
width: 100%;
height: 100%;
background: #000;
animation: scrollLine 5s linear infinite;
}
#keyframes scrollLine {
0% {
transform: scaleY(0);
}
10% {
transform: scaleY(0);
transform-origin: top;
}
30% {
transform: scaleY(1);
}
70% {
transform: scaleY(1);
}
90% {
transform: scaleY(0);
transform-origin: bottom;
}
100% {
transform: scaleY(0);
}
}
<div class="lineWrapper">
<div class="line"></div>
</div>
Codepen
https://codepen.io/strazan/pen/RwPYgjq
The default transform-origin is center so if you omit it in the initial and last state it will be set to center. You need to also have an instant change of the transform-origin in the middle:
.lineWrapper {
width: 1px;
height: 300px;
margin: auto;
position: relative;
}
.line {
height: 100%;
background: #000;
animation: scrollLine 5s infinite;
}
#keyframes scrollLine {
0%,10% {
transform: scaleY(0);
transform-origin: top;
}
49.9% {
transform: scaleY(1);
transform-origin: top;
}
50% {
transform: scaleY(1);
transform-origin: bottom;
}
90%,100% {
transform: scaleY(0);
transform-origin: bottom;
}
}
<div class="lineWrapper">
<div class="line"></div>
</div>
I have made similar CSS animation with some different code lines.
body {
margin: 0px;
display: flex;
justify-content: center;
background: black;
overflow: hidden;
}
.line-wrapper {
height: 800px;
width: 8px;
background: tranparent;
display: flex;
justify-content: center;
animation: down 2s linear infinite;
}
#keyframes down {
0% {
transform: translateY(0px);
}
15% {
transform: translateY(0px);
}
30% {
transform: translateY(0px);
}
60% {
transform: translateY(90px);
}
90% {
transform: translateY(115px);
}
100% {
transform: translateY(115px);
}
}
.line {
height: 8px;
width: 4px;
background: Gray;
animation: scrollLine 2s ease-in-out infinite;
}
#keyframes scrollLine {
100% {
height: 800px;
}
}
.eraser {
height: 0px;
width: 4px;
background: black;
animation: rmv 2s linear infinite;
}
#keyframes rmv {
55% {
height: 0px;
}
100% {
height: 800px;
}
}
<div class="line-wrapper">
<div class="line">
<div class="eraser"></div>
</div>
</div>