Como hacer un cubo 3D con CSS3

Con CSS3 se pueden hacer tanto transformaciones 2D como 3D y aquí vamos a ver lo sencillo que es crear un cubo utilizando únicamente CSS3 y luego veremos como poder animarlo usando también únicamente CSS3.

Estructura HTML

Empecemos, lo primero es definir la estructura HTML para poder hacer un cubo para lo que necesitamos un elemento que haga de cubo como tal, sus 6 caras que serán las que tendremos que transformar para formar el cubo y también es necesario que el cubo este dentro de un «contenedor», luego veremos porque.


<div class="contenedor"> 
    <div class="cubo">
        <div class="cara"></div>
        <div class="cara"></div>
        <div class="cara"></div>
        <div class="cara"></div>
        <div class="cara"></div>
        <div class="cara"></div>
    </div>
</div>

Cada cara hay que tratarla de forma individual porque cada una tendrá una combinación de posición y orientación única por lo que tenemos 2 alternativas:

  • Añadir un identificador a cada cara, cara-superior, cara-derecha, etc.
  • Diferenciar las caras por medio del selector de hijos de CSS3 (:nth-child(número)).

En este ejemplo usaré esta segunda opción para hacer más sencillo la generación dinámica de las caras al no tener que preocuparse de ponerles un identificador a cada una, incluso tampoco es necesario poner una clase a los elementos que hagan de caras…

Transformaciones 3D con CSS3

El resultado que vamos a conseguir es un cubo en 3D con bordes y con un pequeño grado de transparencia en las imágenes para que se vea ligeramente el cubo por dentro y los bordes ayudan a que se vea mejor pero tanto los bordes como la transparencia son independientes de la forma en la que se construye el cubo, aunque si se quitan los bordes no hay que olvidar aumentar el tamaño de la imagen para que ocupe lo mismo que en el caso de que tuviese los bordes.

Con CSS3 hacer transformaciones en 3D es tan sencillo como saber cuanto hay que rotar y/o desplazar cada parte para conseguir la figura deseada y un cubo es de las figuras más simples que hay.

Lo primero que hay que hacer es definir la perspectiva, es decir, desde donde se va a ver el cubo, cuanto mayor sea la distancia menor será el efecto 3D lo mismo que sucede en el mundo real y como pasa en la realidad la perspectiva no depende del objeto sino de la posición desde la que se mira por eso es necesario un contenedor, para definir la perspectiva desde la que se vera el cubo.


.contenedor {
    perspective: 1000px;
    perspective-origin: 50% 50%;
}

.cubo, .cubo .cara{
    height: 290px;
    width: 290px;
}

.cubo {
    transform-style: preserve-3d;
    transform: rotateX( 0deg ) rotateY( -30deg );
    margin: 200px auto;
}

El cubo estará en 3D y sus caras también lo deben estar por eso es necesario usar transform-style: preserve-3d y de esta forma se podrán hacer transformaciones 3D en el cubo y en las caras del cubo. Para poder ver como se ve el cubo en 3D lo mejor es rotarlo un poco y asi se veran tres de sus caras para que se pueda apreciar perfectamente que es un cubo.

Para que las caras se puedan colocar de forma correcta es necesario que tengan un posicionamiento absoluto. Vamos a ver como hay que transformar cada cara para formar el cubo. En un principio las 6 caras aparecerán unas sobre otras ya que están posicionadas de forma absoluta por lo que tendremos que hacer una combinación de translaciones y rotaciones en cada cara para colocarla en su sitio.

El tamaño de las caras en el ejemplo es de 300px (290px de ancho + 5px de borde derecho + 5 px de borde izquierdo) y como las caras están en el centro habrá que desplazarlas la mitad del ancho de cada cara (150px). Vamos a desplazar todas las caras 150px

Antes de empezar con las transformaciones concretas hay que tener en cuenta que las transformaciones se van haciendo en el orden en el que están puestas, por ejemplo para las transformaciones siguientes en la primera primero se rota 90° respecto al eje Y y luego se traslada 150px por lo que con esta transformación se conseguiría la cara derecha del cuadrado, mientras que en la segunda primero se hace la translación por lo que se hace hacia delante y luego se gira por lo que con esta transformación se conseguiría una cara que cortase perpendicularmente por el centro con la cara frontal del cubo.


transform: rotateY(90deg) translateZ(150px);
transform: translateZ(150px) rotateY(90deg);

Recordemos la posición de los ejes para tener claro que estamos haciendo, el eje X corta la pantalla en horizontal, el Y en vertical y el Z es el que marca la profundidad. Una vez recordado y entendido como se hacen las transformaciones vamos con las transformaciones para cada cara.

  • Cara frontal: esta cara solo hace falta trasladarla hacia adelante.
  • Cara posterior: hay que trasladarla hacia atrás, y aunque podamos tener la tentación de simplemente trasladarla hacía atrás (translateZ(-150px)) lo que hay que hacer es primero rotar la cara 180° respecto al eje Y para que quede mirando hacia atrás y luego hacer un desplazamiento positivo y así la imagen quedará correctamente si usásemos el primer método la imagen quedaría al revés (como si la viésemos en un espejo).
  • Cara izquierda: primero se rota 90° hacia la izquierda (-90°) y luego se desplaza.
  • Cara derecha: lo mismo que la izquierda pero rotando sobre el eje Y hacia la derecha.
  • Cara superior: para conseguir esta cara hay que rotar 90° hacia arriba, es decir, sobre el eje X y luego hacer la translación.
  • Cara inferior: igual que la cara superior pero rotando -90° para que quede hacia abajo.

.cubo .cara {
    position: absolute;
    border: 5px solid #000;
    opacity: 0.95;
}

/*Cara frontal*/

.cubo .cara:nth-child(1) {
    transform: translateZ(150px);
}
/*Cara posterior*/

.cubo .cara:nth-child(2) {
    transform: rotateY(180deg) translateZ(150px);
}
/*Cara izquierda*/

.cubo .cara:nth-child(3) {
    transform: rotateY(-90deg) translateZ(150px);
}
/*Cara derecha*/

.cubo .cara:nth-child(4) {
    transform: rotateY(90deg) translateZ(150px);
}
/*Cara superior*/

.cubo .cara:nth-child(5) {
    transform: rotateX(90deg) translateZ(150px);
}
/*Cara inferior*/

.cubo .cara:nth-child(6) {
    transform: rotateX(-90deg) translateZ(150px);
}

Puede parecer extraño que siempre estemos haciendo la misma translación de 150px sobre el eje Z, pero la razón de esto es que cuando se hace la rotación se rota el sistema de coordenadas también por lo que lo que estamos haciendo es rotar para conseguir la orientación correcta y luego desplazarlo hacia adelante (en la dirección en la que esta colocada la cara) para colocarlo en la posición correcta.

Esta no es la única forma de hacer el cubo y se pueden usar otras combinaciones de rotaciones y translaciones, por ejemplo para conseguir la cara izquierda podríamos usar transform: translateX(-150px) rotateY(-90deg); y así primero colocaríamos la cara izquierda en su posición y luego de daríamos la orientación correcta y podríamos hacer lo mismo con el resto de caras teniendo en cuenta que habría que hacer la translación antes del giro y hacerla sobre el eje correspondiente y el giro se mantendría igual.


/*Cara frontal*/

.cubo .cara:nth-child(1) {
    transform: translateZ(150px);
}
/*Cara posterior*/

.cubo .cara:nth-child(2) {
    transform: translateZ(-150px) rotateY(180deg);
}
/*Cara izquierda*/

.cubo .cara:nth-child(3) {
    transform: translateX(-150px) rotateY(-90deg);
}
/*Cara derecha*/

.cubo .cara:nth-child(4) {
    transform: translateX(150px) rotateY(90deg);
}
/*Cara superior*/

.cubo .cara:nth-child(5) {
    transform: translateY(-150px) rotateX(90deg);
}
/*Cara inferior*/

.cubo .cara:nth-child(6) {
    transform: translateY(150px) rotateX(-90deg);
}

Puedes comprobar ambos métodos y veras que el resultado es el mismo.

See the Pen CSS3 3D cube with images by Ivan Salas (@isc7) on CodePen

Animando el cubo con CSS3

Una vez conseguido el cubo ya podemos animarlo para que de vueltas a nuestro gusto, por ejemplo podemos hacer que gire 360° respecto al eje X e Y y el cubo girará de forma que podemos ver todas sus caras, aunque de una forma un poco caótica ya que veremos las imágenes de lado, boca abajo o en la orientación que salga por lo que esta animación quizás no sea la mejor, aunque desde luego es una opción.


@keyframes giro360 {
    0% { transform: rotateX(   0deg ) rotateY(   0deg ); }
    100% { transform: rotateX( 360deg ) rotateY( 360deg ); }
}

Una opción para ver todas las imágenes en la posición correcta es la siguiente, aunque las imágenes superior e inferior no se llegan a ver totalmente de frente el resultado yo creo que es bastante bueno para lo sencillo de la animación.


@keyframes giro {
    0% { transform: rotateX(  -45deg ) rotateY(   0deg ); }
    50% { transform: rotateX(  45deg ) rotateY(   360deg ); }
    100% { transform: rotateX( -45deg ) rotateY( 720deg ); }
}

Y si se quiere conseguir una animación en la que todas las caras se vean totalmente de frente en algún momento pues solo es cuestión de ir metiendo más pasos a la animación y hacer bien los cálculos para que la animación no de saltos bruscos.

Y no hay que olvidarse de poner la animación al cubo.


.cubo {
    animation: giro 20s infinite linear;
}

See the Pen CSS3 3D cube animated with images by Ivan Salas (@isc7) on CodePen

Cubo 3D con esquinas redondeadas usando solo CSS3

Si usamos esquinas redondeadas en las caras del cubo esto no se traslada a que se forme una esquina redondeada entre las 3 caras del cubo que forman la esquina, pero podemos simular este efecto con un poco de imaginación y no demasiado esfuerzo para conseguir un cubo con esquinas redondeadas en 3D y solo usando CSS3.

Si a las caras del cubo que hemos estado haciendo le haces las esquinas redondeadas veras que como no podía ser de otra forma por los huecos que quedan se ve el interior del cubo, por lo que la primera idea que se me ocurrió fue crear algo que las tapase pero claro la forma que se necesita es una especie de triangulo con las esquinas dobladas hacia adentro y creo que eso con CSS3 no se puede hacer por lo que la siguiente idea que me vino a la cabeza fue que el cubo fuese por dentro del mismo color que los bordes y así parecía que las esquinas son redondeadas aunque ciertamente siguiesen siendo como antes.

Para que el cubo sea del color que queramos por dentro pues ¿que hay más sencillo que hacer un cubo exactamente igual pero desplazado un pixel hacia adentro para que no tape las caras del cubo?


<div class="contenedor"> 
    <div class="cubo">
        <div class="cara">
            <img src="img/img1.png" title="Soto y Caldevilla de Valdeón" alt="Soto y Caldevilla de Valdeón" height: "290px" width="290px" >
        </div>
        <div class="cara">
            <img src="img/img2.png" title="Un poco de nieve en agosto" alt="Un poco de nieve en agosto" width="290px" height: "290px">
        </div>
        <div class="cara">
            <img src="img/img3.png" title="Un rebeco" alt="Un rebeco" width="290px" height: "290px">
        </div>
        <div class="cara">
            <img src="img/img4.png" title="Posada de Valdeón" alt="Posada de Valdeón" width="290px" height: "290px">
        </div>
        <div class="cara">
            <img src="img/img5.png" title="Refugio de Pantivalles" alt="Refugio de Pantivalles" width="290px" height: "290px">
        </div>
        <div class="cara">
            <img src="img/img6.png" title="Unas montañas" alt="Unas montañas" width="290px" height: "290px">
        </div>
        <div class="cara-fondo"></div>
        <div class="cara-fondo"></div>
        <div class="cara-fondo"></div>
        <div class="cara-fondo"></div>
        <div class="cara-fondo"></div>
        <div class="cara-fondo"></div>
        <div class="cara-fondo"></div>
        <div class="cara-fondo"></div>
        <div class="cara-fondo"></div>
    </div>
</div>    

Añadimos las caras para formar el otro cubo dentro y hacemos las transformaciones con CSS3 para que se forme el cubo pero teniendo cuidado de que quede dentro del otro y el resultado es que ya parece que tenemos esquinas redondeadas aunque aun se pueden ver algunos huecos por dentro, por eso si te has fijado hay 9 caras para el nuevo cuadrado, cuando solo son necesarias 6 pero esas 3 sobrantes las usamos para crear una cruz en el centro del cubo (estas caras estarán alineadas con los ejes de forma que dividen al cubo en 4 cubos más pequeños) y así impedir que se vea por una esquina el agujero de otra esquina cuando estén alineadas.


/************Caras fondo*************/

/*Cara frontal*/

.cubo .cara-fondo:nth-child(7) {
    transform: translateZ(149px);
}
/*Cara posterior*/

.cubo .cara-fondo:nth-child(8) {
    transform: rotateY(180deg) translateZ(149px);
}
/*Cara izquierda*/

.cubo .cara-fondo:nth-child(9) {
    transform: rotateY(-90deg) translateZ(149px);
}
/*Cara derecha*/

.cubo .cara-fondo:nth-child(10) {
    transform: rotateY(90deg) translateZ(149px);
}
/*Cara superior*/

.cubo .cara-fondo:nth-child(11) {
    transform: rotateX(90deg) translateZ(149px);
}
/*Cara inferior*/

.cubo .cara-fondo:nth-child(12) {
    transform: rotateX(-90deg) translateZ(149px);
}

/*Caras interiores para formar una cruz en el centro*/

.cubo .cara-fondo:nth-child(13) {
    transform: rotateX(180deg);
}
.cubo .cara-fondo:nth-child(14) {
    transform: rotateY(90deg);
}
.cubo .cara-fondo:nth-child(15) {
    transform: rotateX(90deg);
}   

Con esto ya casi tenemos terminado el trabajo porque ya cuando las esquinas están pasando por la parte frontal del cubo se ven totalmente redondeadas pero cuando la esquina aparece y desaparece al hacer el giro e irse hacia la parte de atrás se nota ligeramente que esta hueca por lo que parece que nos vamos a quedar con las ganas de tener nuestro cubo 3D CSS3, pero hay una solución sencilla aunque no 100% perfecta si miras el cubo con lupa, pero sino parece una esquina perfectamente redondeada. Y esta solución no es más que las caras del cubo interior tengan sus esquinas ligeramente menos redondeadas que las caras del cubo de forma que tapan el hueco cuando las esquinas están apareciendo o desapareciendo pero no se ve que sobresalgan, para este ejemplo la combinación «perfecta» es la siguiente.


.contenedor {
    perspective: 1000px;
    perspective-origin: 50% 50%;
}
.cubo, .cubo .cara, .cubo .cara-fondo {
    height: 290px;
    width: 290px;
}

.cubo {
    transform-style: preserve-3d;
    transform: rotateX( 0deg ) rotateY( -30deg );
    margin: 200px auto;
    animation: giro 20s infinite linear; /**/
}

.cubo .cara {
    position: absolute;
    border: 5px solid #000;
    border-radius: 25px;
}

.cubo .cara img {
    border-radius: 25px;
}

.cubo .cara-fondo{
    background: #000;
    position: absolute;
    border: 5px solid #000;
    border-radius: 19px;

}

También esta modificada la perspectiva respecto al ejemplo anterior para que se vea más pequeño. Y el resultado es este:

See the Pen CSS3 3D cube with rounded corners by Ivan Salas (@isc7) on CodePen

Y como siempre si quieres el código tanto del ejemplo del cubo normal (con y sin bordes), como el del cubo con esquinas redondeadas puedes descargarlo desde aquí, con este código funciona en Firefox, Chrome y Safari pero el del articulo solo funciona en Firefox, para que funcione en Chrome y Safari hay que añadir -webkit- delante de todas las propiedades de animación o transformación (en el código para descargar ya esta puesto y en los ejemplos de codepen también) y como de costumbre en IE no funciona ni tan siquiera en la versión 10, porque no tiene soporte para preserve-3d por lo que si quieres que se vea el cubo en 3D tienes que animar cada cara individualmente, si quieres puedes ver como lo ha hecho Stu Nicholls en CSS play y aunque no describe como lo ha hecho pues con ver el código de la página se ve en un momento que no es muy complicado, pero si quieres hacer una animación diferente…

3 Comments

  1. Saul Garcia 16 agosto, 2015 Reply
  2. Francisco Martinez Gich 22 marzo, 2017 Reply
    • Iván Salas 25 marzo, 2017 Reply

Leave a Reply