I have this cube that I rotate it so I would look trough it's diagonal. How could I rotate this cube around this particular diagonal? I tried different rotations but nothing seems to fit me.
I am looking for CSS only solution/explenation.
.container {
width: 200px;
height: 200px;
position: absolute;
perspective: 10000px;
left: 50vw;
top: 50vh;
transform: translateX(-50%) translateY(-50%);
}
.cube {
width: 100%;
height: 100%;
position: absolute;
transform-style: preserve-3d;
}
.cube figure {
margin: 0;
width: 100%;
height: 100%;
display: block;
position: absolute;
border: 2px solid black;
box-sizing: border-box;
}
.cube .front {
transform: rotateY(0deg) translateZ(100px);
}
.cube .back {
transform: rotateX(180deg) translateZ(100px);
}
.cube .right {
transform: rotateY(90deg) translateZ(100px);
}
.cube .left {
transform: rotateY(-90deg) translateZ(100px);
}
.cube .top {
transform: rotateX(90deg) translateZ(100px);
}
.cube .bottom {
transform: rotateX(-90deg) translateZ(100px);
}
.cube {
transform: rotateY(35deg) rotateX(45deg);
}
.cube:hover {
transition: all 1s;
transform: rotateY(35deg) rotateX(45deg);
}
<section class="container">
<div class="cube">
<figure class="front"></figure>
<figure class="back"></figure>
<figure class="right"></figure>
<figure class="left"></figure>
<figure class="top"></figure>
<figure class="bottom"></figure>
</div>
</section>
Found it - this solved my problem (hover over cube).
Explanation: the transform stack is evaluated from right to left. So, if we want to rotate an element that is transformed around the z axis, we need to set this transform the first one.
If the original is
transform: translateX(-50%) translateY(-50%);
then
transform: rotateZ(value) translateX(-50%) translateY(-50%);
will rotate the element around the viewer z axis (the desired effect)
transform: translateX(-50%) translateY(-50%) rotateZ(value);
would rotate the element around its Z axis
.container {
width: 200px;
height: 200px;
position: absolute;
perspective: 10000px;
left: 50vw;
top: 50vh;
transform: translateX(-50%) translateY(-50%);
}
.cube {
width: 100%;
height: 100%;
position: absolute;
transform-style: preserve-3d;
}
.cube figure {
margin: 0;
width: 100%;
height: 100%;
display: block;
position: absolute;
border: 2px solid black;
box-sizing: border-box;
}
.cube .front { transform: rotateY( 0deg ) translateZ( 100px ); }
.cube .back { transform: rotateX( 180deg ) translateZ( 100px ); }
.cube .right { transform: rotateY( 90deg ) translateZ( 100px ); }
.cube .left { transform: rotateY( -90deg ) translateZ( 100px ); }
.cube .top { transform: rotateX( 90deg ) translateZ( 100px ); }
.cube .bottom { transform: rotateX( -90deg ) translateZ( 100px ); }
.cube {
transform: rotateY(35deg) rotateX(45deg);
}
.cube:hover {
transition: all 1s;
transform:rotateZ(60deg) rotateY(35deg) rotateX(45deg);
}
<section class="container">
<div class="cube">
<figure class="front"></figure>
<figure class="back"></figure>
<figure class="right"></figure>
<figure class="left"></figure>
<figure class="top"></figure>
<figure class="bottom"></figure>
</div>
</section>
Related
I am trying to rotate a cube with keyframes so it keeps rotating in the same direction with no rotation backwards and keeps rotating horizontally in one direction without reverse on infinite.
<div class="cube">
<div class="cube-face front"></div>
<div class="cube-face back"></div>
<div class="cube-face right"></div>
<div class="cube-face left"></div>
<div class="cube-face top"></div>
<div class="cube-face bottom"></div>
</div>
CSS degrees run over 360 and don't seem to stop... As you can see with the current keyframes the cube will rotate backwards, is there a solution to keep it going with CSS?
.cube {
width: 250px;
height: 250px;
position: relative;
transform-style: preserve-3d;
transform: rotateX(315deg) rotateY(-45deg);
animation: rotate-cube 5s infinite;
margin-bottom: 50px;
cursor: pointer;
}
.cube-face {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
width: 250px;
height: 250px;
border: 2px solid black;
font-size: 90px !important;
font-weight: bold;
color: #000;
}
.cube .front {
background: #f15d2a;
transform: rotateY(0deg) translateZ(125px);
}
.cube .right {
background: #0063a6;
transform: rotateY(90deg) translateZ(125px);
}
.cube .back {
background: #ed1652;
transform: rotate(0deg) rotateY(180deg) translateZ(125px);
}
.cube .left {
background: #12b259;
transform: rotateX(0) rotateY(-90deg) translateZ(125px);
}
.cube .top {
background: #fff;
transform: rotateY(0deg) rotateX(90deg) translateZ(125px);
}
.cube .bottom {
background: #ffd54c;
transform: rotatey(90deg) rotateX(-90deg) translateZ(125px);
}
#keyframes rotate-cube {
0% {
transform: rotateX(315deg) rotateY(-45deg);
}
33.33% {
transform: rotateX(315deg) rotateY(-135deg);
}
66.66% {
transform: rotateX(315deg) rotateY(-225deg);
}
100% {
transform: rotateX(315deg) rotateY(-45deg);
}
}
See example on codepen
Assuming you want the end and start to have the same rotation, you can set the final rotation to -405deg (360 + 45).
This should make sure the animation continues in the correct direction.
0% {
transform: rotateX(315deg) rotateY(-45deg);
}
33.33% {
transform: rotateX(315deg) rotateY(-135deg);
}
66.66% {
transform: rotateX(315deg) rotateY(-225deg);
}
100% {
transform: rotateX(315deg) rotateY(-405deg);
}
I wanna create brochure which open to the left and the right when someone hover over it.
I use transform-origin: 0% and transform: rotateY(-180deg) for the left site of the brochure to open to the left site (Card red and blue). For the right side I use of course transform-origin: 100% and transform: rotateY(180deg) to open to the right site (Card green).
But the actual behavior of the right side is, that it applies transform-origin: 0% and rotates behind the left site of the brochure (Thats why you can't see it, but its there).
I can't understand why transform-origin: 100% don't take affect.
here is the code: https://jsfiddle.net/eL6q3hp4/2/
.book-container {
height: 350px;
width: 250px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
-webkit-perspective: 1000px;
-moz-perspective: 1000px;
perspective: 1000px;
}
.book-part {
height: auto;
width: auto;
position: absolute;
transform-style: preserve-3d;
top: 0;
left: 0;
}
.book-part > .card {
height: 350px;
width: 250px;
position: absolute;
transform-style: preserve-3d;
backface-visibility: hidden;
}
/* RIGHT SITE */
.right-part {
transform-origin: 0%;
}
.right-card {
transform: rotateY(-180deg);
}
.book-container:hover .right-part {
transform: rotateY(180deg);
transition: 0.7s;
transition-delay: 0.3s;
}
/* LEFT SITE */
.left-part {
transform-origin: 100%;
}
.left-card {
transform: rotateY(180deg);
}
.book-container:hover .left-part {
transform: rotateY(-180deg);
transition: 0.7s;
}
.middle-card {
background-color: blue;
}
.right-card {
background-color: green;
}
.left-card {
background-color: red;
}
.front-card {
background-color: yellow;
}
<div class="book-container">
<div class="book-part middle-part">
<div class="card middle-card"></div>
</div>
<div class="book-part right-part">
<div class="card right-card"></div>
</div>
<div class="book-part left-part">
<div class="card left-card"></div>
<div class="card front-card"></div>
</div>
</div>
Remove absolute position from .book-part and invert the rotation values. You can also add a front card to the right block
I also added transition to the closing effect:
.book-container {
height: 350px;
width: 250px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
perspective: 1000px;
}
.book-part {
transform-style: preserve-3d;
}
.book-part>.card {
height: 350px;
width: 250px;
position: absolute;
transform-style: preserve-3d;
backface-visibility: hidden;
}
/* RIGHT SITE */
.right-part {
transform-origin: 0%;
transition: 0.7s;
}
.right-card {
transform: rotateY(180deg);
}
.book-container:hover .right-part {
transform: rotateY(-180deg);
transition-delay: 0.3s;
}
/* LEFT SITE */
.left-part {
transform-origin: 100%;
transition: 0.7s;
transition-delay: 0.3s;
}
.left-card {
transform: rotateY(-180deg);
}
.book-container:hover .left-part {
transform: rotateY(180deg);
transition-delay: 0s;
}
<div class="book-container">
<div class="book-part middle-part">
<div class="card middle-card" style="background:blue"></div>
</div>
<div class="book-part right-part">
<img class="card right-card" style="background:green">
<img class="card front-card" style="background:pink;">
</div>
<div class="book-part left-part">
<img class="card left-card" style="background:red">
<img class="card front-card" style="background:yellow">
</div>
</div>
You can also simplify your code like below:
.book-container {
height: 350px;
width: 250px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
perspective: 1000px;
background:blue;
}
.book-container > div{
transform-style: preserve-3d;
}
.book-container > div:before,
.book-container > div:after{
content:"";
height: 350px;
width:100%;
position: absolute;
transform-style: preserve-3d;
backface-visibility: hidden;
background:yellow;
}
/* RIGHT SITE */
.right-part {
transform-origin: 0%;
transition: 0.7s;
}
.book-container .right-part:before {
transform: rotateY(180deg);
background:green;
}
.book-container:hover .right-part {
transform: rotateY(-180deg);
transition-delay: 0.3s;
}
/* LEFT SITE */
.left-part {
transform-origin: 100%;
transition: 0.7s;
transition-delay: 0.3s;
}
.book-container .left-part:before {
transform: rotateY(180deg);
background:red;
}
.book-container:hover .left-part {
transform: rotateY(180deg);
transition-delay: 0s;
}
<div class="book-container">
<div class="right-part">
</div>
<div class="left-part">
</div>
</div>
I don't know if in the original situation you work with dynamic sizes (in which case this solution would not apply), but you can use a pixel value for transform-origin to make it work:
.book-container {
height: 350px;
width: 250px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
-webkit-perspective: 1000px;
-moz-perspective: 1000px;
perspective: 1000px;
}
.book-part {
height: auto;
width: auto;
position: absolute;
transform-style: preserve-3d;
top: 0;
left: 0;
}
.book-part > .card {
height: 350px;
width: 250px;
position: absolute;
transform-style: preserve-3d;
backface-visibility: hidden;
}
/* RIGHT SITE */
.right-part {
transform-origin: 250px;
}
.right-card {
transform: rotateY(180deg);
}
.book-container:hover .right-part {
transform: rotateY(180deg);
transition: 0.7s;
transition-delay: 0.3s;
}
/* LEFT SITE */
.left-part {
transform-origin: 0%;
}
.left-card {
transform: rotateY(-180deg);
}
.book-container:hover .left-part {
transform: rotateY(-180deg);
transition: 0.7s;
}
.middle-card {
background-color: blue;
}
.right-card {
background-color: green;
}
.left-card {
background-color: red;
}
.front-card {
background-color: yellow;
}
<div class="book-container">
<div class="book-part middle-part">
<div class="card middle-card"></div>
</div>
<div class="book-part right-part">
<div class="card right-card"></div>
</div>
<div class="book-part left-part">
<div class="card left-card"></div>
<div class="card front-card"></div>
</div>
</div>
I'm trying to get my head around transforms and 3d animation perspectives for css. I have created a piece of code that displays an 8 sided die and then rotates it for the viewer.
However, the die seems to rotate around an invisible center object,
rather than the center of the die being the center point for the rotation animation.
I realize that I must not be grasping something about the code I have written through trial and error.
Here is a fiddle to show what I mean about the way the shape seems to rotate around an invisible center: https://jsfiddle.net/4qbLct3b/
Instead, I want the center of the 3 dimensional object to be the center point of the rotation animation.
HTML
body {
perspective: 9000px;
padding-top: 10%;
}
.d8 {
height: 64px;
width: 64px;
margin: auto;
}
.tetra {
position: relative;
height: 86.6%;
width: 100%;
margin: 0 auto;
transform-style: preserve-3d;
transform: rotatex(0deg) rotateY(0deg) rotatez(0deg);
animation: rotate 10s linear infinite;
}
.tetra div {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
-webkit-clip-path: polygon(50% -2.5%, 102.5% 102.5%, -2.5% 102.5%);
clip-path: polygon(50% -2.5%, 102.5% 102.5%, -2.5% 102.5%);
-webkit-clip-path: border-box;
clip-path: border-box;
background: teal;
transform-origin: 0% 100%;
transform: rotatex(35deg);
transform-style: preserve-3d;
}
.tetra .face2 {
transform-origin: 0% 100%;
transform: rotatey(90deg) rotatex(-35deg);
background: gold;
}
.tetra .face3 {
transform-origin: 0% 100%;
left: 100%;
transform: rotatey(90deg) rotatex(35deg);
background: red;
}
.tetra .face4 {
transform-origin: 0% 100%;
transform: rotateY(-90deg) translateX(-100%) rotateY(90deg) rotatex(-35deg);
background: black;
}
.tetra .face5 {
transform-origin: 0% 100%;
transform: rotateY(-90deg) translateX(-100%) rotateY(90deg) rotatex(-145deg);
background: orange;
}
.tetra .face6 {
transform-origin: 0% 100%;
left: 100%;
transform: rotatey(90deg) rotatex(145deg);
background: green;
}
.tetra .face7 {
transform-origin: 0% 100%;
transform: rotatey(90deg) rotatex(-145deg);
background: brown;
}
.tetra .face8 {
background: grey;
transform-origin: 0% 100%;
transform: rotatex(145deg);
}
#keyframes rotate {
50% {
transform: rotatex(180deg) rotateY(180deg) rotatez(180deg);
}
100% {
transform: rotatex(360deg) rotateY(360deg) rotatez(360deg);
}
}
<div class="d8">
<div class="tetra">
<div class="face1"></div>
<div class="face2"></div>
<div class="face3"></div>
<div class="face4"></div>
<div class="face5"></div>
<div class="face6"></div>
<div class="face7"></div>
<div class="face8"></div>
</div>
</div>
I have the following HTML and CSS code to draw the top of a cube. So it moves down and I want it to animate as if it is opening up. I am unable to figure out how to transform the top so that it appears to open up.
I have included the entire code for the cube. With respect to this, I want the top to open up.
.pers500 {
perspective: 500px;
-webkit-perspective: 500px;
-moz-perspective: 500px;
}
/* Define the container div, the cube div, and a generic face */
.container {
width: 25%;
margin: 0 auto;
margin-top: 2em;
border: none;
animation-name: moveDown;
animation-duration: 2s;
animation-timing-function: linear;
transform: translate(0px, 110px);
}
.cube {
width: 70%;
height: 70%;
backface-visibility: visible;
perspective-origin: 150% 150%;
transform-style: preserve-3d;
-webkit-backface-visibility: visible;
-webkit-perspective-origin: 150% 150%;
-webkit-transform-style: preserve-3d;
}
.face {
display: block;
position: absolute;
border: none;
line-height: 100px;
font-family: sans-serif;
font-size: 60px;
color: white;
text-align: center;
}
/* Define each face based on direction */
.front {
width: 3.64em;
height: 3.43em;
background-color: rgba(0, 255, 0, 0.7);
transform: translateZ(50px) translateX(171px) translateY(222px);
-webkit-transform: translateZ(50px) translateX(171px) translateY(222px);
-moz-transform: translateZ(50px) translateX(171px) translateY(222px);
}
.left {
width: 2em;
height: 3.4em;
background-color: rgba(0, 0, 255, 0.7);
margin: 70px;
transform: skewY(40deg) translateZ(50px);
-webkit-transform: skewY(40deg) translateZ(50px) translateY(65px) translateX(-20px);
-moz-transform: skewY(40deg) translateZ(50px) translateY(62px) translateX(-20px);
}
.top {
width: 3.65em;
height: 1.7em;
background-color: rgba(255, 0, 0, 0.7);
margin: 100px;
transform: skewX(50deg) translateZ(50px) translateX(-14px) translateY(20px);
-webkit-transform: skewX(50deg) translateZ(50px) translateX(-14px) translateY(20px);
;
-moz-transform: skewX(50deg) translateZ(50px) translateX(-14px) translateY(20px);
;
animation-name: openTop;
animation-duration: 2s;
animation-timing-function: linear;
}
#-webkit-keyframes moveDown {
0% {
transform: translate(0px, 10px);
}
50% {
transform: translate(0px, 55px);
}
100% {
transform: translate(0px, 110px);
}
}
#keyframes moveDown {
0% {
transform: translate(0px, 10px);
}
50% {
transform: translate(0px, 55px);
}
100% {
transform: translate(0px, 110px);
}
}
#keyframes openTop {
/*0% {transform:rotateX(30deg);}
50% {transform:rotateX(30deg);}
100% {transform:rotateX(30deg);} commented code here doesn't work*/
}
<div class="container">
<div class="cube pers500">
<div class="face front"></div>
<div class="face top"></div>
<br>
<br>
<br>
<div class="face left"></div>
</div>
</div>
To make the cube open up, you first need to set the transform-origin property (as mentioned in the other answer) to top. This setting would make the top side of the .face.top remain fixed when the rotation is being performed. Then you need to add the rotation using rotateX(). This would rotate the top face to produce the opening effect. Note that the transform property should contain the entire list of transforms for it to open correctly. You cannot just add the rotateX() alone within the animation.
.pers500 {
perspective: 500px;
}
/* Define the container div, the cube div, and a generic face */
.container {
width: 25%;
margin: 0 auto;
margin-top: 2em;
border: none;
animation-name: moveDown;
animation-duration: 2s;
animation-timing-function: linear;
transform: translate(0px, 110px);
}
.cube {
width: 70%;
height: 70%;
backface-visibility: visible;
perspective-origin: 150% 150%;
transform-style: preserve-3d;
}
.face {
display: block;
position: absolute;
border: none;
line-height: 100px;
font-family: sans-serif;
font-size: 60px;
color: white;
text-align: center;
border: 1px solid brown; /* just for testing */
}
/* Define each face based on direction */
.front {
width: 3.64em;
height: 3.43em;
background-color: rgba(0, 255, 0, 0.7);
transform: translateZ(50px) translateX(171px) translateY(222px);
}
.left {
width: 2em;
height: 3.43em;
background-color: rgba(0, 0, 255, 0.7);
margin: 70px;
transform: skewY(40deg) translateZ(50px) translateY(64px) translateX(-20px);
}
.top {
width: 3.65em;
height: 1.69em;
background-color: rgba(255, 0, 0, 0.7);
margin: 100px;
transform: skewX(50deg) translateZ(50px) translateX(-74px) translateY(20px) rotateX(0deg);
transform-origin: top;
animation-name: openTop;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
}
#-webkit-keyframes moveDown {
0% {
transform: translate(0px, 10px);
}
50% {
transform: translate(0px, 55px);
}
100% {
transform: translate(0px, 110px);
}
}
#keyframes moveDown {
0% {
transform: translate(0px, 10px);
}
50% {
transform: translate(0px, 55px);
}
100% {
transform: translate(0px, 110px);
}
}
#keyframes openTop {
0% {
transform: skewX(50deg) translateZ(50px) translateX(-74px) translateY(20px) rotateX(0deg);
}
100% {
transform: skewX(50deg) translateZ(50px) translateX(-74px) translateY(20px) rotateX(200deg);
}
}
<div class="container">
<div class="cube pers500">
<div class="face front"></div>
<div class="face top"></div>
<br>
<br>
<br>
<div class="face left"></div>
</div>
</div>
Note:
Setting a transform-origin will affect the position of the top face in the demo and so the values that you've used for translateX() and translateY() on the top face need to be modified a bit like in the above demo.
The vendor prefixed versions of properties should always be added before the standard property in order to be future proof.
I have removed the vendor prefixed versions in the above snippet just to keep it simple.
Set the transform origin to tbe edge of the cube with
transform-origin: 0 50% 0;
Then rotate it around the z axis:
transform: rotateZ(90deg);
I hope this works for you, I didn't have the chance to test it.
Is it possible to use scaleZ() to effectively create a 3D box?
Here's what I've tried, but obviously it didn't scaleZ at all:
.box {
-webkit-transform-style: preserve-3d;
-moz-transform-style: preserve-3d;
-ms-transform-style: preserve-3d;
-o-transform-style: preserve-3d;
transform-style: preserve-3d;
-webkit-transform: scaleZ(10);
-moz-transform: scaleZ(10);
-ms-transform: scaleZ(10);
-o-transform: scaleZ(10);
transform: scaleZ(10);
width: 100px;
height: 100px;
display: block;
background:red;
}
Is there another way I can tackle this? Even if I have to use Javascript?
DEMO: http://jsfiddle.net/3r1gus9f/
ScaleZ() doesn't "extrude", it would required elements to have a thickness which they don't.
ScaleZ is particular in the way that in most cases it won't have any visible effect (as in your example) and requires other 3d transforms to be visible, example :
.w{
display:inline-block;
perspective:500px;
border:1px solid red;
}
.b{
width:150px;
height:150px;
transform-origin:0 0;
transform: rotatey(45deg);
background:pink;
}
.b2{
transform: scaleZ(10) rotatey(45deg);
}
<div class="w">
no scaleZ()
<div class="b"></div>
</div>
<div class="w">
scaleZ(10)
<div class="b b2"></div>
</div>
For an explanation of the calculations behind this, see What does the scaleZ() CSS transform function do?.
A common way to make a 3d cube with CSS is to use 6 surfaces and to transform them into the 6 planes of a cube, you could do this :
#cube {
position: relative;
width: 200px; height:200px;
margin: 100px auto;
perspective: 500px;
perspective-origin: 50% 10%;
}
#cube div {
font-size: 2rem;
position: absolute;
width: 200px; height: 200px;
background: rgba(0, 0, 0, 0.2);
border: 1px solid #000;
}
.back {
transform: translateZ(-100px) rotateY(180deg);
}
.right {
transform: rotateY(-270deg) translateX(100px);
transform-origin: top right;
}
.left {
transform: rotateY(270deg) translateX(-100px);
transform-origin: center left;
}
.top {
transform: rotateX(-90deg) translateY(-100px);
transform-origin: top center;
}
.bottom {
transform: rotateX(90deg) translateY(100px);
transform-origin: bottom center;
}
.front {
transform: translateZ(100px);
}
<div id="cube">
<div class="front">front</div>
<div class="back">back</div>
<div class="top">top</div>
<div class="bottom">bottom</div>
<div class="left">left</div>
<div class="right">right</div>
</div>
I found out that the value for a scaling in Z axes is multiple with a value of translate for the Z axes. So you have to also apply translateZ in order to apply scaleZ.
transform: scaleZ(10) translateZ(1px);
see fiddle http://jsfiddle.net/jakethashi/ey8j5345/