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>
Related
I have an element that rotates, and inside of it I have .pop-out-item. This has translateZ(500px) on it.
When the rotating element (.rotator--child) spins, the .pop-out-item stays "attached" to the rotating div (see code snippet)
#keyframes spin {
0% {
transform: rotateY(0deg);
}
100% {
transform: rotateY(360deg);
}
}
.rotator {
position: relative;
perspective: 500px;
}
.rotator--element {
display: block;
width: 300px;
background: red;
aspect-ratio: 1/ 1;
animation: spin 10s infinite;
}
.pop-out-item{
width: 50px;
aspect-ratio: 1 / 1;
background: orange;
transform: translateZ(500px);
transform-style: preserve-3d;
}
body{
padding: 60px;
}
<div class="rotator">
<div class="rotator--element">
<div class="pop-out-item"></div>
</div>
</div>
I expect it to look different, something like this:
Sorry for terrible drawing.
What am I doing wrong? Thanks.
I assume what you want is for the orange square to move with the red one, but translated. I moved the transform-style: preserve-3d to the red rotator--element and made the translateZ value 50px as it's easier to see that way. As the transform-style MDN documentation states:
The transform-style CSS property sets whether children of an element are positioned in the 3D space or are flattened in the plane of the element.
#keyframes spin {
0% {
transform: rotateY(0deg);
}
100% {
transform: rotateY(360deg);
}
}
.rotator {
position: relative;
perspective: 500px;
}
.rotator--element {
display: block;
width: 300px;
background: red;
aspect-ratio: 1/ 1;
animation: spin 10s infinite;
transform-style: preserve-3d;
}
.pop-out-item{
width: 50px;
aspect-ratio: 1 / 1;
background: orange;
transform: translateZ(50px);
}
body{
padding: 60px;
}
<div class="rotator">
<div class="rotator--element">
<div class="pop-out-item"></div>
</div>
</div>
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>
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?
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>
I'm trying to center something horizontally and vertically using flexbox as described Here ( click "Both Horizontally and Vertically" => then click "Can you use flexbox?")
.parent_test {
display: flex;
justify-content: center;
align-items: center;
}
.sk-double-bounce {
width: 40px;
height: 40px;
position: relative;
}
.sk-double-bounce .sk-child {
width: 100%;
height: 100%;
border-radius: 20%;
background-color: green;
position: absolute;
top: 0;
left: 0;
-webkit-animation: sk-doubleBounce 2s infinite ease-in-out;
animation: sk-doubleBounce 2s infinite ease-in-out; }
.sk-double-bounce .sk-double-bounce2 {
-webkit-animation-delay: -1.0s;
animation-delay: -1.0s; }
#-webkit-keyframes sk-doubleBounce {
0%, 100% {
-webkit-transform: scale(0);
transform: scale(0); }
50% {
-webkit-transform: scale(1);
transform: scale(1); } }
#keyframes sk-doubleBounce {
0%, 100% {
-webkit-transform: scale(0);
transform: scale(0); }
50% {
-webkit-transform: scale(1);
transform: scale(1); } }
<h1>centering-css-complete-guide/#both-flexbox
<div class="parent_test">
<div class="sk-double-bounce">
<div class="sk-child sk-double-bounce1"></div>
<div class="sk-child sk-double-bounce2"></div>
</div>
</div>
But why isn't it centering vertically? JSBin
you need to specify a height for parent, in order to make it vertically aligned.
body {
margin: 0
}
.parent_test {
display: flex;
justify-content: center;
align-items: center;
height: 100vh
}
.sk-double-bounce {
width: 40px;
height: 40px;
position: relative;
}
.sk-double-bounce .sk-child {
width: 100%;
height: 100%;
border-radius: 20%;
background-color: green;
position: absolute;
top: 0;
left: 0;
-webkit-animation: sk-doubleBounce 2s infinite ease-in-out;
animation: sk-doubleBounce 2s infinite ease-in-out;
}
.sk-double-bounce .sk-double-bounce2 {
-webkit-animation-delay: -1.0s;
animation-delay: -1.0s;
}
#-webkit-keyframes sk-doubleBounce {
0%, 100% {
-webkit-transform: scale(0);
transform: scale(0);
}
50% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
#keyframes sk-doubleBounce {
0%, 100% {
-webkit-transform: scale(0);
transform: scale(0);
}
50% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
<div class="parent_test">
<div class="sk-double-bounce">
<div class="sk-child sk-double-bounce1"></div>
<div class="sk-child sk-double-bounce2"></div>
</div>
</div>
If you inspect the output, you'll see .sk-double-bounce is actually centered within .parent_test. The problem is that .parent_test has way lesser height. ( It only takes the amount of height required by it's content plus padding and border values).
You can now understand why the solution by #dippas works. If you want, you could remove the .parent_test wrapper, put flex rules in body, set body's height to 100vh and then put .sk-double-bounce div directly inside body. That would do the same job.