Table of Contents generated with DocToc
Learning CSS3 3D with Tuts Plus course.
To learn about 3D, download Blender or brew cask install blender
.
In the 3D world, there are two different views. One is perspective, the other is orthographic.
Perspective view is how you view the world through your own eyes. For example, if there are two objects in the world such as cubes that are the exact same size, but one is placed farther back than the other, the one farther back will appear smaller to you than the one in front.
Orthographic view does not respect the relationship from the view (i.e. user) to the distance. It's totally flat. This view is useful for positioning elements.
Orthographic view has no vanishing points, whereas perspective view does. By moving the vanishing points, we can change our perspective.
When using CSS 3D, you effectively have just one vanishing point, or a focal point in your scene.
CSS transform
property allows us to perform 3 transform functions:
translate
(move something), scale
, and rotate
For example, to move something along the X axis, use translateX(numUnits)
.box {
width: 100px;
height: 100px;
background: red;
transform: translateX(10em);
}
Multiple transform functions can be specified all at once. For example, to move on the Y and X axes:
.box {
width: 100px;
height: 100px;
background: red;
transform: translateX(50px) translateY(100px);
}
So far, just using X and Y axes moves in 2D space. To move in 3D space, need to also make use of the Z axis.
In the browser, your default view is looking down at the scene from the top. Therefore the Z axes gives things depth, i.e a positive value will move the object closer, whereas a negative value will make the object appear farther away.
However, in the code below adding Z axis will not have any visible effect in the browser:
.box {
width: 100px;
height: 100px;
background: red;
transform: translateX(50px) translateY(100px) translateZ(200px);
}
This is because in the browser, we are in orthographic mode by default, therefore an object being closer or further always looks the same. i.e. no vanishing points, and no relationship between the size of the object and distance it is from your view.
To make effective use of the Z axis, must tell the browser to go into perspective mode (will be covered next lesson).
The 3 translate functions (X, Y, and Z) can be combined into a single shorthand function translate3D
,
that accepts X, Y, and Z parameters in order. For example:
.box {
width: 100px;
height: 100px;
background: red;
transform: translate3D(100px, 300px, 300px);
}
No measurement units needed, because it automatically uses percentages.
Also supports separate functions for X, Y, and Z axes and a shorthand syntax scale3D(x,y,z)
scaleX(1)
has no effect because 1 = 100%, so object will remain exactly the same size.
scaleX(2)
will make the width 200% of its current size. So if current width is 100px, this would make it 200px.
scaleX(.5)
will make it 50%, i.e. half its size.
Rotate function takes number of degrees, for example:
.box {
width: 100px;
height: 100px;
background: red;
transform: rotateX(40deg) rotateY(30deg) rotateZ(30deg);
}
Note that X axis rotation just makes the square look "shorter", being in perspective mode will fix this.
Unlike translate
and scale
, shorthand syntax for rotate
takes 4 arguments.
First three arguments (X, Y, Z) represent a number that is component of the direction vector about which the element is rotated.
Fourth argument is the angle in which the element will be rotated, for example:
.box {
transform: rotate3D(0,0,0,40deg);
}
Leaving the first three args as 0 will have no effect on rotation. Setting X to 1 will make it rotate 40 degrees in the x axis.
Read this for more details on rotate3D shorthand syntax.
Perspective is applied to the parent element of the div having transform
.
For example, if box1
is to be transformed, apply perspective to container
:
<div class="container">
<div id="box1" class="box">Box</div>
</div>
.container {
perspective: 500px;
}
Value assigned to perspective makes objects go further back as its increased, makes the distance between the view and the object larger. The further back, the more sublte the 3D effect.
When you create a 3D object, a Z-Plane is created. This is like a rendered scene. The greater the perspective value, the further back the Z-Plane is pushed.
Note that applying perspective to an element does NOT AFFECT the element itself, it only affects its child elements.
Perspective property only has an effect on 3D transformed elements, i.e elements having transform
property.
Another way to apply perspective is as a function on the same line as transform
attribute BUT ORDER MATTERS.
It must appear as the fist function, for example:
#box1 {
background: red;
transform: perspective(500) rotateX(40deg) translateX(400px);
}
Changing the vanishing point, i.e. changing our perspective. Default perspective origin is center. But could be for example, top left, top, top right, etc.
Perspective origin css property should be applied to the same element that has the perspective property.
i.e. perspective
and perspective-origin
go together and must be on the parent element.
Must supply two values, X and Y to perspective-origin. Default values are center center
(or 50% 50%).
Can be any measurement units that are compatible with css such as pixels, percentages, etc.
Can also use descriptive positioning like left
, top
, etc.
For example to make user's view up to the top and left of the 3D scene:
.container {
perspective: 500px;
perspective-origin:left top;
}
perspective-origin:100% 100%
is right bottom.
Position | Percentage |
---|---|
left top | 0% 0% |
right top | 100% 0% |
left bottom | 0% 100% |
right bottom | 100% 100% |
By default, transform origin is located in the center of the object being transformed.
transform-origin
property must go together on same element having transform
property, they go together.
Units can be pixesl or percentages. Recommend using percentage because that allows moving origin point in proportion to size of element.
For example, to make origin point the left top corner:
#box1 {
background: #d81670;
transform-origin:0% 0%;
transform: rotate(40deg);
}
To make origin the right bottom corner:
#box1 {
background: #d81670;
transform-origin:100% 100%;
transform: rotate(40deg);
}
Note: rotate(40deg)
, with no X, Y or Z specified rotates the object in 2D space.
Allow child elements to be transformed independently of the parent.
In the example below, setting preserve-3D
on the parent element allows the child to be rotated differently than the parent.
<div id="box1">
<div id="childEl"></div>
</div>
body {
perspective: 500px;
perspective-origin: 100% 100%;
}
#box1 {
transform: rotateX(40deg) translateX(400px);
transform-style: preserve-3D;
}
#childEl {
transform: rotateX(80deg);
}
Translate functions are relative to the object itself. So if you first rotate an object, say 90deg in the Y axis, then apply translateX, it will move in the Z axis, which is now the object's local axis.
Most of the time, want to stick with the global axes (i.e. X moves left to right, Y top to bottom, etc). To achive this, always translate first, then apply other transformations such as rotate.
Cube div is empty, functions as a container to group all of the "planes" together, which represent the faces of the cube. In this way, the cube can be rotated, which will rotate all the planes together.
Make all the faces absolute
positioning, so that transforms can start from same position, this is easier to manage.
No rotation needed for front face because we're in top view by default.
Note in browser, positive translateY value makes the object go down, and negative translateY value makes the object to up. (opposite of Blender).
translateX with negative value will move the object to the left, positive value will go to the right. (same as Blender).
By default, viewport width is entire width of the browser, and height is 0, so cube looks "stuck" to the left hand side of the page. The reason the cube shows at all despite viewport height of 0 is that overflow is set to visible by default.
To get the cube to render exactly in the center, need to set width and height on viewport to be same as the cube. Then use absolute positioning and margins for centering:
#viewport {
width: 200px;
height: 200px;
position: absolute;
top: 50%;
left: 50%;
margin: -100px 0 0 -100px;
-webkit-perspective: 1000px;
perspective: 1000px;
}
To make the cube rotate about its center, need to set its height, otherwise it defaults to 0 and rotates about the top axis.
Change cube and face divs to have width and height 100%, so they automatically scale to viewport width and height.
Adding text to each face - front and right faces look ok, but left face text is reversed. Switch X rotation to negative degrees to fix it.
The correct positive/negative rotation to make the text be upright depends on what sequence the cube will be animated in.
Start by setting up a timeline. Timeline consists of frames, where each frame is like a page in a flip book.
Keyframes are a technique to program certain points within the timeline, and css does the interpolation between these points automatically. For example, to animate a background color change:
@keyframes Foo {
from { background: #25064C; }
20% { background: #36175E; }
40% { background: #553285; }
60% { background: #7B52AB; }
80% { background: #7B52AB; }
to { background: #9768D1; }
}
from
is equivalent to 0% and to
is equivalent to 100%. But don't need this, could start say at 20%.
By itself, keyframes doesn't do anything, must set it as animation
property of element. For example:
#front {
-webkit-animation: Rotate 3s infinite alternate;
animation: Rotate 3s infinite alternate;
}
Can apply the animation class interactively via css, for example, when user hovers over a link:
<a href="#" id="anim">Animate</a>
<div id="viewport">
<div id="cube">
All the faces are here...
</div>
</div>
#anim:hover + #viewport > #cube {
animation: RotateCrazy 3s infinite alternate;
}
@keyframes RotateCrazy {
0% { transform: rotateY(0deg); }
20% { transform: rotateY(30deg) rotateX(50deg); }
70% { transform: rotateY(210deg) rotateZ(120deg); }
100% { transform: rotateY(360deg); }
}
In the last example, the cube "snaps" back into place at the end of keyframe animation.
CSS transition
can be used instead for a smoother effect (and less processor intensive which is more mobile friendly).
transition: all
specifies that all properties that are animatable should be. This example transitions the transform
property on hover:
#cube {
width: 100%;
height: 100%;
transform: rotateX(0deg) rotateY(0deg);
transform-style: preserve-3d;
position: relative;
transition: all 2s;
}
#anim:hover + #viewport > #cube {
transform: translateX(400px) rotateX(-290deg) rotateY(150deg) rotateZ(130deg);
}
Transitions are less flexible than animations, but smoother. Also animations have to redraw every frame.
See example 2D transitions with modal.
Impress.js can be used to build 3D presentations using just css, javascript and html. As a developer, only need to manipulate data attributes of dom element to get the 3D effects.
Oridomi.js to fold up DOM elements like paper, and can help in displaying menus.
Recommended to give all elements a width and height before Oridomi loads.