Transformaciones en CSS
En esta lección
- La propiedad transform
- Mover: translate()
- Escalar: scale()
- Girar: rotate()
- Inclinar: skew()
- Las propiedades individuales: translate, rotate y scale
- El punto de origen: transform-origin
- Combinar transformaciones: el orden importa
- Transformaciones en 3D
- Efectos secundarios que conviene saber
- Errores frecuentes
- Resumen
Una transformación cambia cómo se ve un elemento en pantalla: lo mueve, lo agranda, lo gira o lo inclina, incluso en tres dimensiones. Lo especial es que lo hace sin mover a los demás: el resto de la página se comporta como si el elemento siguiera en su sitio. Por eso las transformaciones son la base de casi todos los efectos al pasar el ratón y de las animaciones fluidas. En esta lección verás las cuatro funciones básicas, las propiedades individuales modernas, el punto de origen, por qué importa el orden y cómo hacer una tarjeta que gira en 3D.
La propiedad transform
transform recibe una o varias funciones de transformación:
.insignia { transform: rotate(-8deg); }
Una idea clave antes de empezar: la transformación es solo visual. El elemento sigue ocupando su hueco original en la página. Si mueves una caja 50px a la derecha con transform, la caja de al lado no se desplaza; como mucho, se solapan.
.boton:hover {
transform: translateY(-3px); /* sube 3px sin empujar nada */
}
Si lo hicieras con margin-top: -3px, todo lo que va debajo subiría también y la página “temblaría” al pasar el ratón.
Mover: translate()
.a { transform: translate(20px, 10px); } /* 20px a la derecha, 10px abajo */
.b { transform: translateX(-100%); } /* a la izquierda, todo su ancho */
.c { transform: translateY(8px); } /* 8px hacia abajo */
Los valores positivos van a la derecha y hacia abajo. Lo interesante son los porcentajes: se calculan sobre el tamaño del propio elemento, no del padre. translateX(-100%) mueve el elemento exactamente su propio ancho, mida lo que mida. Por eso se usa para menús laterales que se esconden fuera de la pantalla:
.menu-lateral { transform: translateX(-100%); } /* fuera, a la izquierda */
.menu-lateral.abierto { transform: translateX(0); }
Y por eso existe este truco clásico para centrar un elemento posicionado:
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%); /* retrocede la mitad de su propio tamaño */
}
top: 50% coloca la esquina superior en el centro; el translate la devuelve la mitad de su tamaño. Hoy hay formas más sencillas de centrar, que verás en centrar elementos.
Escalar: scale()
.a { transform: scale(1.1); } /* 10 % más grande */
.b { transform: scale(0.5); } /* a la mitad */
.c { transform: scale(2, 1); } /* el doble de ancho, mismo alto */
.d { transform: scaleX(-1); } /* espejo horizontal */
1 es el tamaño normal. Con un número negativo, el elemento se refleja: scaleX(-1) da la vuelta a un icono de flecha para que apunte al otro lado.
El texto escalado se agranda como una foto, sin reorganizarse. Para cambiar el tamaño real de un texto, usa font-size; scale es para efectos breves, como resaltar una tarjeta al pasar el ratón.
Girar: rotate()
.a { transform: rotate(45deg); } /* 45 grados en el sentido del reloj */
.b { transform: rotate(-10deg); } /* al revés */
.c { transform: rotate(0.5turn); } /* media vuelta = 180deg */
Un uso muy práctico: la flechita de un desplegable que gira cuando se abre.
.flecha { transition: transform 0.2s; }
details[open] .flecha { transform: rotate(180deg); }
Inclinar: skew()
skew inclina el elemento, como si empujaras de lado un rectángulo hasta convertirlo en un paralelogramo:
.a { transform: skewX(-15deg); }
.b { transform: skew(10deg, 5deg); } /* en X y en Y */
Es la menos usada. Queda bien en rótulos y etiquetas con aire deportivo. Si inclinas un contenedor, su texto se inclina también; para enderezarlo, aplica al hijo la inclinación contraria:
.etiqueta { transform: skewX(-15deg); }
.etiqueta span { display: inline-block; transform: skewX(15deg); }
Las propiedades individuales: translate, rotate y scale
Desde 2022, todos los navegadores admiten tres propiedades con el mismo nombre que las funciones:
.tarjeta {
translate: 0 -4px; /* x y, separados por espacio, sin comas */
rotate: 2deg;
scale: 1.05;
}
¿Para qué, si ya existe transform? Porque transform es una sola propiedad: si en el :hover cambias una función, tienes que repetir todas las demás o se pierden.
/* Con transform: hay que repetirlo todo */
.carta { transform: rotate(-3deg); }
.carta:hover { transform: rotate(-3deg) scale(1.1); } /* si olvidas el rotate, se endereza */
/* Con propiedades individuales: cada una va por su lado */
.carta { rotate: -3deg; }
.carta:hover { scale: 1.1; }
Además, se pueden animar por separado, cada una con su duración. Las tres se aplican siempre en el mismo orden: primero translate, luego rotate, luego scale, y por último lo que haya en transform.
El punto de origen: transform-origin
Toda transformación ocurre respecto a un punto, por defecto el centro del elemento. Si giras una caja, gira sobre su centro. Con transform-origin cambias ese punto:
.puerta {
transform-origin: left center; /* gira como una puerta, sobre su lado izquierdo */
transform: rotateY(-60deg);
}
.aguja {
transform-origin: bottom center; /* la aguja de un reloj gira desde abajo */
rotate: 90deg;
}
.subrayado {
transform-origin: left; /* crece de izquierda a derecha */
transform: scaleX(0);
}
.enlace:hover .subrayado { transform: scaleX(1); }
Acepta palabras (top, right, bottom, left, center), porcentajes o medidas: transform-origin: 20% 80%.
Combinar transformaciones: el orden importa
Puedes poner varias funciones en un mismo transform, separadas por espacios:
.a { transform: translateX(100px) rotate(45deg); }
.b { transform: rotate(45deg) translateX(100px); }
Parecen iguales, pero no lo son. Cada función transforma también los ejes de las que vienen después:
.a: primero se mueve 100px a la derecha y después gira sobre sí misma. Acaba a la derecha, girada..b: primero gira 45 grados, y con ella giran sus ejes. Después “100px a la derecha” significa 100px en la dirección girada: acaba en diagonal, abajo a la derecha.
Una regla práctica: si quieres mover un elemento y además girarlo sobre sí mismo, pon el translate primero.
Nota:
transformno funciona en elementos en línea como<span>o<a>. Si no ves ningún efecto, añadedisplay: inline-block.
Transformaciones en 3D
Además de los ejes X (horizontal) e Y (vertical), existe el eje Z, que sale de la pantalla hacia ti.
.a { transform: rotateX(45deg); } /* gira como una persiana */
.b { transform: rotateY(45deg); } /* gira como una puerta */
.c { transform: rotateZ(45deg); } /* igual que rotate() */
.d { transform: translateZ(50px); } /* se acerca a ti */
perspective: dar profundidad
Sin perspectiva, un giro en 3D se ve plano: la caja simplemente parece más estrecha. La perspectiva es la distancia entre tus ojos y la pantalla. Cuanto menor, más exagerado el efecto:
.escena { perspective: 800px; } /* en el PADRE: todos los hijos comparten punto de vista */
.carta { transform: rotateY(30deg); }
También existe la función perspective() dentro de transform, que afecta solo a ese elemento: transform: perspective(800px) rotateY(30deg);. Para varios elementos en la misma escena, usa la propiedad en el padre. Valores entre 600px y 1200px dan un resultado natural.
La tarjeta que gira
Es el ejemplo 3D más habitual: una tarjeta con dos caras que se da la vuelta al pasar el ratón. Necesitas tres piezas:
<div class="escena">
<div class="tarjeta">
<div class="cara frente">Clase de escalada</div>
<div class="cara dorso">Martes y jueves, 19:00</div>
</div>
</div>
.escena {
width: 240px;
height: 160px;
perspective: 800px; /* 1. la profundidad */
}
.tarjeta {
position: relative;
height: 100%;
transform-style: preserve-3d; /* 2. los hijos viven en el mismo espacio 3D */
transition: transform 0.6s;
}
.escena:hover .tarjeta {
transform: rotateY(180deg);
}
.cara {
position: absolute;
inset: 0; /* las dos caras, una encima de otra */
backface-visibility: hidden; /* 3. no se ve la cara de atrás */
}
.dorso {
transform: rotateY(180deg); /* empieza ya dada la vuelta */
}
perspectiveen la escena da profundidad.transform-style: preserve-3dhace que las caras giren con la tarjeta en 3D, en lugar de aplanarse.backface-visibility: hiddenoculta cada cara cuando está de espaldas. El dorso empieza girado 180 grados, así que al principio no se ve; cuando la tarjeta gira, se intercambian.
El :hover se pone en la escena y no en la tarjeta: si la tarjeta gira bajo el ratón, a mitad de giro puede “perder” el puntero y volver atrás de golpe.
Efectos secundarios que conviene saber
Aplicar cualquier transform (aunque sea translate(0)) tiene dos consecuencias poco intuitivas:
- Crea un contexto de apilamiento nuevo, lo que puede cambiar cómo funciona el
z-indexde sus hijos. Lo verás en z-index y capas. - Los hijos con
position: fixeddejan de fijarse a la ventana y se fijan a ese elemento. Si un modal “fijo” se desplaza con la página, busca untransformen algún antepasado.
Errores frecuentes
- Esperar que
transformmueva a los vecinos. No lo hace: el hueco original se mantiene. Para cambiar el diseño de verdad, usa márgenes, Flexbox o Grid. - Sobrescribir un
transformen el:hover.transform: scale(1.1)en el:hoverborra elrotate()que tenía. Repite todas las funciones o usa las propiedades individuales. - Usar comas.
transform: rotate(10deg), scale(2)no es válido. Las funciones se separan con espacios. Y en la propiedadtranslatetampoco hay comas:translate: 10px 20px. - Aplicarlo a un
<span>. Los elementos en línea no se transforman. Usainline-block. - Poner
perspectiveen el elemento que gira. La propiedadperspectiveva en el padre; en el propio elemento, usa la funciónperspective(). - Olvidar
transform-style: preserve-3d. Sin ella, la tarjeta 3D se aplana y las dos caras se ven mal.
Resumen
| Función o propiedad | Qué hace | Ejemplo |
|---|---|---|
translate() | Mueve (los % son del propio elemento) | translate(-50%, -50%) |
scale() | Agranda o encoge | scale(1.1), scaleX(-1) |
rotate() | Gira | rotate(45deg), rotate(0.5turn) |
skew() | Inclina | skewX(-15deg) |
translate, rotate, scale | Propiedades sueltas, independientes | scale: 1.05; |
transform-origin | Punto sobre el que se transforma | left center |
| Varias funciones | Se aplican en orden, cambiando los ejes | translateX(50px) rotate(30deg) |
perspective | Profundidad 3D (en el padre) | perspective: 800px |
rotateX(), rotateY(), translateZ() | Transformaciones en 3D | rotateY(180deg) |
transform-style: preserve-3d | Los hijos comparten el espacio 3D | Tarjeta que gira |
backface-visibility: hidden | Oculta la cara de atrás | Tarjeta que gira |
Las transformaciones lucen de verdad cuando se mueven. Con transition ya puedes animarlas al pasar el ratón (lo tienes en transiciones); para movimientos que se repiten o empiezan solos, sigue con animaciones.
Pruébalo tú
Cambia el código y pulsa Ejecutar (o Ctrl + Enter).
Pon a prueba lo que has aprendido
¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.