CSS 3
Partes de CSS (selector, propiedades, valores)
En CSS se pueden hablar de 3 partes principales:
- Selector: Es la parte que selecciona el elemento al que se le va a aplicar el estilo.
- Propiedad: Es la parte que define el estilo que se le va a aplicar al elemento.
- Valor: Es la parte que define el valor de la propiedad que se le va a aplicar al elemento.
Para añadir comentarios en CSS se utiliza /* comentario */
.
A la línea que tiene propiedad: valor;
se le llama declaración.
selector {
propiedad: valor; /* comentario */
}
Selectores
Hay varios tipos de selectores:
- Selector universal: Selecciona todos los elementos de la página. Se utiliza el asterisco
*
. - Selector de tipo: Selecciona todos los elementos de un tipo. Se utiliza el nombre del tipo de elemento. Por ejemplo,
p
selecciona todos los párrafos. - Selector de clase: Selecciona todos los elementos que tengan una clase. Se utiliza el nombre de la clase. Por ejemplo,
.clase
selecciona todos los elementos que tengan la claseclase
. Esto es útil, porque si queremos que todos los botones sean iguales, en el html ponemos<button class="boton">
y en el css ponemos.boton
. Así todos los botones tendrán los mismos estilos, y queremos que un botón sea diferente, le ponemos otra clase. - Selector de pseudo-clase: Selecciona todos los elementos que tengan una pseudo-clase. Se utiliza el nombre de la pseudo-clase. Por ejemplo,
:hover
selecciona todos los elementos que estén siendo seleccionados por el ratón. Esto es útil, porque si queremos que un botón cambie de color cuando el ratón esté encima, en el css ponemos.boton:hover
. Así el botón tendrá los estilos que queramos cuando el ratón esté encima. Algunas pseudo-clases son::hover
: Selecciona todos los elementos que estén siendo seleccionados por el ratón.:active
: Selecciona todos los elementos que estén siendo seleccionados por el ratón y estén siendo pulsados.:focus
: Selecciona todos los elementos que estén siendo seleccionados por el ratón y estén siendo pulsados, y además tengan el foco.:first-child
: Selecciona todos los elementos que sean el primer hijo de su padre. Esto es útil por ejemplo con los<li>
de las listas, porque si queremos que el primer elemento de la lista tenga un estilo diferente, en el css ponemosli:first-child
. Así el primer elemento de la lista tendrá los estilos que queramos.:last-child
: Selecciona todos los elementos que sean el último hijo de su padre. Esto es útil por ejemplo con los<li>
de las listas, porque si queremos que el último elemento de la lista tenga un estilo diferente, en el css ponemosli:last-child
. Así el último elemento de la lista tendrá los estilos que queramos.:nth-child(n)
: Selecciona todos los elementos que sean el n-ésimo hijo de su padre. Por ejemplo,:nth-child(2)
selecciona todos los elementos que sean el segundo hijo de su padre.:nth-last-child(n)
: Selecciona todos los elementos que sean el n-ésimo hijo de su padre, empezando desde el final. Por ejemplo,:nth-last-child(2)
selecciona todos los elementos que sean el segundo hijo de su padre, empezando desde el final.:nth-of-type(n)
: Selecciona todos los elementos que sean el n-ésimo hijo de su padre, del mismo tipo. Por ejemplo,:nth-of-type(2)
selecciona todos los elementos que sean el segundo hijo de su padre, del mismo tipo.:nth-last-of-type(n)
: Selecciona todos los elementos que sean el n-ésimo hijo de su padre, del mismo tipo, empezando desde el final. Por ejemplo,:nth-last-of-type(2)
selecciona todos los elementos que sean el segundo hijo de su padre, del mismo tipo, empezando desde el final.:first-of-type
: Selecciona todos los elementos que sean el primer hijo de su padre, del mismo tipo.:last-of-type
: Selecciona todos los elementos que sean el último hijo de su padre, del mismo tipo.:only-child
: Selecciona todos los elementos que sean el único hijo de su padre.:only-of-type
: Selecciona todos los elementos que sean el único hijo de su padre, del mismo tipo.:empty
: Se selecciona todos los elementos que no tengan hijos.
- Selector de id: Selecciona un elemento que tenga un id. Se utiliza el nombre del id. Por ejemplo,
#id
selecciona el elemento que tenga el idid
. Esto es útil, porque si queremos que un elemento sea único, en el html ponemos<p id="unico">
y en el css ponemos#unico
. Así ese elemento tendrá los estilos que queramos, y si queremos que otro elemento sea igual, le ponemos otra clase. - Selectores combinados: Seleccionan elementos que cumplan varias condiciones. Se utilizan los selectores que queramos, separados por un espacio. Por ejemplo,
p .clase
selecciona todos los elementos que tengan la claseclase
y sean hijos de un párrafo. Esto es útil, porque si queremos que todos los botones que estén dentro de un párrafo sean iguales, en el html ponemos<p class="parrafo_que_quiero_cambiar"><button class="boton">
y en el css ponemos.parrafo_que_quiero_cambiar .boton
. Así todos los botones que estén dentro de un párrafo con la claseparrafo_que_quiero_cambiar
tendrán los mismos estilos, y queremos que un botón sea diferente, le ponemos otra clase. - Selector combinado de primer nivel: Seleccionan elementos que cumplan varias condiciones, pero solo si están en el primer nivel. Se utilizan los selectores que queramos, separados por un
>
. Por ejemplo,p > .clase
selecciona todos los elementos que tengan la claseclase
y sean hijos directos de un párrafo. Esto es útil, porque si queremos que todos los botones que estén dentro de un párrafo sean iguales, en el html ponemos<p class="parrafo_que_quiero_cambiar"><button class="boton">
y en el css ponemos.parrafo_que_quiero_cambiar > .boton
. Así todos los botones que estén dentro de un párrafo con la claseparrafo_que_quiero_cambiar
tendrán los mismos estilos, y queremos que un botón sea diferente, le ponemos otra clase. - Selector combinado de hermanos: Seleccionan elementos que cumplan varias condiciones, pero solo si están en el mismo nivel. Se utilizan los selectores que queramos, separados por un
~
. Por ejemplo,p ~ .clase
selecciona todos los elementos que tengan la claseclase
y estén en el mismo nivel que un párrafo. Esto es útil, porque si queremos que todos los botones que estén en el mismo nivel que un párrafo sean iguales, en el html ponemos<p class="parrafo_que_quiero_cambiar"></p><button class="boton">
y en el css ponemos.parrafo_que_quiero_cambiar ~ .boton
. Así todos los botones que estén en el mismo nivel que un párrafo con la claseparrafo_que_quiero_cambiar
tendrán los mismos estilos, y queremos que un botón sea diferente, le ponemos otra clase. - Selector combinado de hermanos adyacentes: Seleccionan elementos que cumplan varias condiciones, pero solo si están en el mismo nivel y son adyacentes. Se utilizan los selectores que queramos, separados por un
+
. Por ejemplo,p + .clase
selecciona todos los elementos que tengan la claseclase
y estén en el mismo nivel y sean adyacentes a un párrafo. Esto es útil, porque si queremos que todos los botones que estén en el mismo nivel y sean adyacentes a un párrafo sean iguales, en el html ponemos<p class="parrafo_que_quiero_cambiar"></p><button class="boton">
y en el css ponemos.parrafo_que_quiero_cambiar + .boton
. Así todos los botones que estén en el mismo nivel y sean adyacentes a un párrafo con la claseparrafo_que_quiero_cambiar
tendrán los mismos estilos, y queremos que un botón sea diferente, le ponemos otra clase.
Lo normal es utilizar el selector de clase, porque así podemos reutilizar los estilos.
Estilos
Color
El color se puede poner de varias formas:
Nombre: Se puede poner el nombre del color. Por ejemplo,
red
es rojo.Hexadecimal: Se puede poner el color en hexadecimal. Por ejemplo,
#ff0000
es rojo.Si se quiere añadir transparencia, se puede poner
#ff000080
, que es rojo con 50% de transparencia.Si solo se ponen 3 números, se repiten. Por ejemplo,
#f10
es lo mismo que#ff1100
. Si se quiere añadir transparencia, se puede poner#f108
, que es lo mismo que#ff110088
.RGB: Se puede poner el color en RGB. Por ejemplo,
rgb(255, 0, 0)
es rojo.Si se quiere añadir transparencia, se puede poner
rgb(255 0 0 / 0.5)
, que es rojo con 50% de transparencia. También se poner la transparencia en porcentaje,rgb(255 0 0 / 50%)
. Puedes encontrar la transparencia de una forma legacy conrgba(255, 0, 0, 0.5)
, que es rojo con 50% de transparencia, pero lo mejor es utilizar la forma moderna.HSL: Se puede poner el color en HSL. Por ejemplo,
hsl(0, 100%, 50%)
es rojo.OKLCH: Se puede poner el color en OKLCH. Por ejemplo,
oklch(0 100% 50%)
es rojo.
En HSL
y OKLCH
hay más escala de colores que en RGB
, por lo que si necesitas más colores, es mejor utilizar HSL
o OKLCH
.
También se puede añadir la transparencia añadiendo la declaración color:transparent
.
Current Color
Hay un valor de color que es currentColor
, que es el color actual. Por ejemplo, si tenemos un texto y configuramos su color a rojo, y luego a este texto le añadimos un borde, si ponemos border: 1px solid currentColor;
, el borde será rojo.
p {
color: red;
border: 1px solid currentColor;
}
Herencia
Cuando se pone un estilo a un elemento, este estilo se hereda a los elementos hijos. Por ejemplo, si tenemos un div
con un texto, y le ponemos el color rojo al div
, el texto también será rojo.
<div>
<p>Texto</p>
</div>
div {
color: red;
}
Al hacer esto, el texto será rojo.
Podemos indicar en el hijo qué estilos se heredan, por ejemplo supongamos que tenemos un padre y un hijo
<div class="padre">
<p class="hijo">Texto</p>
</div>
.padre {
color: red;
}
.hijo {
color: inherit;
}
Al hacer esto, el texto será rojo, porque el hijo hereda el color del padre.
Las posibles opciones son:
inherit
: Hereda el estilo del padre.initial
: Pone el estilo por defecto.unset
: Resetea el estilorevert
: Revierte el estilo
No todos los estilos se herean, por ejemplo, el background
no se hereda. Para no poner todos los estilos que se heredan, una forma de saberlo es llendo a MDN
y mirando si el estilo tiene la propiedad Inherited
a yes
(Dentro de Formal definition
).
Fuentes
A la hora de cargar las fuentes, se pueden cargar de varias formas:
- Local: Se puede cargar una fuente local. Por ejemplo,
font-family: Arial;
carga la fuente Arial. - URL: Se puede cargar una fuente de una URL. Por ejemplo,
font-family: url(https://fonts.googleapis.com/css2?family=Roboto);
carga la fuente Roboto de Google Fonts. - Genérica: Se puede cargar una fuente genérica. Por ejemplo,
font-family: sans-serif;
carga una fuente sin serifa. Esta fuente depende del sistema operativo, por lo que en Windows será Arial, en Mac será Helvetica y en Linux será DejaVu Sans.
Se pueden cargar varias fuentes, y si una no está disponible, se carga la siguiente. Por ejemplo, font-family: Arial, sans-serif;
carga Arial, y si no está disponible, carga una fuente sin serifa.
También se puede cargar una fuente con varios estilos. Por ejemplo, font-family: Arial, sans-serif; font-weight: 700;
carga Arial en negrita, y si no está disponible, carga una fuente sin serifa en negrita.
Como sans-serif
es una fuente genérica, lo ideal es siempre ponerla la última, para que si no está disponible la fuente que queremos, se cargue la genérica.
p {
font-family: url(https://fonts.googleapis.com/css2?family=Roboto), url(https://fonts.googleapis.com/css2?family=Roboto+Slab), Ubuntu, sans-serif;
}
Border y Outline
Podemos ponerle un borde a un elemento con border: 1px solid red;
. Esto pone un borde de 1px de grosor, sólido y rojo.
Si queremos poner un contorno, podemos utilizar outline: 1px solid red;
. Esto pone un contorno de 1px de grosor, sólido y rojo.
La diferencia entre border
y outline
es que border
ocupa espacio, y outline
no. Por ejemplo, si tenemos un div
con un texto, y le ponemos un borde, el texto se moverá para que el borde se vea. Si ponemos un contorno, el texto no se moverá, porque el contorno no ocupa espacio. Esto se puede apreciar si cambiamos el estilo en la pseudo-clase :hover
. Si ponemos un borde, cuando pasemos el ratón por encima, el texto se moverá, pero si ponemos un contorno, el texto no se moverá.
Cascada
La cascada es el orden en el que se aplican los estilos. El orden es:
- Estilos del usuario: Son los estilos que el usuario ha configurado. Por ejemplo, si el usuario tiene configurado que el texto sea de color rojo, el texto será rojo.
- Estilos del autor: Son los estilos que el autor ha configurado. Por ejemplo, si el autor ha configurado que el texto sea de color azul, el texto será azul.
- Estilos del navegador: Son los estilos del navegador. Por ejemplo, si el navegador tiene configurado que el texto sea de color verde, el texto será verde.
Prevalecen los estilos del usuario sobre los del autor, y los del autor sobre los del navegador.
Pero dentro de los estilos del autor, prevalecen los estilos que estén más abajo en el código. Por ejemplo, si tenemos un div
con un texto, y le ponemos el color rojo, y luego le ponemos el color azul, el texto será azul.
<div>
<p>Texto</p>
</div>
div {
color: red;
}
div {
color: blue;
}
En este ejemplo, el texto será azul. Se sobreescribe el color rojo con el color azul.
Fallback
Uno de los beneficios de la cascada es que podemos poner un estilo muy nuevo, pero por si el navegador que esté usando el usuario no lo soporta, podemos poner un estilo más antiguo antes por si acaso. Por ejemplo, estilar el color con oklch
es algo nuevo, que puede que el navegador que el usuario esté usando no lo soporte, por lo que podemos poner un estilo más antiguo antes por si acaso.
p {
color: rgb(255, 0, 0);
color: oklch(0 100% 50%);
}
De esta manera el navegador primero intentará estilar con oklch
, y si no puede, estilará con rgb
.
Especificidad
Puede ser que un elemento html tenga varias formas de referirnos a él. Por ejemplo
<p class="clase" id="id">Texto</p>
p {
color: red;
}
.clase {
color: blue;
}
#id {
color: green;
}
En este ejemplo, el texto será verde. Esto es porque el selector de id tiene más especificidad que el selector de clase, y el selector de clase tiene más especificidad que el selector de tipo. Por lo que el selector de id sobreescribe al selector de clase, y el selector de clase sobreescribe al selector de tipo.
Si en el css tuviésemos
p {
color: red;
}
p.clase {
color: blue;
}
El texto sería azul. Esto es porque el selector de clase tiene más especificidad que el selector de tipo, por lo que el selector de clase sobreescribe al selector de tipo.
Los estilos en línea tienen más especificidad que los estilos del autor. Por ejemplo
<p style="color: red;">Texto</p>
p {
color: blue;
}
En este ejemplo, el texto será rojo. Esto es porque el estilo en línea tiene más especificidad que el estilo del autor.
Si se pone !important
al final de la declaración, esta declaración tendrá más especificidad que cualquier otra. Por ejemplo
<p class="clase" id="id">Texto</p>
p {
color: red;
}
.clase {
color: blue;
}
#id {
color: green;
}
p.clase {
color: yellow !important;
}
En este ejemplo, el texto será amarillo. Esto es porque la declaración con !important
tiene más especificidad que cualquier otra.
Unidades
Unidades de longitud
Unidades absolutas
Si queremos poner un tamaño fijo, podemos utilizar unidades absolutas. Por ejemplo, px
es un píxel, cm
es un centímetro, mm
es un milímetro, in
es una pulgada, pt
es un punto, pc
es una pica.
Unidades relativas
Sin embargo, si queremos que el tamaño sea relativo, podemos utilizar unidades relativas. Por ejemplo, em
es el tamaño de la fuente, rem
es el tamaño de la fuente del elemento raíz, vw
es el ancho de la ventana, vh
es el alto de la ventana, vmin
es el ancho o el alto de la ventana, dependiendo de cuál sea menor, vmax
es el ancho o el alto de la ventana, dependiendo de cuál sea mayor, ch
es el ancho de un carácter, ex
es la altura de una x, fr
es una fracción del espacio disponible.
Modelo de la caja
En html todo son cajas, pero hay dos tipos de maneras de ver las cajas, inline
y block
. Por ejemplo, los <span>
son inline
, y los <div>
son block
.
Cajas inline
Cuando el elemento es inline
, el ancho y el alto no se pueden configurar, y el elemento se comporta como si fuese texto. Por ejemplo, si tenemos un span
con un texto, y le ponemos un ancho y un alto, el ancho y el alto no se aplicarán, y el elemento se comportará como si fuese texto.
<span>Texto</span>
span {
width: 100px;
height: 100px;
}
En este ejemplo, el ancho y el alto no se aplicarán, y el elemento se comportará como si fuese texto.
Además, cuando el elemento es inline
, si se ponen varios elementos juntos en el html, estos elementos se mostrarán juntos. Por ejemplo, si tenemos varios span
con un texto, y los ponemos juntos en el html, estos elementos se mostrarán juntos.
<span>Texto</span>
<span>Texto</span>
<span>Texto</span>
En este ejemplo, los elementos se mostrarán juntos ==> TextoTextoTexto.
Pero si queremos que los elementos se muestren en diferentes líneas, podemos utilizar display: block;
. Por ejemplo, si tenemos varios span
con un texto, y les ponemos display: block;
, estos elementos se mostrarán en diferentes líneas.
<span>Texto</span>
<span>Texto</span>
<span>Texto</span>
span {
display: block;
}
En este ejemplo, los elementos se mostrarán en diferentes líneas
⬇
Texto
Texto
Texto
Cajas block
Cuanod el elemento es block
, el ancho y el alto se pueden configurar, y el elemento se comporta como si fuese un bloque. Por ejemplo, si tenemos un div
con un texto, y le ponemos un ancho y un alto, el ancho y el alto se aplicarán, y el elemento se comportará como si fuese un bloque.
<div>Texto</div>
div {
width: 100px;
height: 100px;
}
En este ejemplo, el ancho y el alto se aplicarán, y el elemento se comportará como si fuese un bloque.
Además, cuando el elemento es block
, si se ponen varios elementos juntos en el html, estos elementos se mostrarán uno debajo del otro. Por ejemplo, si tenemos varios div
con un texto, y los ponemos juntos en el html, estos elementos se mostrarán uno debajo del otro.
<div>Texto</div>
<div>Texto</div>
<div>Texto</div>
En este ejemplo, los elementos se mostrarán uno debajo del otro
⬇
Texto
Texto
Texto
Pero si queremos que los elementos se muestren en la misma línea, podemos utilizar display: inline;
. Por ejemplo, si tenemos varios div
con un texto, y les ponemos display: inline;
, estos elementos se mostrarán en la misma línea.
<div>Texto</div>
<div>Texto</div>
<div>Texto</div>
div {
display: inline;
}
En este ejemplo, los elementos se mostrarán en la misma línea ==> TextoTextoTexto.
Margin, Border, Padding y Content
Ahora que sabemos en en html todo son cajas, podemos ver que cada caja tiene 4 partes:
- Margin: Es el espacio que hay entre la caja y las demás cajas.
- Border: Es el borde de la caja.
- Padding: Es el espacio que hay entre el borde y el contenido.
- Content: Es el contenido de la caja.
Todas estas propiedades se pueden configurar. Por ejemplo, si tenemos un div
con un texto, y le ponemos un ancho y un alto, el ancho y el alto se aplicarán, y el elemento se comportará como si fuese un bloque.
<div>Texto</div>
div {
width: 100px;
height: 100px;
margin: 10px;
border: 10px solid red;
padding: 10px;
}
Como son propiedades de tamaño, se pueden poner unidades de longitud. Por ejemplo:
- Si queremos que el margen sea de 10 píxeles, ponemos
margin: 10px;
. - Si queremos que solo sea el margen izquierdo, ponemos
margin-left: 10px;
. - Si queremos que solo sea el margen derecho, ponemos
margin-right: 10px;
. - Si queremos que solo sea el margen superior, ponemos
margin-top: 10px;
. - Si queremos que solo sea el margen inferior, ponemos
margin-bottom: 10px;
. - Si queremos que cada margen sea de un tamaño, ponemos
margin: 10px 20px 30px 40px;
. El orden es arriba, derecha, abajo, izquierda, como si fuesen las agujas del reloj. - Si queremos cambiar los tamaños en el eje horizontal y vertical, ponemos
margin: 10px 20px;
. El orden es arriba y abajo (10px), izquierda y derecha (20px).
Tamaño de la caja al cambiar el padding
Si tenemos un div
con un texto, y le ponemos un ancho y un alto, el ancho y el alto se aplicarán, y el elemento se comportará como si fuese un bloque.
<div>Texto</div>
div {
width: 100px;
height: 100px;
}
De esta manera el div
tendrá un ancho y un alto de 100px.
Pero si ahora le aplicamos un padding de 10px, el ancho y el alto se mantendrán, pero el tamaño de la caja será de 120px, porque el padding se añade al ancho y al alto.
<div>Texto</div>
div {
width: 100px;
height: 100px;
padding: 10px;
}
De esta manera el div
tendrá un ancho y un alto de 100px, pero el tamaño de la caja será de 120px.
Tamaño de la caja al cambiar el border
Si tenemos un div
con un texto, y le ponemos un ancho y un alto, el ancho y el alto se aplicarán, y el elemento se comportará como si fuese un bloque.
<div>Texto</div>
div {
width: 100px;
height: 100px;
}
De esta manera el div
tendrá un ancho y un alto de 100px.
Pero si ahora le aplicamos un border de 10px, el ancho y el alto se mantendrán, pero el tamaño de la caja será de 120px, porque el border se añade al ancho y al alto.
<div>Texto</div>
div {
width: 100px;
height: 100px;
border: 10px solid red;
}
De esta manera el div
tendrá un ancho y un alto de 100px, pero el tamaño de la caja será de 120px.
Tamaño de la caja al cambiar el margin
En el caso de los márgenes, el tamaño de la caja no cambia, pero el espacio entre las cajas sí. Por ejemplo, si tenemos dos div
con un texto, y le ponemos un ancho y un alto, el ancho y el alto se aplicarán, y el elemento se comportará como si fuese un bloque.
<div>Texto</div>
<div>Texto</div>
div {
width: 100px;
height: 100px;
}
De esta manera los div
tendrán un ancho y un alto de 100px.
Pero si ahora le aplicamos un margin de 10px, el ancho y el alto se mantendrán, pero el espacio entre los div
será de 20px, porque el margin se añade al espacio entre los div
.
<div>Texto</div>
<div>Texto</div>
div {
width: 100px;
height: 100px;
margin: 10px;
}
De esta manera los div
tendrán un ancho y un alto de 100px, pero el espacio entre los div
será de 20px.
Tamaño de la caja
Por tanto lo que ocupa la caja es:
- Ancho:
width + padding + border
. - Alto:
height + padding + border
.
El margen no cuenta, porque el margen es el espacio entre las cajas.
Box-sizing
Por defecto, la propiedad box-sizing
está configurada a content-box
. Esto significa que el ancho y el alto no incluyen el padding ni el border. Por ejemplo, si tenemos un div
con un texto, y le ponemos un ancho y un alto, el ancho y el alto se aplicarán, y el elemento se comportará como si fuese un bloque.
<div>Texto</div>
div {
width: 100px;
height: 100px;
}
De esta manera el div
tendrá un ancho y un alto de 100px.
Pero si ahora le aplicamos un padding de 10px, el ancho y el alto se mantendrán, pero el tamaño de la caja será de 120px, porque el padding se añade al ancho y al alto.
<div>Texto</div>
div {
width: 100px;
height: 100px;
padding: 10px;
}
De esta manera el div
tendrá un ancho y un alto de 100px, pero el tamaño de la caja será de 120px.
Si cambiaramos la propiedad box-sizing
a border-box
, el ancho y el alto incluirían el padding y el border. Por ejemplo, si tenemos un div
con un texto, y le ponemos un ancho y un alto, el ancho y el alto se aplicarán, y el elemento se comportará como si fuese un bloque.
<div>Texto</div>
div {
width: 100px;
height: 100px;
box-sizing: border-box;
}
De esta manera el div
tendrá un ancho y un alto de 100px.
Pero si ahora le aplicamos un padding de 10px, el ancho y el alto se mantendrán, y el tamaño de la caja también será de 100px, porque el padding no se añade al ancho y al alto.
<div>Texto</div>
div {
width: 100px;
height: 100px;
box-sizing: border-box;
padding: 10px;
}
De esta manera el div
tendrá un ancho y un alto de 100px, y el tamaño de la caja también será de 100px.
Hay que tener en cuenta que cuando se cambia la propiedad box-sizing
a border-box
, el ancho y el alto incluyen el padding y el border, por lo que no podemos poner un ancho y un alto menor que el padding y el border. Por ejemplo, si tenemos un div
con un texto, y le ponemos un ancho y un alto, el ancho y el alto se aplicarán, y el elemento se comportará como si fuese un bloque.
<div>Texto</div>
div {
width: 100px;
height: 100px;
box-sizing: border-box;
}
De esta manera el div
tendrá un ancho y un alto de 100px.
Pero si ahora le aplicamos un padding de 110px, el ancho y el alto se mantendrán, pero el tamaño de la caja será de 220px, porque el padding se añade al ancho y al alto.
<div>Texto</div>
div {
width: 100px;
height: 100px;
box-sizing: border-box;
padding: 110px;
}
De esta manera el div
tendrá un ancho y un alto de 100px, pero el tamaño de la caja será de 220px.
Overflow
Uno de los memes más famosos de CSS es el siguiente
Y esto se produce cuando el tamaño del contenido es mayor que el tamaño de la caja. Por ejemplo, si tenemos un div
con un texto, y le ponemos un ancho y un alto, el ancho y el alto se aplicarán, y el elemento se comportará como si fuese un bloque.
<div>Texto</div>
div {
width: 100px;
height: 100px;
}
De esta manera el div
tendrá un ancho y un alto de 100px.
Pero si ahora le aplicamos un texto muy largo, el texto se saldrá de la caja, porque el tamaño del contenido es mayor que el tamaño de la caja.
<div>Texto muy largo</div>
div {
width: 100px;
height: 100px;
}
De esta manera el div
tendrá un ancho y un alto de 100px, pero el texto se saldrá de la caja.
Esto ocurreo porque en CSS la propiedad overflow
está configurada a visible
. Esto significa que el contenido se puede salir de la caja. Pero tenemos otras opciones:
hidden
: El contenido no se puede salir de la caja, y se corta.scroll
: El contenido no se puede salir de la caja, y se añade una barra de desplazamiento.auto
: El contenido no se puede salir de la caja, y se añade una barra de desplazamiento si es necesario. En este caso depende del dispositivo, porque si el dispositivo tiene una barra de desplazamiento, se añadirá una barra de desplazamiento, y si el dispositivo no tiene una barra de desplazamiento, no se añadirá una barra de desplazamiento.
Entre scroll
y auto
el recomendado es auto
, porque si el dispositivo tiene una barra de desplazamiento, se añadirá una barra de desplazamiento, y si el dispositivo no tiene una barra de desplazamiento, no se añadirá una barra de desplazamiento.
Overflow hidden
En el caso de elegir hidden
, el contenido no se puede salir de la caja, y se corta. En este caso tenemos la propiedad text-overlow
, que nos permite configurar qué se hace con el texto que se sale de la caja. Las opciones son:
clip
: El texto se corta.ellipsis
: El texto se corta, y se añade...
al final del texto.
En el futuro se podrá poner un símbolo personalizado, pero de momento no se puede.
Estilado de la barra
En caso de tener desbordamientos se puede estilar la barra, pero es recomendable no estilar la barra de la página y solo hacerlo en barras de cajas internas. Por ejemplo, si en la página hay un índice en el lateral, y queremos cambiar el tamaño y el color de la barra para que se vea mejor, podemos hacerlo.
En scrollbar.app tenemos un editor para poder estilar la barra y obtener el código necesario
Position
En html los elementos se van apilando, se posicionan por defecto de manera estática, esto es porque por defecto en CSS tienen el atributo position
con el valor static
. Esto significa que el elemento se posiciona de manera estática, y no se puede mover. Los posibles valores son
static
: El elemento se posiciona de manera estática, y no se puede mover.relative
: El elemento se posiciona de manera relativa, y se puede mover.absolute
: El elemento se posiciona de manera absoluta, y se puede mover.fixed
: El elemento se posiciona de manera fija, y se puede mover.sticky
: El elemento se posiciona de manera pegajosa, y se puede mover.
Position relative
Cuando queremos que la posición de un elemento sea relativa a otro usamos position: relative;
. Pero hay que poner position: relative;
en el padre, y position: absolute;
en el hijo. Por ejemplo, si tenemos un div
con un texto, y queremos que el texto esté en la esquina superior derecha del div
, podemos hacerlo.
<div>
<p>Texto</p>
</div>
div {
position: relative;
}
p {
position: absolute;
top: 0;
right: 50px;
}
De esta manera el texto estará en la esquina superior derecha del div
.
Position absolute
Cuando el elemento es absolute
, el elemento se posiciona de manera absoluta al primer elemento padre que no sea static
. En el ejemplo anteriore hemos visto que si tenemos un div
con un texto, y queremos que el texto esté en la esquina superior derecha del div
, podemos hacerlo.
<div>
<p>Texto</p>
</div>
div {
position: relative;
}
p {
position: absolute;
top: 0;
right: 50px;
}
En este ejemplo, el div
tiene position: relative;
, por lo que el p
se posiciona de manera absoluta al div
, en la esquina superior derecha.
En caso de que no haya ningún elemento padre que no sea static
, el elemento se posiciona de manera absoluta al body
, es decir, a la página.
<p>Texto</p>
p {
position: absolute;
top: 0;
right: 50px;
}
En este ejemplo, el p
no tiene ningún elemento padre que no sea static
, por lo que el p
se posiciona de manera absoluta al body
. Es decir en la parte superior derecha de la página.
Gracias a las propiedades relative
y absolute
podemos centrar un div
horizontalmente y verticalmente. Por ejemplo, si tenemos un div
con un texto, y queremos que el texto esté centrado horizontalmente y verticalmente, podemos hacerlo.
<div>
<p>Texto</p>
</div>
div {
position: relative;
}
p {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
}
En este ejemplo, el div
tiene position: relative;
, por lo que el p
se posiciona de manera absoluta al div
, en la esquina superior derecha. Además, el p
tiene top: 0;
, right: 0;
, bottom: 0;
y left: 0;
, por lo que el p
ocupa todo el div
. Por último, el p
tiene margin: auto;
, por lo que el p
se centra horizontalmente y verticalmente.
Esta no es la mejor manera de centrar el contenido en un div
, pero puede ser muy útil en algunos casos, como por ejemplo en un modal.
Position fixed
Cuando el elemento es fixed
, el elemento se posiciona de manera fija a la ventana. Es parecido a absolute
, pero en vez de posicionarse al primer elemento padre que no sea static
, se posiciona a la ventana. Además, si la ventana se mueve, el elemento se mueve con ella, es decir, que si hacemos scroll, el elemento siempre estará en la misma posición.
Por ejemplo, si tenemos un div
con un texto, y queremos que el texto esté en la esquina superior derecha de la ventana, podemos hacerlo.
<div>
<p>Texto</p>
</div>
p {
position: fixed;
top: 0;
right: 50px;
}
En este ejemplo, el p
se posiciona de manera fija a la ventana, en la esquina superior derecha y al hacer scroll, el p
siempre estará en la misma posición.
Position sticky
Cuando el elemento es sticky
, el elemento se posiciona de manera pegajosa al primer elemento padre que no sea static
.
Es parecido a relative
, pero cuando el elemento llega a la parte superior de la ventana, el elemento se posiciona de manera fija a la ventana. Además, si la ventana se mueve, el elemento se mueve con ella, es decir, que si hacemos scroll, el elemento siempre estará en la misma posición.
Por ejemplo, si tenemos un div
con un texto, y queremos que el texto esté en la esquina superior derecha del div
, podemos hacerlo.
<div>
<p>Texto</p>
</div>
div {
position: relative;
}
p {
position: sticky;
top: 0;
right: 50px;
}
En este ejemplo, el div
tiene position: relative;
, por lo que el p
se posiciona de manera relativa al div
, en la esquina superior derecha. Además, el p
tiene top: 0;
, por lo que el p
se posiciona de manera pegajosa al div
. Es decir, que cuando el p
llega a la parte superior de la ventana, el p
se posiciona de manera fija a la ventana.
Z-index
Como hemos visto al cambiar el position
de un elemento, el elemento se posiciona encima de los demás elementos. Por lo que necesitamos tener control de qué elemento está o se verá por encima de los demás. Para ello tenemos la propiedad z-index
. Por defecto, todos los elementos tienen z-index: auto;
, pero podemos cambiarlo. Por ejemplo, si tenemos un div
con un texto, y queremos que el texto esté encima del div
, podemos hacerlo.
<div>
<p>Texto</p>
</div>
div {
position: relative;
z-index: 0;
}
p {
position: absolute;
top: 0;
right: 50px;
z-index: 1;
}
En este ejemplo, el div
tiene position: relative;
y z-index: 0;
, por lo que el div
se posiciona de manera relativa al div
, y el div
tiene un z-index
de 0. Además, el p
tiene position: absolute;
, top: 0;
, right: 50px;
y z-index: 1;
, por lo que el p
se posiciona de manera absoluta al div
, en la esquina superior derecha, y el p
tiene un z-index
de 1. Por lo que el p
estará encima del div
.
Si no se indica el z-index
, los hijos tienen un z-index
mayor que los padres. Pero por ejemplo, en el caso de position: sticky;
, el z-index
del elemento hijo es mayor que el z-index
del de su padre, pero a la hora de hacer scroll, si en algún momento coincide el hijo con otro padre, el otro padre estará por encima.
Si queremos que ese hijo se vea por encima de los otros padres podemos controlarlo con el z-index
.
En el curso de CSS de Goolge se puede ver muy bien cómo funciona el z-index
.
Flexbox y Grid
Hay dos maneras de hacer layouts en CSS, con flexbox
y con grid
. Flexbox
es más antiguo, y grid
es más nuevo. Flexbox
es unidimensional, y grid
es bidimensional. Flexbox
es para layouts sencillos, y grid
es para layouts complejos.
Flexbox
Como hemos visto, tenemos contenedores que tienen display: block;
, y contenedores que tienen display: inline;
. Los primeros se muestran en diferentes líneas, y los segundos se muestran en la misma línea. Por lo que si tenemos varios div
s se verán uno debajo del otro, y si tenemos varios span
s se verán en la misma línea.
Pero si queremos que los div
s se vean en la misma línea y además de manera flexible, podemos crear un contenedor padre que los contenga y hacer que el contenedor padre tenga display: flex;
.
<section>
<div>Texto</div>
<div>Texto</div>
<div>Texto</div>
</div>
section {
display: flex;
}
De esta manera los div
s se verán en la misma línea y además de manera flexible, es decir, si no caben en la misma línea, se pondrán en la siguiente línea.
Flex-direction
Flexbox
es uni-dimensional, por lo que solo se puede configurar una dirección. Por defecto, la propiedad flex-direction
está configurada a row
. Esto significa que los elementos se muestran en la misma línea. Pero podemos cambiarlo a column
, para que los elementos se muestren en diferentes líneas.
<section>
<div>Texto</div>
<div>Texto</div>
<div>Texto</div>
</section>
section {
display: flex;
flex-direction: column;
}
De esta manera los div
s se verán en diferentes líneas.
Esto es muy útil para hacer layouts responsive, porque podemos cambiar la dirección de los elementos dependiendo del tamaño de la pantalla.
Podemos además inidicar el sentido de la dirección, con flex-direction: row-reverse;
o flex-direction: column-reverse;
. Por ejemplo, si tenemos varios div
s, y queremos que se muestren en la misma línea, pero en sentido contrario, podemos hacerlo.
<section>
<div>Texto</div>
<div>Texto</div>
<div>Texto</div>
</section>
section {
display: flex;
flex-direction: row-reverse;
}
De esta manera los div
s se verán en la misma línea, pero en sentido contrario.
Esto es muy útil cuando queremos ordenar los elementos de manera inversa, por ejemplo, si tenemos un ul
con una lista, y queremos que la lista se muestre en sentido contrario, de esta manera no hace falta programar nada y se puede hacer con CSS.
Direction
Otra manera de indicar el sentido de la dirección es con la propiedad direction
. Por defecto, la propiedad direction
está configurada a ltr
. Esto significa que el sentido de la dirección es de izquierda a derecha. Pero podemos cambiarlo a rtl
, para que el sentido de la dirección sea de derecha a izquierda.
<section>
<div>Texto</div>
<div>Texto</div>
<div>Texto</div>
</section>
section {
display: flex;
direction: rtl;
}
Flex-wrap
Cuando los elementos no caben en la misma línea, se ponen en la siguiente línea. Pero podemos cambiar este comportamiento con la propiedad flex-wrap
. Por defecto, la propiedad flex-wrap
está configurada a nowrap
. Esto significa que los elementos no se pueden poner en la siguiente línea. Pero podemos cambiarlo a wrap
, para que los elementos se puedan poner en la siguiente línea.
<section>
<div>Texto</div>
<div>Texto</div>
<div>Texto</div>
</section>
section {
display: flex;
flex-wrap: wrap;
}
De esta manera los div
s se podrán poner en la siguiente línea.
Flex-flow
Una manera de configurar la dirección y el wrap de los elementos es con la propiedad flex-flow
. Por defecto, la propiedad flex-flow
está configurada a row nowrap
. Esto significa que los elementos se muestran en la misma línea, y no se pueden poner en la siguiente línea. Pero podemos cambiarlo a row wrap
, para que los elementos se muestren en la misma línea, y se puedan poner en la siguiente línea.
<section>
<div>Texto</div>
<div>Texto</div>
<div>Texto</div>
</section>
section {
display: flex;
flex-flow: row wrap;
}
De esta manera los div
s se verán en la misma línea, y se podrán poner en la siguiente línea.
Flex-grow, Flex-shrink y Flex-basis
Podemos configurar el tamaño de los elementos con las propiedades flex-grow
, flex-shrink
y flex-basis
.
flex-grow
: Indica si el elemento puede crecer o no. Por defecto, la propiedadflex-grow
está configurada a0
, lo que significa que el elemento no puede crecer. Pero podemos cambiarlo a1
, para que el elemento pueda crecer.flex-shrink
: Indica si el elemento puede encoger o no. Por defecto, la propiedadflex-shrink
está configurada a1
, lo que significa que el elemento puede encoger. Pero podemos cambiarlo a0
, para que el elemento no pueda encoger.flex-basis
: Indica el tamaño del elemento. Por defecto, la propiedadflex-basis
está configurada aauto
, lo que significa que el elemento tiene un tamaño automático. Pero podemos cambiarlo a100px
, para que el elemento tenga un tamaño de 100px.
Por ejemplo, si tenemos varios div
s, y queremos que el primer div
tenga un tamaño de 100px, y los demás se repartan el espacio restante, podemos hacerlo.
<section>
<div>Texto</div>
<div>Texto</div>
<div>Texto</div>
</section>
section {
display: flex;
}
section div:first-child {
flex-grow: 0; /* Como por feecto está a 0, no hace falta ponerlo */
flex-shrink: 0; /* Como por feecto está a 1, no hace falta ponerlo */
flex-basis: 100px;
}
section div {
flex-grow: 1;
flex-shrink: 1; /* Como por feecto está a 1, no hace falta ponerlo */
flex-basis: auto; /* Como por feecto está a auto, no hace falta ponerlo */
}
De esta manera el primer div
tendrá un tamaño de 100px, y los demás se repartirán el espacio restante.
Se pueden modificar los tres valores de una vez con la propiedad flex
. Por ejemplo, si tenemos varios div
s, y queremos que el primer div
tenga un tamaño de 100px, y los demás se repartan el espacio restante, podemos hacerlo.
<section>
<div>Texto</div>
<div>Texto</div>
<div>Texto</div>
</section>
section {
display: flex;
}
section div:first-child {
flex: 0 0 100px;
}
section div {
flex: 1 1 auto;
}
De esta manera el primer div
tendrá un tamaño de 100px, y los demás se repartirán el espacio restante.
O también se puede modificar de una vez con flex: initial;
, que es lo mismo que flex: 0 1 auto;
. O con flex: auto;
, que es lo mismo que flex: 1 1 auto;
. O con flex: none;
, que es lo mismo que flex: 0 0 auto;
. O con flex: 1;
, que es lo mismo que flex: 1 1 0%;
.
Otra forma de modificar flex
es poniendo números, que indicarán el espacio relativo del contenedor. Por ejemplo, si tenemos varios div
s, y queremos que el primero tenga el doble de eespacio del segundo, y el segundo tenga el doble de espacio del tercero, podemos hacerlo.
<section>
<div>Texto</div>
<div>Texto</div>
<div>Texto</div>
</section>
section {
display: flex;
}
section div:first-child {
flex: 4;
}
section div:nth-child(2) {
flex: 4;
}
section div:nth-child(3) {
flex: 1;
}
De esta manera el primer div
tendrá el doble de espacio del segundo, y el segundo tendrá el doble de espacio del tercero.
Order
Podemos ordenar los elementos dentro de un contenedor con la propiedad order
. Por defecto, la propiedad order
está configurada a 0
. Pero podemos cambiarlo a 1
, para que el elemento se ponga después de los elementos que tengan order: 0;
. O podemos cambiarlo a -1
, para que el elemento se ponga antes de los elementos que tengan order: 0;
.
Es como z-index
, pero para el orden de los elementos. Cuanto mayor sea el order
, más tarde se pondrá el elemento. Por ejemplo, si tenemos varios div
s, y queremos que el primer div
se ponga después del segundo, podemos hacerlo.
<section>
<div>Texto 1</div>
<div>Texto 2</div>
<div>Texto 3</div>
</section>
section {
display: flex;
}
section div:first-child {
order: 1;
}
section div {
order: 0;
}
El resultado será
Texto 2
Texto 3
Texto 1
Justify-content
Como Flexbox
es uni-dimensional, podemos configurar el justificado de los elementos del contenedor en el eje del Flebox
del contenedor. Es decir, si el eje del Flexbox
del contenedor es horizontal, podemos configurar el justificado de los elementos del contenedor en el eje horizontal. Y si el eje del Flexbox
del contenedor es vertical, podemos configurar el justificado de los elementos del contenedor en el eje vertical.
Los posibles valores son:
flex-start
: Los elementos se justifican al principio del eje delFlexbox
del contenedor.flex-end
: Los elementos se justifican al final del eje delFlexbox
del contenedor.center
: Los elementos se justifican en el centro del eje delFlexbox
del contenedor.space-between
: Los elementos se justifican con el mismo espacio entre ellos. A los laterales del primer y último elemento no se deja espacio.space-around
: Los elementos se justifican con el mismo espacio alrededor de ellos.space-evenly
: Los elementos se justifican con el mismo espacio entre ellos y alrededor de ellos. Es decir, es similar aspace-between
, pero a los laterales del primer y último elemento se deja espacio. El espacio en los laterales es el mismo que el espacio entre los elementos
Gap
Supon que tenemos varios elementos dentro de un contenedor y hemos puesto justify-content: center;
. Esto hará que los elementos estén centrados en el contenedor, pero pegados entre ellos. Si queremos que haya un espacio entre los elementos, podemos poner gap: 10px;
. De esta manera habrá un espacio de 10px entre los elementos.
<section>
<div>Texto 1</div>
<div>Texto 2</div>
<div>Texto 3</div>
</section>
section {
display: flex;
justify-content: center;
gap: 10px;
}
Align-items
Hasta ahora hemos visto como distribuir los elementos en el eje principal del Flexbox
. Pero, ¿qué pasa con el eje secundario? Para ello tenemos la propiedad align-items
. Esta propiedad nos permite alinear los elementos en el eje secundario del Flexbox
.
<section>
<div>Texto 1</div>
<div>Texto 2</div>
<div>Texto 3</div>
</section>
section {
display: flex;
align-items: center;
}
Align-content
Con align-content
podemos alinear el contenido del contenedor en el eje secundario. Esta propiedad es similar a align-items
, pero en vez de alinear los elementos, alinea el contenido del contenedor.
<section>
<div>Texto 1</div>
<div>Texto 2</div>
<div>Texto 3</div>
</section>
section {
display: flex;
align-content: center;
flex-wrap: wrap;
height: 200px;
}
Align-content vs Align-items
Como puede haber confusión entre align-content
y align-items
, vamos a ver un ejemplo para ver la diferencia entre ambas propiedades.
<section>
<div>Texto 1</div>
<div>Texto 2</div>
<div>Texto 3</div>
<div>Texto 4</div>
<div>Texto 5</div>
<div>Texto 6</div>
<div>Texto 7</div>
<div>Texto 8</div>
<div>Texto 9</div>
</section>
section {
display: flex;
align-items: center;
align-content: center;
flex-wrap: wrap;
height: 200px;
}
Con align-items
alineamos los elementos en el eje secundario, mientras que con align-content
alineamos el contenido del contenedor en el eje secundario. Es decir, con align-items
alineamos los elementos entre ellos, mientras que con align-content
alineamos el contenido del contenedor. En el ejemplo anterior podemos ver que con align-items
los elementos se alinean entre ellos, mientras que con align-content
el contenido del contenedor se alinea en el eje secundario.
Align-self
En ocasiones necesitamos alinear un elemento en el eje secundario de forma diferente al resto de elementos. Para ello tenemos la propiedad align-self
. Esta propiedad nos permite alinear un elemento en el eje secundario de forma diferente al resto de elementos.
Hasta ahora alineábamos los elementos en el padre, pero con align-self
podemos alinear un elemento en el eje secundario de forma diferente al resto de elementos.
<section>
<div>Texto 1</div>
<div>Texto 2</div>
<div>Texto 3</div>
</section>
section {
display: flex;
align-items: center;
}
section div:nth-child(2) {
align-self: flex-end;
}
Práctica de Flexbox
Un buen recurso para practicar Flexbox es Flexbox Froggy.
Grid
Si necesitamos crear un layout más complejo, podemos utilizar Grid
. Grid
es un sistema de rejilla bidimensional que nos permite crear layouts más complejos que con Flexbox
.
Grid container
Vamos a ver un ejemplo de cómo maquetar con Grid
. Para ello vamos a utilizar la siguiente estructura HTML.
<section>
<div>Texto 1</div>
<div>Texto 2</div>
<div>Texto 3</div>
<div>Texto 4</div>
<div>Texto 5</div>
<div>Texto 6</div>
<div>Texto 7</div>
<div>Texto 8</div>
<div>Texto 9</div>
</section>
Para crear un Grid
necesitamos crear un contenedor con la propiedad display: grid
, recordemos que por defecto los contenedores tienen por defecto display:block
. Este contenedor se conoce como Grid container
.
section {
display: grid;
}
Este código nos creará un Grid
con una sola columna y tantas filas como elementos tengamos.
Si queremos cambiar el número de columnas, podemos utilizar la propiedad grid-template-columns
. Esta propiedad nos permite definir el número de columnas que tendrá nuestro Grid
. Para definir el número de columnas podemos utilizar unidades de medida como px
, em
, rem
, fr
, etc.
Se van a crear tantas columnas como unidades de medida definamos. En el siguiente ejemplo vamos a crear 3 columnas de 100px cada una.
section {
display: grid;
grid-template-columns: 100px 100px 100px;
}
Con este ejemplo hemos creado un Grid
con 3 columnas de 100px cada una.
Podemos definir el ancho de una de las columnas con auto
y el resto con una medida, de esta manera la columna con auto
se adaptará al contenido, mientras que el resto de columnas tendrán el ancho que le hayamos definido.
Al poner auto
será el navegador el que decida el ancho de la columna en función del espacio que haya en el contenedor y del espacio que ocupe el contenido de la columna.
section {
display: grid;
grid-template-columns: auto 100px 100px;
}
La primera columna se adaptará al contenido, mientras que las otras dos tendrán un ancho de 100px.
Si definimos dos columnas con auto
, el navegador repartirá el espacio entre las dos columnas, pero no tiene por qué ser el mismo espacio para cada columna, ya que como hemos dicho el espacio dependerá del espacio del contenedor y del espacio del contenido.
section {
display: grid;
grid-template-columns: auto auto 100px;
}
En este ejemplo las dos primeras columnas se adaptarán al contenido, mientras que la tercera tendrá un ancho de 100px.
Fraction
Hay una unidad de medida que solo existe en Grid
y es fr
. Esta unidad de medida nos permite definir el ancho de las columnas en función del espacio disponible en el contenedor.
section {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
En este ejemplo las tres columnas tendrán el mismo ancho, ya que el espacio disponible en el contenedor se repartirá entre las tres columnas.
section {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
}
En este ejemplo la segunda columna tendrá el doble de ancho que las otras dos, ya que el espacio disponible en el contenedor se repartirá entre las tres columnas, pero la segunda columna tendrá el doble de espacio que las otras dos.
Podemos hacer lo mismo con las filas, para ello utilizamos la propiedad grid-template-rows
.
section {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
grid-template-rows: 1fr 2fr 1fr;
}
Cuadrícula vacía
Hemos dicho que podemos dividir el Grid
en columnas y filas, para ello ponemos tantas unidades de medida como columnas o filas queramos. Pero qué pasa si ponemos más unidades de medida de las que necesitamos.
<section>
<div>Texto 1</div>
<div>Texto 2</div>
<div>Texto 3</div>
<div>Texto 4</div>
<div>Texto 5</div>
<div>Texto 6</div>
<div>Texto 7</div>
<div>Texto 8</div>
<div>Texto 9</div>
</section>
section {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr 1fr;
}
En este ejemplo se creará un Grid
con 4 columnas y 4 filas, pero solo tenemos 9 elementos, mientras que nosotros hemos creado una cuadrícula de 16 elementos. ¿Qué pasa con los 7 elementos que nos sobran? El navegador los crea vacíos.
Grid-auto-rows
Si a la hora de crear el Grid
solo definimos el valor de grid-template-columns
, el navegador creará las filas necesarias para las columnas que hemos definido, pero las creará con el tamaño por defecto, es decir, con el tamaño del contenido.
Si queremos definir el tamaño de las filas podemos usar la propiedad grid-auto-rows
. Esta propiedad nos permite definir el tamaño de las filas que se crean por defecto.
section {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-auto-rows: 100px;
}
En este ejemplo se creará un Grid
con 4 columnas y tantas filas como elementos tengamos, pero el tamaño de las filas será de 100px.
Supongamos que también hemos definido grid-template-rows
, pero hemos definido el tamaño de las primeras filas y no de todas las filas necesarias, con grid-auto-rows
podemos definir el tamaño de las filas que faltan.
section {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: 100px 100px;
grid-auto-rows: 50px;
}
En este ejemplo se creará un Grid
con 4 columnas y tantas filas como elementos tengamos, pero el tamaño de las dos primeras filas será de 100px, mientras que el tamaño del resto de filas será de 50px.
Esto es muy útil cuando no sabemos cuántos elementos vamos a tener, ya que podemos definir el tamaño de las primeras filas y el tamaño de las filas que se creen por defecto.
Repeat
Imaginemos que queremos crear un Grid
con 100 columnas y todas del mismo tamaño. Tendríamos que escribir 100 veces la unidad de medida que queremos utilizar. Para evitar esto podemos utilizar la propiedad repeat
.
section {
display: grid;
grid-template-columns: repeat(100, 1fr);
}
Con repeat
podemos definir el número de columnas que queremos y la unidad de medida que queremos utilizar.
Podemos usar repeat
con subpartes de la cuadrícula. Por ejemplo, imaginemos que queremos crear otra vez 100 columnas, pero queremos que la primera y la última columna tengan un ancho de 100px y el resto de columnas tengan un ancho de 1fr.
section {
display: grid;
grid-template-columns: 100px repeat(98, 1fr) 100px;
}
Ahora supongamos que tenemos un patrón de columnas que se repite cada 3 columnas. Podemos utilizar repeat
para definir este patrón.
section {
display: grid;
grid-template-columns: repeat(3, 100px 1fr);
}
De esta manera creamos una cuadrícula de 6 columnas, donde el patrón se repite cada 2 columnas.
minmax
A lo mejor no sabemos el tamaño exacto de una fila o una columna, sino que lo que queremos es que ocupe un tamaño entre un mínimo y un máximo. Para ello podemos utilizar la propiedad minmax
.
section {
display: grid;
grid-template-columns: minmax(100px, 1fr) 1fr 1fr 1fr;
}
En este ejemplo queremos que cada columna tenga el 25% del ancho del contenedor, pero que la primera columna tenga un ancho mínimo de 100px. Es decir, si el espacio que ocupa la primera columnas es menor de 100px, la columna tendrá un ancho de 100px, pero si el espacio que ocupa la primera columna es mayor de 100px, la columna tendrá un ancho del 25% del contenedor.
Esto es muy útil por ejemplo cuando tenemos un índice en el lateral de la página y queremos que ocupe un ancho mínimo, pero que si el espacio disponible es mayor, ocupe el espacio que le corresponde.
<div>
<aside>Índice</aside>
<main>Contenido</main>
</div>
div {
display: grid;
grid-template-columns: minmax(100px, 1fr) 5fr;
}
De esta manera el índice tendrá un ancho mínimo de 100px, pero si el espacio disponible es mayor, el índice ocupará el espacio que le corresponde.
Grid-column-gap y Grid-row-gap
Si queremos añadir un espacio entre las columnas o entre las filas, podemos utilizar las propiedades grid-column-gap
y grid-row-gap
.
section {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-column-gap: 20px;
}
En este ejemplo hemos creado un Grid
con 3 columnas de 100px cada una y un espacio de 20px entre las columnas.
section {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-row-gap: 20px;
}
En este ejemplo hemos creado un Grid
con 3 columnas de 100px cada una y un espacio de 20px entre las filas.
Podemos definir el espacio entre las columnas y las filas con la propiedad grid-gap
.
section {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-gap: 20px 10px;
}
En este ejemplo hemos creado un Grid
con 3 columnas de 100px cada una y un espacio de 20px entre las columnas y un espacio de 10px entre las filas.
section {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-gap: 20px;
}
En este ejemplo hemos creado un Grid
con 3 columnas de 100px cada una y un espacio de 20px entre las columnas y las filas.
Auto-fill y Auto-fit
Con auto-fill
y auto-fit
podemos crear un Grid
con un número de columnas o filas que se adapte al espacio disponible en el contenedor, así podemos hacer el Grid
responsive.
section {
display: grid;
grid-template-columns: repeat(auto-fill, 100px);
}
En este ejemplo se crearán tantas columnas como quepan en el contenedor, pero cada columna tendrá un ancho de 100px.
section {
display: grid;
grid-template-columns: repeat(auto-fit, 100px);
}
En este ejemplo se crearán tantas columnas como quepan en el contenedor, pero cada columna tendrá un ancho de 100px y si sobra espacio en el contenedor, el espacio se repartirá entre las columnas.
Ahora lo podemos hacer más completo
section {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
}
En este ejemplo se crearán tantas columnas como quepan en el contenedor, pero cada columna tendrá un ancho mínimo de 100px y si sobra espacio en el contenedor, el espacio se repartirá entre las columnas. A medida que hagamos el navegador más pequeño, las columnas se irán adaptando al espacio disponible, hasta que llegue un momento en el que no para que quepan deberían tener un ancho menor de 100px, por lo que se eliminará una columna y se redistribuirá el espacio entre las columnas restantes.
section {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
grid-gap: 20px;
}
En este ejemplo se crearán tantas columnas como quepan en el contenedor, pero cada columna tendrá un ancho mínimo de 100px y si sobra espacio en el contenedor, el espacio se repartirá entre las columnas y habrá un espacio de 20px entre las columnas.
Auto-fill vs Auto-fit
La diferencia entre auto-fill
y auto-fit
es que auto-fill
crea tantas columnas o filas como quepan en el contenedor, mientras que auto-fit
crea tantas columnas o filas como quepan en el contenedor, pero si sobra espacio en el contenedor, el espacio se repartirá entre las columnas o filas.
Es decir, auto-fill
crea tantas columnas o filas como quepan en el contenedor, pero si sobra espacio en el contenedor, el espacio no se repartirá entre las columnas o filas, mientras que auto-fit
crea tantas columnas o filas como quepan en el contenedor, pero si sobra espacio en el contenedor, el espacio se repartirá entre las columnas o filas.
Grid-column-start y Grid-column-end (bento grid)
Hasta ahora hemos visto cómo crear un Grid
con columnas y filas, pero ¿qué pasa si queremos que un elemento ocupe más de una columna o fila? Para ello tenemos las propiedades grid-column-start
y grid-column-end
.
<section>
<div>Texto 1</div>
<div>Texto 2</div>
<div>Texto 3</div>
<div>Texto 4</div>
<div>Texto 5</div>
<div>Texto 6</div>
<div>Texto 7</div>
<div>Texto 8</div>
<div>Texto 9</div>
</section>
section {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-gap: 20px;
}
section div:nth-child(2) {
grid-column-start: 1;
grid-column-end: 3;
}
En este ejemplo hemos creado un Grid
con 3 columnas de 100px cada una y un espacio de 20px entre las columnas. El segundo elemento ocupa desde la primera columna hasta la tercera columna.
También podemos decirle el inicio y el final de la columna con la propiedad grid-column
.
section {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-gap: 20px;
}
section div:nth-child(2) {
grid-column: 1 / 3;
}
En este ejemplo hemos creado un Grid
con 3 columnas de 100px cada una y un espacio de 20px entre las columnas. El segundo elemento ocupa desde la primera columna hasta la tercera columna.
Si no queremos decirle dónde acabar, sino cuántas columnas queremos que ocupe, podemos utilizar la propiedad span
.
section {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-gap: 20px;
}
section div:nth-child(2) {
grid-column-start: 1;
grid-column-end: span 2;
}
En este ejemplo hemos creado un Grid
con 3 columnas de 100px cada una y un espacio de 20px entre las columnas. El segundo elemento ocupa desde la primera columna hasta la segunda columna, es decir, ocupa dos columnas.
Si queremos posicionarlos al final, pero no sabemos cuántas columnas hay, podemos utilizar números negativos.
section {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-gap: 20px;
}
section div:nth-child(2) {
grid-column-start: 1;
grid-column-end: -1;
}
En este ejemplo hemos creado un Grid
con 3 columnas de 100px cada una y un espacio de 20px entre las columnas. El segundo elemento ocupa desde la primera columna hasta la última columna, es decir, ocupa las tres columnas.
Grid-row-start y Grid-row-end (bento grid)
Podemos hacer lo mismo con las filas, para ello tenemos las propiedades grid-row-start
y grid-row-end
.
<section>
<div>Texto 1</div>
<div>Texto 2</div>
<div>Texto 3</div>
<div>Texto 4</div>
<div>Texto 5</div>
<div>Texto 6</div>
<div>Texto 7</div>
<div>Texto 8</div>
<div>Texto 9</div>
</section>
section {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-gap: 20px;
}
section div:nth-child(2) {
grid-row-start: 1;
grid-row-end: 3;
}
En este ejemplo hemos creado un Grid
con 3 columnas de 100px cada una y un espacio de 20px entre las columnas. El segundo elemento ocupa desde la primera fila hasta la tercera fila.
Tamibén podemos decirle el inicio y el final de la fila con la propiedad grid-row
.
section {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-gap: 20px;
}
section div:nth-child(2) {
grid-row: 1 / 3;
}
Al igual que antes, si no queremos decirle dónde acabar, sino cuántas filas queremos que ocupe, podemos utilizar la propiedad span
.
section {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-gap: 20px;
}
section div:nth-child(2) {
grid-row-start: 1;
grid-row-end: span 2;
}
En este ejemplo hemos creado un Grid
con 3 columnas de 100px cada una y un espacio de 20px entre las columnas. El segundo elemento ocupa desde la primera fila hasta la segunda fila, es decir, ocupa dos filas.
Si queremos posicionarlos al final, pero no sabemos cuántas filas hay, podemos utilizar números negativos.
section {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-gap: 20px;
}
section div:nth-child(2) {
grid-row-start: 1;
grid-row-end: -1;
}
En este ejemplo hemos creado un Grid
con 3 columnas de 100px cada una y un espacio de 20px entre las columnas. El segundo elemento ocupa desde la primera fila hasta la última fila, es decir, ocupa las tres filas.
Superposición de elementos
Podemos posicionar los elementos de forma que se superpongan unos a otros.
<section>
<div>Texto 1</div>
<div>Texto 2</div>
<div>Texto 3</div>
<div>Texto 4</div>
<div>Texto 5</div>
<div>Texto 6</div>
<div>Texto 7</div>
<div>Texto 8</div>
<div>Texto 9</div>
</section>
section {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-gap: 20px;
}
section div:first-child {
grid-column-start: 1;
grid-column-end: 2;
grid-row-start: 1;
grid-row-end: 2;
}
section div:nth-child(2) {
grid-column-start: 1;
grid-column-end: 2;
grid-row-start: 1;
grid-row-end: 2;
}
En este ejemplo hemos creado un Grid
con 3 columnas de 100px cada una y un espacio de 20px entre las columnas. El primer elemento ocupa desde la primera columna hasta la segunda columna y desde la primera fila hasta la segunda fila. El segundo elemento ocupa desde la primera columna hasta la segunda columna y desde la primera fila hasta la segunda fila.
Para controlar cuál de los elementos se superpone al otro, podemos utilizar la propiedad z-index
.
section {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-gap: 20px;
}
section div:first-child {
grid-column-start: 1;
grid-column-end: 2;
grid-row-start: 1;
grid-row-end: 2;
z-index: 1;
}
section div:nth-child(2) {
grid-column-start: 1;
grid-column-end: 2;
grid-row-start: 1;
grid-row-end: 2;
z-index: 2;
}
En este ejemplo hemos creado un Grid
con 3 columnas de 100px cada una y un espacio de 20px entre las columnas. El primer elemento ocupa desde la primera columna hasta la segunda columna y desde la primera fila hasta la segunda fila. El segundo elemento ocupa desde la primera columna hasta la segunda columna y desde la primera fila hasta la segunda fila. Como el segundo elemento tiene un z-index
mayor que el primer elemento, el segundo elemento se superpone al primero.
Layouts con Grid
Ahora que conocemos las propiedades básicas de Grid
, vamos a ver cómo podemos crear layouts con Grid
.
<header>Header</header>
<aside>Aside</aside>
<main>Main</main>
<footer>Footer</footer>
body {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 35px 1fr 100px;
min-height: 100vh;
}
header {
grid-column: 1 / -1;
}
main {
grid-column: span 2;
}
footer {
grid-column: 1 / -1;
}
En este ejemplo hemos creado un Grid
con 3 columnas y 3 filas. La primera fila tiene un alto de 35px, la segunda fila ocupa el resto del espacio disponible y la tercera fila tiene un alto de 100px. El header ocupa desde la primera columna hasta la última columna, el main ocupa desde la primera columna hasta la segunda columna y el footer ocupa desde la primera columna hasta la última columna.
Hemos puesto min-height: 100vh
para que el Grid
ocupe el 100% del alto de la pantalla, ya que si no ponemos esto, el Grid
solo ocupará el alto del contenido.
Sin embargo a la hora de ver el CSS cuesta entenderlo, por lo que podemos utilizar la propiedad grid-area
.
Grid-area
Podemos ponerle un nombre a cada una de las áreas del Grid
y luego utilizar ese nombre para posicionar los elementos.
<header>Header</header>
<aside>Aside</aside>
<main>Main</main>
<footer>Footer</footer>
body {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 35px 1fr 100px;
min-height: 100vh;
grid-template-areas:
"header header header"
"sidebar content content"
"footer footer footer";
}
header {
grid-area: header;
}
main {
grid-area: content;
}
footer {
grid-area: footer;
}
aside {
grid-area: sidebar;
}
Como hemos puesto nombre a cada una de las áreas del Grid
, podemos utilizar ese nombre para posicionar los elementos. De esta manera es más fácil entender el CSS.
Si ahora quisiéramos hacerlo responsive, solo tendríamos que cambiar el Grid
y el resto del CSS se mantendría igual.
body {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 35px 1fr 100px;
min-height: 100vh;
grid-template-areas:
"header header header"
"sidebar content content"
"footer footer footer";
}
@media (width < 400px) {
body {
grid-template-columns: 1fr;
grid-template-rows: 35px 1fr 100px;
grid-template-areas:
"header header sidebar"
"content content content"
"footer footer footer";
}
header {
grid-area: header;
}
main {
grid-area: content;
}
footer {
grid-area: footer;
}
aside {
grid-area: sidebar;
}
Ahora hemos hecho que cuando lo vemos en un dispositivo grande el sidebar esté a la izquierda y el contenido a la derecha, pero cuando lo vemos en un dispositivo pequeño, el sidebar está arriba y el contenido abajo.
Supongamos que queremos que en una zona no haya nada, podemos poner un punto.
body {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 35px 1fr 100px;
min-height: 100vh;
grid-template-areas:
"header header header"
"sidebar . content"
"footer footer footer";
}
@media (width < 400px) {
body {
grid-template-columns: 1fr;
grid-template-rows: 35px 1fr 100px;
grid-template-areas:
"header header sidebar"
"content content content"
"footer footer footer";
}
header {
grid-area: header;
}
main {
grid-area: content;
}
footer {
grid-area: footer;
}
aside {
grid-area: sidebar;
}
Ahora en pantallas grandes hay un hueco entre el sidebar y el contenido.
Justify-items, Align-items, Justify-content y Align-content
Podemos alinear el contenido y los elementos de un Grid
con las propiedades justify-items
, align-items
, justify-content
y align-content
.
Justify-items
Podemos alinear los elementos en el eje X del Grid
con la propiedad justify-items
.
Los valores que podemos utilizar son:
start
: alinea los elementos al principio del eje principal.end
: alinea los elementos al final del eje principal.center
: alinea los elementos en el centro del eje principal.stretch
: estira los elementos para que ocupen todo el espacio disponible en el eje principal.
<section>
<div>Texto 1</div>
<div>Texto 2</div>
<div>Texto 3</div>
</section>
section {
display: grid;
justify-items: center;
}
Justify-self
Con justify-items
alineamos todos los elementos en el eje principal del Grid
, pero con justify-self
podemos alinear un elemento en el eje principal del Grid
de forma diferente al resto de elementos.
<section>
<div>Texto 1</div>
<div>Texto 2</div>
<div>Texto 3</div>
</section>
section {
display: grid;
justify-items: center;
}
section div:nth-child(2) {
justify-self: end;
}
Align-items
Es muy parecido a justify-items
, pero en vez de alinear los elementos en el eje X, los alinea en el eje Y.
Los valores que podemos utilizar son:
start
: alinea los elementos al principio del eje secundario.end
: alinea los elementos al final del eje secundario.center
: alinea los elementos en el centro del eje secundario.stretch
: estira los elementos para que ocupen todo el espacio disponible en el eje secundario.
<section>
<div>Texto 1</div>
<div>Texto 2</div>
<div>Texto 3</div>
</section>
section {
display: grid;
align-items: center;
}
Align-self
Con align-items
alineamos todos los elementos en el eje secundario del Grid
, pero con align-self
podemos alinear un elemento en el eje secundario del Grid
de forma diferente al resto de elementos.
<section>
<div>Texto 1</div>
<div>Texto 2</div>
<div>Texto 3</div>
</section>
section {
display: grid;
align-items: center;
}
section div:nth-child(2) {
align-self: end;
}
Place-content
Si queremos usar justify-content
y align-content
a la vez, podemos usar place-content
.
Los valores que podemos utilizar son:
start
: alinea los elementos al principio del eje principal y secundario.end
: alinea los elementos al final del eje principal y secundario.center
: alinea los elementos en el centro del eje principal y secundario.stretch
: estira los elementos para que ocupen todo el espacio disponible en el eje principal y secundario.
<section>
<div>Texto 1</div>
<div>Texto 2</div>
<div>Texto 3</div>
</section>
section {
display: grid;
place-content: center;
}
Práctica de Grid
Un buen recurso para practicar Grid es Grid Garden.
Centrar un div
Hasta ahora hemos visto 3 formas de centrar un div
:
- Con
position: absolute
. - Con
display: flex
. - Con
display: grid
.
Animaciones
Dentro de las animaciones hay dos tipos las transiciones
y las animaciones
Transiciones
En las transiciones cambiamos un elemento de un estado inicial a un estado objetivo
Supongamos que tenemos el siguiente círculo
<div class="pulser"></div>
Y su CSS
.pulser {
width: 30px;
height: 30px;
background-color: #09f;
border-radius: 50%;
position: relative;
}
Los elementos de html pueden tener estados, por ejemplo el estado hover
, que es cuando el usuario pasa el cursor por encima del elemento
.pulser:hover {
scale: 2;
background: purple;
box-shadow: 0 0 10px purple;
}
Al hacer scale
hacemos que aumente el tamaño, pero ocupando el mismo espacio, sin embargo, si hubiésemos cambiado el width
y el height
el botón se habría movido de sitio.
Transition
Lo que pasa es que si ahora pasamos el ratón por encima del círculo cambia el estado de golpe, así que aquí es donde entra la transición
, que es como le indicamos al CSS cómo se tiene que modificar el estado. Por ejemplo si queremos que la transición dure 1 segundo
.pulser {
width: 30px;
height: 30px;
background-color: #09f;
border-radius: 50%;
position: relative;
transition: 1s;
}
Es importante poner la transición en .pulser
y no en .pulser:hover
porque si no, no se aplicaría la transición al volver al estado inicial. Es decir, cuando pasemos el ratón por encima del círculo se verá la transición, pero cuando quitemos el ratón del círculo no habrá una transición de vuelta, sino que pasará de golpe al estado inicial
Qué se quiere transicionar transition-property
Con lo anterior se haría una transición de color, de tamaño y de fondo, pero si no queremos que se produzca una transición de todo podemos indicárselo mediante transition-property
.pulser {
width: 30px;
height: 30px;
background-color: #09f;
border-radius: 50%;
position: relative;
transition: 1s;
transition-property: background-color, scale;
}
De esta manera solo se hará la transición de background-color
y scale
Transiciones suaves
La transición por defecto se hace de manera lineal, pero si queremos cambiarla podemos hacerlo mediante transition-timing-function
.pulser {
width: 30px;
height: 30px;
background-color: #09f;
border-radius: 50%;
position: relative;
transition: 1s;
transition-property: background-color, scale;
transition-timing-function: ease-in-out;
}
De esta manera la transición será más suave al principio y al final. Los posibles valores son los siguientes:
- linear
- ease
- ease-in
- ease-out
- ease-in-out
- cubic-bezier(n,n,n,n)
Transiciones por pasos
Si queremos que la animación se haga en varios pasos podemos usar steps(n)
, donde n
es el número de pasos que queremos que tenga la animación
.pulser {
width: 30px;
height: 30px;
background-color: #09f;
border-radius: 50%;
position: relative;
transition: 1s;
transition-property: background-color, scale;
transition-timing-function: steps(5);
}
De esta manera se realizará la transición en 5 pasos durante 1 segundo
Control total de la transición con cubic-bezier
Para poder controlar perfectamente la transición podemos usar cubic-bezier(n,n,n,n)
, donde n
es un número entre 0 y 1 que indica la posición del punto en el eje X e Y
.pulser {
width: 30px;
height: 30px;
background-color: #09f;
border-radius: 50%;
position: relative;
transition: 1s;
transition-property: background-color, scale;
transition-timing-function: cubic-bezier(0.1, 0.7, 1.0, 0.1);
}
Con delay
podemos indicar el tiempo que tiene que pasar hasta que se inicie la transición
.pulser {
width: 30px;
height: 30px;
background-color: #09f;
border-radius: 50%;
position: relative;
transition: 1s;
transition-property: background-color, scale;
transition-timing-function: cubic-bezier(0.1, 0.7, 1.0, 0.1);
transition-delay: 1s;
}
Con el delay
se pueden hacer animaciones de cargas, por ejemplo
<section>
Haz hover para mostrar los elementos
<div class="pulser"></div>
<div class="pulser"></div>
<div class="pulser"></div>
</section>
section {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}
.pulser {
width: 30px;
height: 30px;
border-radius: 50%;
position: relative;
position: relative;
opacity: 0;
transition: 2s;
transition-timing-function: ease;
}
section {
display: flex;
gap: 16px;
justify-content: center;
aling-items: center;
}
section:hover .pulser {
opacity: 1;
}
.pulser:first-child {
transition-delay: 0s;
}
.pulser:nth-child(2) {
transition-delay: 300ms;
}
.pulser:last-child {
transition-delay: 600ms;
}
En easings.co podemos ver y configurar las transiciones
Todo en una línea
En .pulser
hemos puesto transition
y transitio-timing-function
, pero también podemos ponerlo todo en una línea
.pulser {
width: 30px;
height: 30px;
background-color: #09f;
border-radius: 50%;
position: relative;
transition: background 300ms ease-in-out 2s;
}
Con esto, lo que le hemos dicho es anime el background
durante 300ms, con una transición suave al principio y al final y que espere 2 segundos antes de empezar la transición
Si queremos hacer especificar varios elementos podemos hacerlo de la siguiente manera
.pulser {
width: 30px;
height: 30px;
background-color: #09f;
border-radius: 50%;
position: relative;
transition: background 300ms ease-in-out 2s, scale 1s ease-in-out 1s;
}
¿Qué transicionar?
A la hora de meter transiciones, se puede buscar qué se puede transicionar en Animatable CSS properties, pero para no estar perdiéndo el tiempo buscando, lo mejor es transicionar propiedades con cabeza, por ejemplo algo que se puede transicionar es un color, un tamaño, etc.
Lo ideal es transicionar propiedades con estados intermedios, por ejemplo una fuente no tiene un estado intermedio y no tiene sentido hacerle una transición de una fuente a otra
Distintas transiciones al inicio y al final
Antes hemos dicho que hay que poner las transiciones en el elemento y no en el hover, porque de esta manera la transición solo se verá cuando se pone el ratón encima del elemento y no cuando quites el ratón. Pues si se quieren tener distintas animaciones al inicio y al final podemos aprovecharnos de esto. En el elemento pondremos la transición final y en el hover la inicial
.pulser {
width: 30px;
height: 30px;
background-color: #09f;
border-radius: 50%;
position: relative;
transition: background 300ms ease-in-out
}
.pulser:hover {
scale: 2;
background: purple;
box-shadow: 0 0 10px purple;
transition: 1s;
transition-duration: 1s;
}
De esta manera cuando pasemos el ratón por encima del elemento se hará una transición de 300 ms y cuando quitemos el ratón la transición será de 1 segundo
Accesibilidad
Hay gente que se puede llegar a marear con las transiciones, por lo que podemos añadir una media query para quitarlas
@media (prefers-reduced-motion: reduce) {
.pulser {
transition: none;
}
}
Animaciones
Las transiciones son las animaciones cuando interactuamos con los elementos, pero en las animaciones no neceitamos interactuar con el elemento, pueden ejecutarse solas. Por ejemplo, el típico botón que cada cierto tiempo cambia se mueve para que sepas que tienes que pilsarlo
Keyframes
Volvemos al ejemplo de la bola azul y quitamos todas las transiciones
<div class="pulser"></div>
.pulser {
width: 30px;
height: 30px;
background-color: #09f;
border-radius: 50%;
}
Tenemos que indicarle al CSS que queremos hacer una animación, para ello usamos @keyframes
y le damos un nombre a la animación
@keyframes move {
}
Ahora le tenemos que decir desde dónde empieza este frame, para ello usamos from
y dónde termina, para ello usamos to
@keyframes move {
from {
}
to {
}
}
Ahora tenemos que indicarle qué propiedades queremos que cambien, por ejemplo la posición
@keyframes move {
from {
transform: translateX(0);
}
to {
transform: translateX(100px);
}
}
De esta manera cuando entremos en la página la bola azul se moverá 100px hacia la derecha
After
En un elemento se puede poner un after
que es un elemento que se pone después del elemento principal
<div class="pulser"></div>
.pulser {
width: 30px;
height: 30px;
background-color: blue;
border-radius: 50%;
}
.pulser::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: blue;
border-radius: 50%;
z-index: -1;
}
Esto lo que hace es poner un círculo azul detrás del círculo azul, por lo que ahora tenemos dos círculos azules
Ahora definimos los keyframes
@keyframes move {
0% {
opacity: 0;
}
50% {
scale: 1.5;
opacity: 40%;
}
100% {
opacity: 60%;
}
}
Y como ya hemos definido los keyframes, ahora solo tenemos que indicarle al CSS que queremos que se ejecute la animación
.pulser::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: blue;
border-radius: 50%;
z-index: -1;
animation-name: pulse;
animation-duration: 2s;
animation-timing-function: ease-in-out;
}
Ahora cuando cargue la página se vería como si el círculo azul tuviese un latido
Pero solo se produce una vez, para que se produzca más veces necesitamos añadir animation-iteration-count
.pulser::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: blue;
border-radius: 50%;
z-index: -1;
animation-name: pulse;
animation-duration: 2s;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
}
Ahora se producirá infinitas veces
Movimiento
Podemos hacer que un elemento se mueva
<div class="pulser"></div>
.pulser {
width: 30px;
height: 30px;
background-color: blue;
border-radius: 50%;
position: relative;
}
.pulser::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: blue;
border-radius: 50%;
z-index: -1;
animation-name: mover;
animation-duration: 2s;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
@keyframes move {
from {
trasnform: translateX(0);
}
to {
transform: translateX(100px);
}
}
Ahora la bola azul se moverá 100px hacia la derecha
Dirección
Para que la bola azul se mueva hacia la izquierda solo hay que hacer animation-direction: reverse
.pulser::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: blue;
border-radius: 50%;
z-index: -1;
animation-name: mover;
animation-duration: 2s;
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-direction: reverse;
}
Si lo que queremos es que la bola vaya de un lado al otro hay que poner animation-direction: alternate
.pulser::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: blue;
border-radius: 50%;
z-index: -1;
animation-name: mover;
animation-duration: 2s;
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-direction: alternate;
}
Pausar animaciones
Imagina que tienes tarjetas que tienen animaciones, a lo mejor quieres que cuando pases el ratón por encima de la tarjeta se pare la animación, para ello podemos usar animation-play-state: paused
.card:hover {
animation-play-state: paused;
}
CSS nesting
Hemos declarado en el CSS las propiedades del pulser y las propiedades cuando se hace hover, pero se puede hacer todo junto
.pulser {
width: 30px;
height: 30px;
background-color: blue;
border-radius: 50%;
position: relative;
&::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: blue;
border-radius: 50%;
z-index: -1;
animation-name: mover;
animation-duration: 2s;
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-direction: alternate;
}
&:hover::after {
animation-play-state: paused;
}
}
Cómo terminar las animaciones
Si tenemos una animación que solo se ejecuta una vez, por ejemplo, que la bola azul se desplace hacia la derecha, cuando termine la animación irá de golpe a su posición inicial. Para evitar esto se puede usar animation-fill-mode: forwards
.pulser::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: blue;
border-radius: 50%;
z-index: -1;
animation-name: mover;
animation-duration: 2s;
animation-timing-function: linear;
animation-direction: alternate;
animation-fill-mode: forwards;
}
De esta manera, cuando termine la animación, la bola azul se quedará en la posición final
Si en vez de forwards
ponemos backwards
la animación empezará desde el estado final
Si ponemos both
la animación empezará desde el estado final y terminará en el estado final
Todo en una línea
Tenemos un montón de propiedades (animation-name
animation-duration
, animation-timing-function
, animation-direction
, animation-fill-mode
), pero se pueden poner todas en una línea. Todo lo anterior se podría poner así
.pulser::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: blue;
border-radius: 50%;
z-index: -1;
animation: mover 2s linear alternate forwards;
}
Podemos crear varias animaciones
.pulser::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: blue;
border-radius: 50%;
z-index: -1;
animation:
mover 2s linear alternate forwards,
agrandar 1s linear 2s both;
}
Pero como no existe la animación agrandar
la creamos con keyframes
@keyframes agrandar {
0% {
transform: scale: 1;
}
25% {
transform: scale: 1.5;
}
50% {
transform: scale: 2;
}
75% {
transform: scale: 1.6;
}
100% {
transform: scale: 2;
}
}
Se va a reproducir una detrás de la otra, porque a agrandar se le ha puesto un delay de 2 segundos, que es lo que dura la primera animación, pero si queremos que sea al mismo tiempo, hay que quitar el delay
.pulser::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: blue;
border-radius: 50%;
z-index: -1;
animation:
mover 2s linear alternate forwards,
agrandar 1s linear both;
}
Animaciones con scroll
Ejemplo de barra de progreso
Por ejemplo, si queremos hacer una barra que vaya aumentando de tamaño a medida que vamos bajando por la página
<section>
<div id="barra"></div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit
</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit
</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit
</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit
</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit
</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit
</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit
</p>
</section>
section {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}
#barra {
position: fixed;
top: 0;
width: 0%;
background-color: red;
height: 1em;
animation: barra-grow auto linear;
animation-timeline: scroll(root block);
}
@keyframes barra-grow {
from {
width: 0%;
}
from {
width: 100%;
}
}
Como en animation
hemos puesto un tiempo de auto
para saber cuánto tiempo tiene que durar la animación, el navegador mirará animation-timeline
, donde le indicamos que tiene que fijarse en el scroll. Dentro de la función scroll
le decimos en qué elemento se tiene que fijar, en nuestro caso hemos puesto rootp
porque queremos el scroll de la página, pero se podría poner cualquier otro elemento de la página. Además le tenemos qu decir si queremos que se fije en el scroll vertical o en el horizontal, en nuestro caso hemos puesto block
porque queremos que se fije en el scroll vertical (block
es el valor por defecto, por lo que si quieres no hace falta ponerlo)
Ejemplo de header que cambia de color
Si queremos que cuando hagamos scroll el header cambie de color
<header>
<nav>
<ul>
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
</nav>
</header>
header {
position: sticky;
top: 0;
width: 100%;
background-color: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
z-index: 2;
animation: header-color linear both;
animation-timeline: scroll(root block);
}
@keyframes header-color {
from {
background-color: white;
}
to {
background-color: gray;
backdrop-filter: blur(5px);
color: white;
}
}
Pero haciéndolo así la animación del header termina solo cuando se llega al final de la página, pero a nosotros nos interesa que termine cuando se ha hecho un poco de scroll, para ello quitamos el both
del animation
y ponemos animation-range: 0 200px
para que la animación termine cuando se ha hecho un scroll de 200px, es decir, se le está diciendo que la animación va desde los 0 px hasta los 200 px
header {
position: sticky;
top: 0;
width: 100%;
background-color: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
z-index: 2;
animation: header-color linear;
animation-timeline: scroll(root);
animation-range: 0 200px;
}
Ejemplo de galería de imágenes
Imaginemos que tenemos un montón de imágenes y queremos que cuando vayamos haciendo scroll vayan apareciendo
<section>
<img src="img1.jpg" alt="imagen 1">
<img src="img2.jpg" alt="imagen 2">
<img src="img3.jpg" alt="imagen 3">
<img src="img4.jpg" alt="imagen 4">
<img src="img5.jpg" alt="imagen 5">
<img src="img6.jpg" alt="imagen 6">
<img src="img7.jpg" alt="imagen 7">
<img src="img8.jpg" alt="imagen 8">
<img src="img9.jpg" alt="imagen 9">
<img src="img10.jpg" alt="imagen 10">
</section>
section {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 16px;
}
img {
width: 100%;
height: auto;
opacity: 0;
animation: aparecer linear both;
animation-timeline: view()
animation-range: entry 20% cover 30%;
}
@keyframes aparecer {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
con animation-timeline: view()
le estamos diciendo que haga la animación cuando la imagen se vea en la pantalla y con animation-range: entry 20% cover 30%
le estamos diciendo que la animación empiece cuando la imagen ocupe el 20% de la pantalla y que termine cuando ocupe el 30% de la pantalla
Al poner both
en animation
le estamos diciendo que la animación se haga tanto al aparecer como al desaparecer, es decir, que cuando la imagen aparece se ve la animación, pero cuando desaparece también se ve la animación pero al revés, es decir, que la imagen va teniendo una opacidad de 1 a 0 poco a poco