Have you ever come across a rather complex 3D creation while surfing the internet and your curiosity leads you to click on it to see if it has been rendered in ? These days, the features that come with modern browsers give you the power to create amazing projects without needing an external animating tool. Flash In fact, there are a handful of techniques: , , which can be used to get this done. But in this article, I would like to introduce how to manage and to the elements of a website using only CSS features. JavaScript Canvas animations transformations CSS also for 3D? Yes, even for 3D. In this post, we will create a 3D animated wooden-house model with CSS. Take a look at the here. DEMO As a result, we will get a scene that is tilted at a 45-degree and viewed at a 2000-pixels viewpoint using the property. perspective The objects positioned in this model are normal HTML elements. They have widths, heights, and are rectangular. This means that as you build a 3D object, you place each rectangle in place. The HTML elements are placed within the 3D scene using the property to move them in 3-dimensional spaces and also, the and properties are applied to the objects to create the illusion of depth. transform border gradient CSS Transform The property uses a value of with three dimensions. It is used to translate the element by a vector , where is the translation along the x-axis, for the y-axis, and for the z-axis. Positive translation values will move the element along the positive direction of the axis, and negative values will move it in the opposite direction. Read more . transform translate3d [tx, ty, tz] tx ty tz here Also, note that is one of the values that can be applied to the property. There are also , , , values and we will be using a combination of all or some in this tutorial. You should also note that the ordering of these values matter. When an element is applied more than one value, it starts its transformation from the last applied value to the first in that order. So, you can have similar values of transformation for two elements but they will be positioned differently if their orders are not the same. translate3d transform rotate skew scale matrics In particular, this is the scene that will be created: The first is its static view while the other is its animated view. A quick note This project has been developed and tested primarily in Chrome and so, supports all properties used. Hence, I’ve removed the prefixed versions of rules in the following CSS. I would recommend either using compilers like LESS or SASS to manage these for you. Otherwise, be aware that most browser prefixes will need to be applied. Full versions of the CSS and SASS can be found on this including the HTML. pen , Let’s get started! We need to set a scene in which we can build our 3D creation. To do this, we’ll need to use an HTML element as the parent element and give it the needed properties that tell the browser to expect 3D content within it. Let’s start with some HTML: ... < = > article class "scene" </ > article In this case, the is an tag. You can use any other semantic tag and still achieve the same result. But I decided to use the tag because in HTML5, represents a standalone piece of content that could be reproduced elsewhere and still make sense. scene container article article article The first property to apply is . This property takes a value in pixels and represents the depth of the 3D scene. The property defines how far the object is away from the viewer. So, a lower value will result in a more intensive 3D effect than a higher value. perspective perspective For this view to feel like a wide scenery and with our model structure seated fully, we will set the perspective value quite high at 2,000 pixels. We could also establish the scene viewing angle by adjusting the property. This will determine whether we’re looking down at the object or from the side. The property takes two values, a horizontal and a vertical offset. And in our case, we want it centered with a value and which is the default, so we don’t need to specify it. perspective-origin perspective-origin 50% 50% { : (0, 50px); : ; } article .scene transform translate perspective 2000px Let’s Build! With the scene set, we can start putting together our 3D masterpiece. When beginning to build 3D objects with HTML and CSS, it’s worth taking a moment to understand how these properties work. Before we start building, we will create a section inside our tag, which will contain the different features of our house model as a set of elements and form the main parts of our model. house article div < = > section class "house" < = > div class "deck" </ > div < = > div class "walls" </ > div < = > div class "roof" </ > div < = > div class "staircase" </ > div < = > div class "wedges" </ > div < = > div class "person" </ > div </ > section The elements in the section above will take the form of the deck, the wall-frames and ceiling, the staircase attached at the top-left of the deck, the veranda and the animated persons. With that in mind, we adjust our class by rotating the entire scene by 45-degrees. We will have to set that now so as not to give us any issue with positioning our later. Next, we need to apply a property and to the section and also give the some shared properties. house divs transform transform-style house divs { : auto; : relative; : preserve- d; : (-45deg); : ; } { : absolute; : preserve- d; } .house margin 0 position transform-style 3 transform rotateY width 460px .house div position transform-style 3 Each will be positioned absolutely in order to control and fix them easily, and the transform-style property set to to instruct the browser that 3D transforms are to be applied in relation to the property we set earlier. div preserve-3d perspective With this done, we can create our children elements inside our parent and start positioning them. I should also note that I used the unit for my positioning. You can use other units you desire but I find quite handy. The values are not as high as pixels or percent and it takes fewer adjustments to reach your targeted positions. div rem rem Creating the deck The key concept of CSS drawing is to creatively use to create curves and shapes. Then rotate and place them in the right position. And how do I know the exact degrees or pixels to put into my values? Well, I don’t! The trick is to use the browser dev tools to help you with a live adjustment. Then copy the styles into your source file when you get the right value. And the most important thing that would help you with a good judgment of deciding what values to use or values closest to the one you want is to know the directions of the dimensions. With that, you’ll have fewer adjustments to make. border-radius Let’s continue then, shall we? < = > div class "deck" < = > div class "covering" </ > div < = > div class "left" </ > div < = > div class "right" </ > div < = > div class "back" </ > div < = > div class "front" </ > div </ > div * , * , * { : solid ; : solid ; } { : ; : ; : ; : (7.4rem, 19.6rem, 38.3rem); } { : ; : ; : ; : (-38.4rem, 29.1rem, -38.4rem); } { : ; : ; : ; : (-66rem, 29.3rem, -12.8rem) (90deg); } { : ; : ; : ; : (32.1rem, 21.2rem, 9rem) (90deg); } .deck :not(.covering) .deck ::before .deck ::after border-right 3px #78552c border-top 2px #b5854a .deck .left width 33.75rem height 2.06rem background #8a693d transform translate3D .deck .right width 61.3rem height 2.9rem background #4e3b23 transform translate3D .deck .back width 53rem height 2.9rem background #4e3b23 transform translate3D rotateY .deck .front width 25.3rem height 2.2rem background #9c7645 transform translate3d rotateY The above rules assign a border-right and left to all sides of the deck except the covering to create a nice depth effect. It also describes a of 33.75rem (540px), a of 2.06rem and a dark-brown for the left side. The is then positioned at 7.4rem along its x-axis, 19.6rem along its y-axis and 38.3rem at its z-axis. width height background color div Next, we create the other sides of the deck. Since it has four corners, I created two more sides — right and back sides and applied similar properties. You may have noticed I used a of 90-degrees on the and . We want them to be perpendicular to the and . The front side will be a little more complicated since we have to make a dent to fit in our staircase. I created a single for this and also used pseudo-elements for carving out this space. rotateY .deck .back .deck .front .deck .right .deck .left div ::before, ::after To complete the deck, we will be creating a covering for it. We will create a large L-shape from a rectangular shape. This is to create room for the stairs which we will be building later. I could have made this shape using the clip-path property but I wanted the shapes used for this project to be built solely with backgrounds and sizes. And again, not all browsers support the clip-path property yet. With this, I use the stacking linear-gradient background below to achieve the L-shape for the covering. : ( , ) (100% — 124 ) , ( , ) 0 188 /100% ; background linear-gradient #7a5d37 #7a5d37 calc px no-repeat linear-gradient #7a5d37 #7a5d37 px no-repeat We will also give it a value and it negative 90-degrees along it x-axis to make it lap onto the four corners of the deck stands. translate3d rotate The result of all this should be a scene that looks like this: Erecting the wall frames The HTML structure for the walls will be a little intricate, but we can always manage it, right? We will be inserting a window div inside the walls for all four sides of the wall. And inside the windows , we will be creating two for the two windows, and each with a louvre and a lower bar div . And the end, we’ll be adding a door to the front wall. div div rim class divs div First, each of the walls will be given a value of and we will start with the left wall. The left wall should be created first to determine where we want the length of the house to begin and end and also to determine how well to fit and align it to the adjoining walls. We will begin by giving it a , as usual. 12.5rem translate3d width To complete this wall, we will give it a brown color; a little darker than the front wall. They are the only two walls that will be exposed to the viewer and we want to make it appear that the light reflects more on the front wall than the left wall. Next, we will create the right wall by giving it similar properties. For the property, we will give it a . The negative values for the x-axis and z-axis are because the wall will be further away from our view. We will also add a of 180-degrees since we want it to be perpendicularly aligned to the left wall. transform translate3d(-17.7rem, 6.25rem, -9.06rem) rotateY To finish up this section, we will create the back and front walls in the same fashion but give them a of 90-degrees for the front wall and 3-degrees off 90 for the back wall. This will form perpendicular walls and hence the four-corner or cuboidal shape of the house. rotateY < = > div class "front" < = > div class "windows" < = > div class "rim first-rim" < = > div class "louvres" </ > div < = > div class "bar" </ > div </ > div < = > div class "rim second-front-rim" < = > div class "louvres" </ > div < = > div class "bar" </ > div </ > div </ > div < = > div class "doors" < = > div class "door-open" </ > div < = > div class "door-close" < = > div class "door-knob" </ > div < = > div class "door-bars" </ > div </ > div </ > div </ > div , , , { : ; } { : ; : ; : (18.4rem, 6.2rem, 38.3rem); } { : ; : ; : (18.1rem, 6.2rem, 9.4rem); } { : ; : ; : (2.2rem, 6.3rem, 22.7rem) (90deg); } { : ; : ; : (26rem, 6.2rem, 23.9rem) (90deg); } .right .left .back .front height 12.5rem .walls .left width 22rem background #c3964f transform translate3d .walls .right width 22.2rem background #8c682f transform translate3d .walls .back width 29.2rem background #9f7636 transform translate3d rotateY .walls .front width 28.75rem background #c79d5a transform translate3d rotateY At the end, we will have a nice-looking shape as the one below. The windows and door The windows will be created by giving the rim a weight and height of 4.3rem and height: 3.75rem respectively and also move it 30px away from the top of the walls. Then, we add a border of for both left and right sides of the rims and a to the top and bottom. The offset of 3px on both values is to make up for the width of one to the other since the value we gave to its first parent slightly distorted that. div 9px solid #dac29a div 7px solid #dac29a perspective div Afterward, we will be adding an extra class-names to the rims . This is because both window rims will be stacked up together, so we need to create a distance between them by applying a value. All first rims will take a value of , and while the second rims of the left and right walls take a value, the second rims of the front and back walls will take a left value of . This is because the front and back walls are longer in width compared to the left and right walls. div left left 40px 215px 330px Next, we create a and pseudo-class from the rim . These classes will be used to create the crossed dividers inside the window frames. We will give the class a left value of and the class a top value of 45%. Instead of using a border here, I will be using a gradient background color to simulate a fine inward distance. We will also create a louvre which will be used to form the window glasses. We will give it a , a and an of 0.7 to give it a glassy look. ::before ::after div ::before 45% ::after div background border-top opacity { : ; : ; : ; : solid ; : solid ; : solid ; : solid ; } { : (to left, #dac29a, #bda886); : ; : ; : ; : ; : absolute; } { : (to left, #dac29a, #bda886); : ; : ; : ; : ; : absolute; } { : ; } , { : ; } , { : ; } { : (to left, #dac29a, #b5a181); : solid ; : ; : ; : - ; : ; } { : (to left, #dac29a, #b5a181); : solid ; : ; : ; : - ; : - ; : ; } { : ; : ; : ; : ; : solid ; : (12deg, #7a5d37 40%, #a07c43 0 70%); } { : ; : ; : ; : ; : solid ; : solid ; : solid ; : ; } { : ; : ; : (to top, #dac29a, #dac29a); : ; : ; : ; : solid ; } { : ; : ; : (to top, #dac29a, #dac29a); : ; : - ; : - ; : solid ; } .windows .rim top 30px width 4.3rem height 3.75rem border-left 9px #dac29a border-right 9px #dac29a border-top 7px #dac29a border-bottom 7px #dac29a .windows .rim ::before background linear-gradient left 45% width 0.62rem height 3.75rem content '' position .windows .rim ::after background linear-gradient top 45% width 4.3rem height 0.45rem content '' position .windows .first-rim left 40px .windows .second-left-rim .windows .second-right-rim left 215px .windows .second-front-rim .windows .second-back-rim left 330px .windows .louvres background linear-gradient border-top 2px #7a5d37 width 4.3rem height 3.75rem z-index 1 opacity 0.7 .windows .bar background linear-gradient border-top 2px #7a5d37 width 6rem height 0.5rem bottom 15px right 15px border-radius 20px .doors .door-open width 5.5rem height 7.5rem bottom 0% left 40% border-right 3px #a58152 background linear-gradient .doors .door-close width 5.5rem height 7.5rem bottom 0% left 40% border-left 8px #dac29a border-right 8px #dac29a border-top 8px #dac29a background #fff .doors .door-knob width 0.5rem height 0.5rem background linear-gradient border-radius 50% top 50% left 5px border-left 2px #a28658 .doors .door-bars width 7rem height 0.5rem background linear-gradient border-radius 20px top 15px left 12px border-bottom 2px #7a5d37 Styling the door requires two features. The first door-open is to create what looks like an opening in the front wall, which will come in handy when we animate our to move in through the door. We will give it a to simulate this; sharp contrast colors going from the floor color to the right wall color and tilted at a degree of 12 and also some borders that will make it look like its inset. Secondly, we will create the door by giving the door-close a of white and borders that will form the door-frames. We will give the door, a knob and top bar using , and sizes. div person linear-gradient div background-color background border-radius Roofing the house structure < = > div class "roof" < = > div class "left" </ > div < = > div class "right" </ > div < = > div class "front" </ > div < = > div class "back" </ > div </ > div < = > div class "porch" < = > div class "bottom" </ > div < = > div class "left" </ > div < = > div class "right" </ > div < = > div class "front" </ > div < = > div class "first_bar bar" </ > div < = > div class "second_bar bar" </ > div </ > div We will start this section by creating the HTML structure. Creating the upper compartments may look pretty straight-forward but it seemed to me to be the toughest part of this project. This is because I had to make several tilting and positioning points to get the shape I needed. We will be starting this section by creating the HTML for the roof and porch structures. divs The styling for the front side of the roof will be achieved by using borders to create a triangular shape. This could be done by using the clip-path property too but I’m opting for borders instead. First, we will give the , and . We will also give it a rotation of 90 degrees along its y-axis which is the same degree as the front wall. Next, we will give it a values. We will do the same to the backside and give it similar properties. border-left:220px solid transparent border-right:246px solid transparent border-bottom:110px solid #e7b565 translate3d { : solid transparent; : solid transparent; : solid ; : (25.6rem, -0.6rem, 23.7rem) (90deg); } { : solid transparent; : solid transparent; : solid ; : (15.85rem, -0.6rem, 31.7rem) (90deg); } { : ; : ; : (to left, #795f35, #a68349, 10%, #a68349, #795f35 10%); : solid ; : solid ; : (29.5rem, -1.8rem, 42rem) (45deg) (-35deg); } { : ; : ; : (to left, #8e734b, #65502d, 10%, #65502d, #8e734b 10%); : solid ; : solid ; : (-12.3rem, -3.1rem, -0.7rem) (131deg) (-35deg); } .roof .front border-left 220px border-right 246px border-bottom 110px #c79d5a transform translate3d rotateY .roof .back border-left 203px border-right 203px border-bottom 98px #9f7636 transform translate3d rotateY .roof .left width 24.25rem height 8.4rem background-image repeating-linear-gradient border-right 5px #86693b border-bottom 3px #927340 transform translate3d rotateX skewX .roof .right width 41.25rem height 12.5rem background-image repeating-linear-gradient border-right 5px #b38f55 border-bottom 3px #927340 transform translate3d rotateX skewX The right and left roofs will also be created in the same fashion but with a twist. We will add a to the left roof and since the scene we are building is to be viewed at 45-degrees, this effect works to our advantage in this case. Subsequently, a which is calculated as will be given to the right roof. This is to create an opposite tilting of both roofs. rotateX(45deg) rotateX(45deg + 90deg) rotateX(135deg) Next, we also add a value of negative 35-degrees to both roofs. This is also to make the bottom-end side of the roof planes stick out more than the top-end. The idea behind this is that looking at our view, we should be able to put up a better judgment on the appearance and placing of the structure. We will also be adding a nice repeating-linear-gradient to make them appear ridged-like. skewX : ( , , , 10%, , 10%) background repeating-linear-gradient to left #8e734b #65502d #7b561a #655235 Next, we will be creating a porch that will be placed directly above the front door. The bottom-porch will be styled first to enable proper alignments of other sides of the porch. A and of and will be assigned to it, a and a . We slightly offset the rotate value off 1 degree since we are viewing the scene from a higher viewpoint, an 89-degrees will completely tilt the bottom-side of the porch and still make it visible. width height 2.6rem 11rem translate3d rotateX(89deg) Subsequently, we will also create the left and right side of the porch similarly but completely tilting them and make them steeper. For the front side, we will be creating a triangular shape using borders just like we did for the front and back sides of the roof. We will also adjust the sides and positions until it laps perfectly unto the other sides of the porch. To complete the porch, we will create two pillars that will hold the porch and stretch from the bottom of the porch to the flooring. * { : (to top, #795f35, #b18c50); : solid ; } { : ; : ; : (52rem, 0.4rem, 36rem) (90deg); } { : ; : ; : (51.1rem, 1.6rem, 38rem) (63deg); } { : ; : ; : (51.3rem, 1.6rem, 32.8rem) (-63deg); } { : solid transparent; : solid transparent; : solid ; : (58rem, 2.7rem, 44.2rem) (90deg); } { : ; : ; : ; : (to bottom, #795f35, #b18c50); : solid ; } { : (52rem, 6rem, 37rem); } { : (51.8rem, 6rem, 31.5rem); } .porch :not(.front) background linear-gradient border-right 3px #9a7944 .porch .bottom width 2.6rem height 11rem transform translate3d rotateX .porch .left width 3rem height 6rem transform translate3d rotateX .porch .right width 3rem height 5.9rem transform translate3d rotateX .porch .front border-left 70px border-right 70px border-bottom 36px #866a3c transform translate3d rotateY .porch [class*='bar'] height 155px width 10px border-radius 0 0 5px 3px background linear-gradient border-right 3px #9a7944 .porch .first_bar transform translate3d .porch .second_bar transform translate3d Walking up the staircase < = > div class "staircase" < = > div class "vertical-step" </ > div < = > div class "horizontal-step" </ > div < = > div class "back-cover vertical" </ > div < = > div class "bottom-cover horizontal" </ > div < = > div class "side-cover" </ > div </ > div Building the stairs was not as difficult as I thought it would. What I had to do was to create div class — , , make pseudo-elements from them to make-up the three numbers of stairs. Then, I made a back, bottom and side coverings for them too. horizontal-steps vertical-steps For the pseudo-elements, I did not have to use properties for them, thankfully. This was because I did not need them to be transformed by their z-axes. All I needed to do was to use the positional properties — , , and to align them properly and since we already have all divs at absolute positioning, it was quite easy to accomplish. transform top bottom left right First, we will start with the vertical-step by giving it , and properties. With the properties set, we will not need to set the positions of its pseudo-elements because they will automatically inherit them. div width height transform transform All we have to do is to use and properties to push them to the positions we want them to be. A similar procedure will be followed for the horizontal-steps as well. top left Below are the CSS rules: , , { : ; : solid ; : solid ; } { : ; : ; : (46.8rem, 18.3rem, 33.3rem) (-4deg); } { : ; : ; : ; : absolute; : ; : - ; } { : ; : ; : ; : absolute; : ; : - ; } , , { : ; : solid ; } { : ; : ; : ; : ; : (47.8rem, 17.5rem, 33.3rem) (90deg) (2deg); } { : ; : ; : ; : absolute; : ; : ; } { : ; : ; : ; : absolute; : ; : ; } { : ; : ; : ; : absolute; : (40rem, 20.6rem, 25rem) (-5deg); } { : ; : ; : ; : absolute; : (39.2rem, 22.2rem, 27rem) (82deg) (1deg) (-25deg); } { : ; : ; : ; : (56.5rem, 16.68rem, 38rem) (90deg); } { : ; : ; : ; : ; : absolute; : (-1.6rem, 0.8rem, 0rem); } { : ; : ; : ; : ; : absolute; : (-2.9rem, 1.6rem, 0rem); } .staircase [class*='vertical'] .staircase [class*='vertical'] ::before .staircase [class*='vertical'] ::after background-color #7a5d37 border-right 3px #78552c border-top 2px #b5854a .staircase .vertical-step width 5.62rem height 0.93rem transform translate3D rotateY .staircase .vertical-step ::before width 6.2rem height 0.93rem content '' position top 24px left 40px .staircase .vertical-step ::after width 6.2rem height 0.93rem content '' position top 48px left 65px .staircase [class*='horizontal'] .staircase [class*='horizontal'] ::before .staircase [class*='horizontal'] ::after background-color #8a683d border-right 4px #78552c .staircase .horizontal-step width 5rem height 1.3rem width 80px height 21px transform translate3D rotateX rotateY .staircase .horizontal-step ::before width 5rem height 1.3rem content '' position top 63px left 35px .staircase .horizontal-step ::after width 5rem height 1.3rem content '' position top 116px left 63px .staircase .vertical-back width 6.25rem height 3.13rem content '' position transform translate3D rotateY .staircase .horizontal-back width 6.25rem height 3.55rem content '' position transform translate3D rotateX rotateY skewX .staircase .side width 1.25rem height 2.56rem background #674e2e transform translate3D rotateY .staircase .side ::before width 1.63rem height 1.71rem background #674e2e content '' position transform translate3D .staircase .side ::after width 1.31rem height 0.85rem background #674e2e content '' position transform translate3D Subsequently, we create the bottom and back coverings by copying the properties for the horizontal and vertical steps, enlarge their widths and heights and place them accordingly. And for the side covering, I used a when I created it at first but I had wanted clip-path to be out of the scope of this tutorial, I had to recoup another method to achieve that shape. clip-path So, I created a , made pseudo-elements from it again, gave them appropriate shapes and aligned them to the three sides of the stairs each. div Framing the veranda The HTML structure for the veranda will be pretty lengthy but needful because we will be placing bars and adjoining planks at all sides of the deck. < = > div class "veranda" < = > div class "wedges" < = > div class "wedge1 border-left" </ > div < = > div class "wedge2 border-left" </ > div < = > div class "wedge3 border-left" </ > div < = > div class "wedge4 border-right" </ > div < = > div class "wedge5 border-right" </ > div < = > div class "wedge6 border-right" </ > div < = > div class "wedge7 border-right" </ > div < = > div class "wedge8 border-left" </ > div < = > div class "wedge9 border-left" </ > div </ > div < = > div class "planks" < = > div class "plank1 border-right" </ > div < = > div class "plank2 border-right" </ > div < = > div class "plank3 border-left" </ > div < = > div class "plank4 border-left" </ > div < = > div class "plank5 border-left" </ > div < = > div class "plank6 border-right" </ > div < = > div class "plank7 border-left" </ > div < = > div class "plank8 border-left" </ > div </ > div </ > div Erecting the veranda was my favorite part of this project. The positionings were quite straight-forward. The wedges lie at every corner of the deck, so once I got a wedge’s position rightly, I can only adjust an axis or two to get the opposite wedge’s position. This also applies to the planks which will be used to join the wedges together. We will start with the wedges, and first, we will be creating nine wedges which are the total numbers to be fitted at every corner including the edges of the staircase as well. We will assign a general styling of 6px to the top-left and right and a border-top of . And after then, we will add extra class names to the wedges and planks — some will take a border-left position while others will take a border-right. border-radius 1px solid #b5854a The reason for this is the following. We want every wedge attached to the stairs to have a rotation of 90-degrees while the others remain at 0-degree. The stair wedges will be used to build the stair-rails, and so they will need to be rotated to perfectly form this shape and then only properties will be needed while we give a class to the others. border-left border-right A similar procedure will be done for the planks . We will give them a general styling of ; a to the planks directly facing the view and a border-left to the planks facing a different view other than the front. At the end of this, we will be left with nicely drawn wooden bars and planks attaching them and we will do the magic by using the borders properties. divs border-top border-right Viewing the images below will give a better visualization. After giving them general styling, we can then begin to work on the positioning. Once we place a wedge at the corner, we can use good judgment to decide how far the opposite one can be. We will perform similar actions to the plank . divs And just like how we created the deck, we will give the front and back planks a of 90-degrees, so as to be right-angled with the side planks. We will also give a to the planks that form the stair-rails and as well as a values to make them slanted. rotateY rotateY(90deg) rotateZ { : ; : ; : solid ; } { : solid ; } { : solid ; } { : ; : ; : (to bottom, #7a5d37, #523e25); : (57.8rem, 14rem, 46.3rem) (90deg); } { : ; : ; : (to bottom, #7a5d37, #523e25); : (54rem, 13.3rem, 38rem) (90deg); } { : ; : ; : (to bottom, #8a683d, #b78549); : (45.8rem, 15rem, 32rem) (90deg); } { : ; : ; : (to bottom, #8a683d, #b78549); : (40rem, 16.5rem, 38.5rem); } { : ; : ; : (to bottom, #8a683d, #b78549); : (10rem, 16.5rem, 38.5rem); } { : ; : ; : (to bottom, #7a5d37, #523e25); : (10rem, 16.5rem, 5.5rem); } { : ; : ; : (to bottom, #7a5d37, #523e25); : (48rem, 16.3rem, 5.5rem); } { : ; : ; : (to bottom, #8a683d, #b78549); : (58.5rem, 13.3rem, 38rem) (90deg); } { : ; : ; : (to bottom, #8a683d, #b78549); : (61.8rem, 14.4rem, 46.5rem) (90deg); } { : solid ; : solid ; } { : solid ; : solid ; } { : ; : ; : ; : (55rem, 13.6rem, 43.7rem) (90deg) (-19deg); } { : ; : ; : ; : (53.5rem, 13.5rem, 39.2rem) (-3deg); } { : ; : ; : ; : (52rem, 12.7rem, 46.7rem) (90deg); } { : ; : ; : ; : (12.7rem, 16.5rem, 40rem); } { : ; : ; : ; : (-11rem, 17.7rem, 18.7rem) (90deg); } { : ; : ; : ; : (10rem, 17rem, 5rem); } { : ; : ; : ; : (52rem, 13.2rem, 31.7rem) (90deg); } { : ; : ; : ; : (63rem, 12.5rem, 47.7rem) (90deg) (-19deg); } .veranda [class*='wedge'] border-top-left-radius 6px border-top-right-radius 6px border-top 1px #b5854a .veranda .wedges [class*='border-right'] border-right 3px #8a683d .veranda .wedges [class*='border-left'] border-left 3px #8a683d .veranda .wedge1 width 0.6rem height 2rem background linear-gradient transform translate3D rotateY .veranda .wedge2 width 0.7rem height 2.3rem background linear-gradient transform translate3D rotateY .veranda .wedge3 width 0.8rem height 2.6rem background linear-gradient transform translate3d rotateY .veranda .wedge4 width 1rem height 2.8rem background linear-gradient transform translate3D .veranda .wedge5 width 1.3rem height 2.8rem background linear-gradient transform translate3D .veranda .wedge6 width 1rem height 2.8rem background linear-gradient transform translate3D .veranda .wedge7 width 1rem height 3rem background linear-gradient transform translate3D .veranda .wedge8 width 0.7rem height 2.3rem background linear-gradient transform translate3D rotateY .veranda .wedge9 width 0.6rem height 1.7rem background linear-gradient transform translate3D rotateY .veranda .planks [class*='border-right'] border-right 2px #78552c border-top 2px #b5854a .veranda .planks [class*='border-left'] border-left 3px #78552c border-top 2px #b5854a .veranda .plank1 width 4.7rem height 0.7rem background-color #795b36 transform translate3D rotateY rotateZ .veranda .plank2 width 1.7rem height 0.7rem background-color #806139 transform translate3D rotateZ .veranda .plank3 width 8.8rem height 0.7rem background-color #8a683d transform translate3D rotateY .veranda .plank4 width 30rem height 0.9rem background-color #8a683d transform translate3D .veranda .plank5 width 34rem height 1rem background-color #46341f transform translate3D rotateY .veranda .plank6 width 38rem height 0.9rem background-color #46341f transform translate3D .veranda .plank7 width 17rem height 0.8rem background-color #8a683d transform translate3D rotateY .veranda .plank8 width 4.5rem height 0.7rem background-color #8a683d transform translate3D rotateY rotateZ Building our characters With the structure in place, we need some persons to move in and out of the house to show it is habitable. In the initial draft of this project, creating the characters was not in the picture but afterward, when the idea popped up, I thought it was a good one. Creating the characters and their animations gave the house scene a livelier look. To build the characters, we need both persons to walk into the house with their starting point at the foot of the stairs. The first person will be going in through the door and this is where the door-open we created earlier comes in handy. The second person will be moved to the end of the front-side of the house and both persons will return to their starting points and move past that point a little further. div Both character shapes are made up of 2 main parts, the heads and bodies. The legs are added using pseudo-elements on the body. So, both characters take one styling. < = > div class "person" < = > div class "person-one" < = > figure class "head" </ > figure < = > figure class "body" </ > figure </ > div < = > div class "person-two" < = > figure class "head" </ > figure < = > figure class "body" </ > figure </ > div </ > div Each of the parts is absolutely positioned and is used to create the round shapes. The leg pseudo-elements are described at once then each positioned in separate rules. The CSS rules are as follows: border-radius , { : black; : block; : absolute; } , { : ; : ; : ; : ; : ; } , { : ; : ; : ; : ; } , , , { : ; : absolute; : black; : ; : ; : ; } , { : ; } , { : ; } .person .person-one figure .person .person-two figure background-color display position .person .person-one .head .person .person-two .head border-radius 22px width 20px height 20px left 3px top 0 .person .person-one .body .person .person-two .body border-radius 30px 30px 0 0 height 30px top 21px width 26px .person .person-one .body :before .person .person-one .body :after .person .person-two .body :before .person .person-two .body :after content "" position background-color width 9px height 15px top 30px .person .person-one .body :before .person .person-two .body :before left 3px .person .person-one .body :after .person .person-two .body :after left 14px With the character shape of person-one and person-two specified, we will position them at the starting position. The person-one at the foot of the staircase, and the person-two a little further away from person-one. And we will also want to make person-two appear just right after person-one is being animated or start climbing the stairs. To set this up, we will give a scale of 0 to person-two and delay its animation for 5.5 seconds. { : (935px, 179px, 780px) (0deg); : move-person-one infinite; } { : (935px, 179px, 790px) (0deg) (0); : move-person-two infinite; } .person .person-one transform translate3d rotateY animation 20s 3s .person .person-two transform translate3d rotateY scale animation 15s 5.5s Keyframe animation With the characters in place, the scene is ready for some animation. If you you’ll see a few animations taking place. Rather than go through all the animations that set up the scene, I’ll focus on the animation of the character walking in and out of the house and also on the opening and closing of the door. view the demo Timing and animating the HTML elements is achieved by using and then attaching the set of keyframes to an element using the property. keyframes animation The first thing is to animate the first character, to have it walk up the stairs and into the front door, walk into the house and out and approach the stairs again. Here’s a set of keyframes that achieves this: @ move-person-one { 0%, 10%, 90% { : (935px, 179px, 780px) (0deg); } 20%, 85% { : (870px, 169px, 610px) (0deg); } 30%, 80% { : (870px, 175px, 610px) (86deg); } 40%, 45%, 70% { : (635px, 215px, 415px) (86deg); } 55%, 50% { : (620px, 215px, 405px) (86deg); } 91% { : (945px, 179px, 810px) (0deg); } 100% { : (945px, 179px, 990px) (0deg); } } keyframes transform translate3d rotateY transform translate3d rotateY transform translate3d rotateY transform translate3d rotateY transform translate3d rotateY transform translate3d rotateY transform translate3d rotateY Keyframes are a series of steps, described using percentages. The percentage relates to the animation time, so that if an animation was to last 10 seconds, 10% would be the 1-second mark. 90% would be the 9-second mark. Next, we animate the door that opens each time the first character goes inside the house and closes when it leaves the house. The timing of when the first character approaches the front door and the time the door opens and vice-versa should be properly calculated. First, we will establish the same duration time of 20 seconds for both the first character and the door. Afterward, we delay the first-character for 3 seconds and the door for 8 seconds, so this corresponds to the interaction described above. Next, immediately the door animation starts, we will transform its z-axis to 20-degrees and rotate its y-axis at 20-degrees and move the degrees higher at 4 seconds into the animation. This animates the door by opening it wide enough for the character to pass through and close it at about the 9th second. I repeated the same animation after the 10th second till the end of it. { : door-open infinite; } @ door-open { 0% { : (0px, 0px, 20px) (20deg); } 8%, 50% { : (0px, 0px, 53px) (53deg); } 35%, 70%, 100% { : (0px, 0px, 0px) (0deg); } } .doors .door-close animation 20s 8s keyframes transform translate3d rotateY transform translate3d rotateY transform translate3d rotateY Having done that, let’s set up the corresponding keyframes for the second character. It will start its movement just like first-character, climbs the stairs and move to to the far end of the house’s front view and make its return. animation @ move-person-two { 0%, 10%, 80% { : (935px, 179px, 790px) (0deg) (1); } 20%, 75% { : (870px, 169px, 610px) (0deg); } 30%, 70% { : (860px, 169px, 380px) (0deg); } 35%, 65% { : (860px, 169px, 380px) (89deg); } 40%, 60% { : (795px, 169px, 380px) (89deg); : ; } 41%, 50% { : ; } 81% { : (965px, 179px, 820px) (0deg); : ; } 82% { : (995px, 189px, 855px) (89deg); } 100% { : (1200px, 179px, 860px) (89deg); } } keyframes transform translate3d rotateY scale transform translate3d rotateY transform translate3d rotateY transform translate3d rotateY transform translate3d rotateY opacity 1 opacity 0 transform translate3d rotateY opacity 1 transform translate3d rotateY transform translate3d rotateY In this way, the two animations are being applied. The first character taking five more seconds later than the first to go through the animated cycle. With the following animations and keyframes in place, the final result will be this: Demo and source code If you haven’t already, in a modern browser or download the . check out the finished result source from Github