33

CSS cube

I have this and I want to make a cube with HTML & CSS only like in the above image. My best try:

.mainDiv{
  position: relative;
  width: 206px;
  height: 190px;
  margin: 0px auto;
  margin-top:100px;
}
.square{
  width:100px;
  height:100px;
  background:#c52329;
  border:solid 2px #FFF;
  float:left;
  transform: skew(180deg,210deg);
  position: absolute;
  top: 43px;
}
.square2{
  width:100px;
  height:100px;
  background:#c52329;
  border:solid 2px #FFF;
  float:left;
  transform: skew(180deg,150deg);
  position: absolute;
  left:102px;
  top: 43px;
}
.square3{
  width:100px;
  height:100px;
  background:#c52329;
  border:solid 2px #FFF;
  float:left;
  transform: skew(180deg,180deg);
  position: absolute;
  left: 51px;
  top: -61px;
}
<div class="mainDiv">
  <div class="square"></div>
  <div class="square2"></div>
  <div class="square3"></div>
</div>
web-tiki
  • 99,765
  • 32
  • 217
  • 249
Sunil Gehlot
  • 1,549
  • 2
  • 17
  • 32
  • http://css3gen.com/css-3d-transform/ – Lalji Tadhani Mar 31 '16 at 11:10
  • 2
    Are you aware of the possibility of using Stack Snippets to provide the demo *inside the question* instead of using a third-party application? It's just a matter of putting two comments instead of your hand-made `**HTML**` headings and you'd get it here (and if you want you can still *add* a link to the external source). – Bakuriu Mar 31 '16 at 14:59
  • 1
    You can use transform to achieve this. See http://tt-cc.cc/web-app/css3-3d-shape-generator/ – TTCC Jul 29 '16 at 02:48

9 Answers9

24

According to your HTML, I get this JSFiddle. I just played with transform.

.mainDiv{
  position: relative;
  width: 206px;
  height: 190px;
  margin: 0px auto;
  margin-top:100px;
}
.square{
  width:100px;
  height:100px;
  background:#c52329;
  border:solid 2px #FFF;
  transform: skew(180deg,210deg);
  position: absolute;
  top: 43px;
}
.square2{
  width:100px;
  height:100px;
  background:#c52329;
  border:solid 2px #FFF;
  transform: skew(180deg,150deg);
  position: absolute;
  left:102px;
  top: 43px;
}
.square3{
  width:114px;
  height:100px;
  background:#c52329;
  border:solid 2px #FFF;
 

transform: rotate(150deg) translate(-40px, -16px) skew(30deg, 0deg);
  position: absolute;
  left: 0px;
  top: -32px;
}
<div class="mainDiv">
  <div class="square"></div>
  <div class="square2"></div>
  <div class="square3"></div>
</div>

Updated CSS

.square3{
  width:114px;
  height:100px;
  background:#c52329;
  border:solid 2px #FFF;
  transform: rotate(150deg) translate(-40px, -16px) skew(30deg, 0deg);
  position: absolute;
  left: 0px;
  top: -32px;
}

I changed transform CSS with this.


Extra: David Walsh has a cool animated version on an cube. Apart from the fact that it looks kinda cool, by fiddling with the settings you can learn quite a lot about it.

BSMP
  • 4,596
  • 8
  • 33
  • 44
Leo the lion
  • 3,164
  • 2
  • 22
  • 40
  • @NiettheDarkAbsol, will tell you in detail.. I just played with transform and got the shape..but will sure answer you or will update the answer.. – Leo the lion Mar 31 '16 at 11:32
  • And for 390-degree skew, i used this from here http://www.css3-generator.de/transform.html – Leo the lion Mar 31 '16 at 11:33
  • That site not only has incorrect ranges for skews (notice how it wraps around when you set the skew to cross over the 90 degree steps?) but also denies that any browser other than Chrome supports 3d-transforms, which has been wrong for a very long time... – Niet the Dark Absol Mar 31 '16 at 11:36
  • About the skew limit, m not sure there is limitation like from -90 to +90..look at other answers too..well m not arguing but asking so can improve my knowledge..:) – Leo the lion Mar 31 '16 at 11:38
  • It's a bit like saying "rotate by 450 degrees" - it's silly when you could just "rotate by 90 degrees" instead. `(-90;90)` is the normal range for skew. – Niet the Dark Absol Mar 31 '16 at 11:48
  • 1
    @Niet the Dark Absol: Rotating or skewing more than 360 degrees makes sense when it's being animated, as the user can then observe the element going through multiple rotations. It's silly when it's not being animated, though. – BoltClock Mar 31 '16 at 12:38
  • 1
    I've added an example by David Walsh to the answer. This has a great learning chance about the perspective workings. – Martijn Mar 31 '16 at 14:12
  • 1
    True words..Today in the morning i showed this example to my senior that wish i could have make like that and was reading his full blog and even played the game of david walsh.. thanx for adding..:) – Leo the lion Mar 31 '16 at 14:16
  • 2
    and even i updated my skype status to david's line that "Users can be very dumb but it's still the developer's fault for not making something easy enough." – Leo the lion Mar 31 '16 at 14:17
  • @Leothelion your floats aren't doing anything to absolutely positioned elements. Hence why you are using `left:Xpx`. https://stackoverflow.com/questions/11333624/float-right-and-position-absolute-doesnt-work-together – nihiser Feb 14 '18 at 15:57
21

You can also achieve a cube with 3d transforms. This will give your cube a more realistic perspective. As if the cube was a real 3d shape like this:

3d cube with 3d transforms

In the following I used one div with 2 pseudo elements :

body {
  perspective: 900px;
  padding-bottom:50%;
}
div {
  position: relative;
  width: 20%;
  padding-bottom: 20%;
  margin: 0 auto;
  transform-style: preserve-3d;
  background: #C52329;
  transform: rotateX(60deg) rotatez(45deg);
}
div:before, div:after {
  content: '';
  position: absolute;
  width: 100%;
  height: 100%;
  transform-origin: -2% -2%;
  background: inherit;
}
div:before {
  top: 104%; left: 0;
  transform: rotateX(-90deg);
}
div:after {
  top: 0; left: 104%;
  transform: rotateY(90deg);
}
<div></div>

CSS 3d cube with 6 faces:

This technique allows you to make a "real cube" with 6 faces:

rotating 3d cube with 6 faces

body{
  perspective-origin:50% -100%;
  perspective: 900px;
  overflow:hidden;
}
h1{position:absolute;font-family:sans-serif;}
.cube {
  position:relative;
  padding-bottom:20%;
  transform-style: preserve-3d;
  transform-origin: 50% 100%;
  transform:rotateY(45deg) rotateX(0);
  transition:transform 3s;
}
.cubeFace {
  position: absolute;
  left:40%;top:0;
  width: 20%;height:100%;
  margin: 0 auto;
  transform-style: inherit;
  background: #C52329;
  box-shadow:inset 0 0 0 5px #fff; 
  transform-origin:50% 50%;
  transform: rotateX(90deg);
  backface-visibility:hidden;
}
.face2{
  transform-origin:50% 50%;
  transform: rotatez(90deg) translateX(100%) rotateY(90deg);
}
.cubeFace:before, .cubeFace:after {
  content: '';
  position: absolute;
  width: 100%;
  height: 100%;
  transform-origin:0 0;
  background: inherit;
  box-shadow:inherit;
  backface-visibility:inherit;
}
.cubeFace:before {
  top: 100%; left: 0;
  transform: rotateX(-90deg);
}
.cubeFace:after {
  top: 0; left: 100%;
  transform: rotateY(90deg);
}

body:hover .cube{
  transform:rotateY(405deg) rotateX(360deg);
}
<h1>Hover me:</h1>
<div class="cube">
  <div class="cubeFace"></div>
  <div class="cubeFace face2"></div>
</div>

Note that I didn't add the vendor prefixes in the examples. For more info about browser support and what vendor prefixes are needed according to your target audience, see canIuse for 3d transforms.

web-tiki
  • 99,765
  • 32
  • 217
  • 249
15

Basically, you want to do 2 transformations:

  1. rotate the rectangle
  2. squeeze it (skew it)

so basically, you need to do a transform: rotate(x) skew(y, y) and play a bit with size and placing.

here's a little demo I created, based on your own demo:

(I did remove the borders since they felt unneeded to me)

.mainDiv{
  position: relative;
  width: 206px;
  height: 190px;
  margin: 0px auto;
  margin-top:100px;
}
.square{
  width:100px;
  height:100px;
  background:#c52329;
  float:left;
  transform: skew(180deg,210deg);
  position: absolute;
  top: 43px;
}
.square2{
  width:100px;
  height:100px;
  background:#c52329;
  float:left;
  transform: skew(180deg,150deg);
  position: absolute;
  left:102px;
  top: 43px;
}
.square3{
  width:110px;
  height:110px;
  background:#c52329;
  float:left;
  transform: rotate(45deg) skew(-15deg, -15deg);
  position: absolute;
  left: 46px;
  top: -42px;
}
<div class="mainDiv">
  <div class="square"></div>
  <div class="square2"></div>
  <div class="square3"></div>
</div>
Thatkookooguy
  • 6,669
  • 1
  • 29
  • 54
9

First let me point out that a skew angle should be between -90deg and 90deg, non-inclusive. All of your skews fall way outside this range.

Limiting myself to sensible skew numbers, it turned out to be quite simple:

.mainDiv{
  position: relative;
  width: 206px;
  height: 190px;
  margin: 0px auto;
  margin-top:100px;
}
.tile {
  width:100px;
  height:100px;
  background:#c52329;
  border:solid 2px #FFF;
  position: absolute;
}
.square{
  transform: skewY(30deg);
  top: 43px;
}
.square2{
  transform: skewY(-30deg);
  left:102px;
  top: 43px;
}
.square3{
  height: 58px;
  left: 50px;
  top: -18px;
  transform: skew(60deg, -30deg);
}
<div class="mainDiv">
  <div class="tile square"></div>
  <div class="tile square2"></div>
  <div class="tile square3"></div>
</div>

Job done. I've also tidied up the huge repetition of styles into a common class for you.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
6

Changing the CSS for .square3 should do it:

height: 58px;
left: 50px;
position: absolute;
top: -18px;
transform: skew(240deg, 150deg);
width: 100px;

https://jsfiddle.net/8vuj7peb/26/

Thatkookooguy
  • 6,669
  • 1
  • 29
  • 54
Nick R
  • 7,704
  • 2
  • 22
  • 32
6

Use the following css for .square3:

.square3{
  width:110px;
  height:110px;
  background:#c52329;
  float:left;
  transform: rotate(45deg) skew(-15deg, -15deg);
  position: absolute;
  left: 46px;
  top: -42px;
}
Thatkookooguy
  • 6,669
  • 1
  • 29
  • 54
6

A single box and 2 pseudos can do this as well.

http://codepen.io/gc-nomade/pen/vGeajp

#square {

  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 5px;
  background: #C52329;
  /*box-shadow: 0 0 5px;*/
  width: 90px;
  height: 150px;
  margin: 5em;
  position: relative;
  transform: skew(30deg) rotate(30deg);
}

#square:before,
#square:after {
  display: inherit;
  align-items: center;
  justify-content: center;
  content: 'before';
  position: absolute;
  top: 0;
  left: 2px;
  right: -2px;
  bottom: 0;
  background: inherit;
  border-radius: inherit;
  box-shadow: inherit;
  transform: translate(100%, -31%) skew(0, -45deg) rotate(0deg);
}
#square:after {
  content: 'after';
  top: -2px;
  left: 0%;
  height: 60%;
  right: 0;
  bottom: 2px;
  transform: translate(50%, -100%) rotate(0deg)skew(-45deg)
}
<div id="square">
  boxe
</div>
G-Cyrillus
  • 101,410
  • 14
  • 105
  • 129
2

I seen this and thought I would add something I came up with while trying to make some old fashioned abc blocks. Making them into 3d I only had to label the main container with another class to change positions and saved on the code. I commented the tutorial in the code. Hope this helps someone. :)

          
/*-------------------------------------------------------------   
First we need to create our container for later reference
    -I put this to show in the center of the screen if you wanted to 
    copy and paste the code into a document for play. 
    -The width is just to give the margin auto something to center on. 
    -You really on need the element itself to reference later, but this is prettier
-------------------------------------------------------------*/
.box{
    width: 100px;
    margin: 200px auto;
    text-align: center;
    line-height: 5;
}

/*---------------------------------------------------------------------------
The box-wrapper is our real hero container here. This is where we nail our box together. 
    -set this to relative position for child elements to reference to.
    -transform-style is set to preserve-3d because I wanted to keep the look as the text turns with the box. You can also set this to flat, but its not near as cool. 
---------------------------------------------------------------------------*/


.box-wrapper{
    position: relative;
    transform-style: preserve-3d;
    -webkit-transform-style: preserve-3d;    
}
/*-------------------------------------------------------------------------
Here I am just giving the box its needed dimesions and setting them to absolute so nothing gets any ideas of wandering off.
    -PLEASE NOTE: the border has 2px and our w:98 h:98 making it a total of 100px. (this is important when we translate later)
-------------------------------------------------------------------------*/
.box-wrapper div{
    width: 98px;
    height: 98px;
    position: absolute;    
    border: 2px solid black;
    border-radius: 5px;
}

/*----------------------------------------------------------------------
Since our sides are 100px we only need to move our box sides 50px to get the edges to match up without gaps.
    -Meaning "translate" moves to the position relative to your .box-wrapper. (You can play with this code to see it in action, try to take a visible section of the box and take it down 10). 
    -Also I use "rotate" y and x to turn our box sheets (.box-wrapper div's)
-----------------------------------------------------------------------*/
.front{
    transform: translateZ(50px) rotateY(0deg);
}
.back{
    transform: translateZ(-50px) rotateY(180deg);
}
.top{
    transform: translateY(-50px) rotateX(90deg);
}
.bottom{
    transform: translateY(50px) rotateX(-90deg);
}

.right{
    transform: translateX(50px) rotateY(90deg);
}
.left{
    transform: translateX(-50px) rotateY(270deg);
}

/*-----------------------------------------------------------------------
Then after all of this we can use our cool box-wrapper to turn this baby
Hope this is helpful! :) Enjoy!
-------------------------------------------------------------------------*/

.box .box-wrapper{
    transform: rotateX(-30deg) rotateY(-40deg);
}
.box .box-wrapper div{
    background-color: yellow;
}
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Bob the box builder</title>
        <link rel="stylesheet" type="text/css" href="boxstyle.css">
        <style>
            

        </style>
    </head>
    <body>
<!--Create our box that holds our stuff -->
           <div class="box">
<!--Create our real container that keeps our box sides nailed together-->
                    <div class="box-wrapper">
<!--Make our box sheets that we will nail together with css-->
                        <div class="front">Front</div>
                        <div class="back">Back</div>
                        <div class="left">Left</div>
                        <div class="right">Right</div>
                        <div class="top">Top</div>
                        <div class="bottom">Bottom</div>
                    </div>
                </div>
    </body>
</html>
HeroZero
  • 143
  • 6
1
      y         
      |          
      |____ x 
     ╱        
    z 

Imagine a cube from the front side. What you can see? A square that comes out over the screen. So, for the front side, we have:

.front {
  transform : translateZ(50px);
}

for the right side, we have a square that is rotated 90 degrees on Y-Axis and moved on own new Z-Axis:

.right {
  transform : rotateY(90deg) translateZ(50px);
}

for the left side, we have a square that is rotated -90 degrees on Y-Axis and moved on own new Z-Axis:

.right {
  transform : rotateY(-90deg) translateZ(50px);
}

for the top side, we have a square that is rotated 90 degrees on X-Axis and moved on own new Z-Axis:

.right {
  transform : rotateX(90deg) translateZ(50px);
}

for the back side, we have a square that is rotated -180 degrees on Y-Axis and moved on own new Z-Axis:

.right {
  transform : rotateY(-180deg) translateZ(50px);
}

Then, Just package them in a shape container class with transform-style: preserve-3d property:

.cube {
  transform-style: preserve-3d;
}

finally, you can rotate your cube and see the CSS-3D magic.

.cube {
  transform-style: preserve-3d;
  transform: rotateX(-40deg) rotateY(45deg);
}

.cube {
  transform-style: preserve-3d;
  transform: rotateX(-40deg) rotateY(45deg);
}

.side {
  position: absolute;
  width: 100px;
  height: 100px;
  background: #c52329;
  border: solid 3px white;
}

.front {
  transform: translateZ(53px);
}

.top {
  transform: rotateX(90deg) translateZ(53px);
}

.right {
  transform: rotateY(90deg) translateZ(53px);
}

.left {
  transform: rotateY(-90deg) translateZ(53px);
}

.bottom {
  transform: rotateX(-90deg) translateZ(53px);
}

.back {
  transform: rotateY(-180deg) translateZ(53px);
}
<div class="cube">
  <div class="side front"></div>
  <div class="side back"></div>
  <div class="side right"></div>
  <div class="side left"></div>
  <div class="side top"></div>
  <div class="side bottom"></div>
</div>
It is a full cube. For your approach, you can ignore the back, right, and bottom sides.

Thanks to css-tricks.com