En este documento abordaremos el tema del diseño web adaptativo o responsive, aunque en breve veremos que estos dos conceptos no son exactamente iguales. Básicamente, la temática a abordar es cómo diseñar una web para que se vea adecuadamente en diferentes tipos de dispositivos o resoluciones, tales como smartphones, tablets o monitores de alta resolución.
Como acabamos de comentar, abordaremos la problemática de cómo diseñar una web para distintos tipos de dispositivos. Esta afirmación en sí plantea dos preguntas:
Tratemos de responder a la primera pregunta: ¿qué tipos principales de dispositivos podemos o debemos considerar?. Realmente no es ésa la pregunta adecuada, sino más bien a cuántos tipos de resoluciones diferentes podemos o debemos adaptar nuestra web. Y para responder a esta pregunta, podemos hacer un análisis rápido de los distintos tipos de pantalla en los que habitualmente podemos consultar una página web:
Vayamos ahora con la segunda pregunta formulada anteriormente: a la hora de abordar el diseño de una web para dar respuesta a todos los tipos de resoluciones posibles (o un grupo de ellos), tenemos dos estrategias:
Una de las etiquetas meta que comentamos en las primeras sesiones de este curso es la etiqueta viewport. Esta etiqueta permite a los diseñadores web controlar el área visible de una web. En general, la etiqueta que se recomienda utilizar tiene este aspecto:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
El parámetro width=device-width
hace que la anchura de la página se iguale a la anchura de la pantalla del dispositivo. Por otra parte, el parámetro initial-scale=1.0
establece el nivel de zoom inicial en 1, es decir, en el zoom del 100%, cuando la página se carga por primera vez.
Las media queries (en español, consulta sobre medios) son una técnica proporcionada por CSS3 que permite adaptar la visualización del contenido de una página a las características del dispositivo en que se va a mostrar. Estas características incluyen, sobre todo, la resolución de la pantalla, pero también podemos hablar de otras, como el tipo de medio. Así, por ejemplo, podemos definir un estilo diferente para una web que se vaya a imprimir en papel y eliminar el color de fondo, entre otras cosas.
Las media queries se definen en el propio documento CSS, a través de la expresión @media
seguida de las condiciones que debe cumplir el dispositivo para aplicar los estilos incluidos en ella. En concreto, su sintaxis general es:
@media not|only tipo_medio and (expresiones)
{
estilos CSS
}
donde:
tipo_medio
alude al tipo de medio donde se va a mostrar el contenido. Típicamente es screen (pantalla), pero puede valer también print (impreso en papel), speech (hablado) u all.min-width
/ max-width
).Por ejemplo, esta media query se aplicaría únicamente a pantallas con una resolución mínima de 768px:
@media only screen and(min-width: 768px)
{
...
}
Para el uso que vamos a hacer aquí de las media queries nos bastará con especificar una anchura mínima o máxima, por lo que podemos dejarlas con este formato:
@media (min-width: 768px)
{
...
}
A la hora de aplicar media queries a nuestra web para definir diferentes disposiciones y diseños de elementos acordes a distintas resoluciones de pantalla, una estrategia general es:
Por ejemplo, supongamos el siguiente contenido HTML:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Ejemplo media queries</title>
<link rel="stylesheet" href="estilos.css">
</head>
<body>
<section id="contenedor">
<section id="caja1">Caja 1</section>
<section id="caja2">Caja 2</section>
</section>
</body>
</html>
Vamos a definir dos tipos de resoluciones: para pantallas de hasta 768px de ancho, mostraremos una caja debajo de la otra. En cambio, para pantallas de mayor anchura, las mostraremos en paralelo, usando para ello un grid de dos columnas. Nuestro CSS quedaría así:
body
{
font-family: Arial;
margin: 10px 5%;
}
#caja1
{
background-color:lightcoral;
padding: 10px;
margin-bottom: 10px;
border: 1px solid black;
}
#caja2
{
background-color:lightskyblue;
padding: 10px;
margin-bottom: 10px;
border: 1px solid black;
}
@media(min-width: 768px)
{
body
{
margin: 100px 20%;
}
#contenedor
{
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: auto;
gap: 10px;
}
}
Y obtendríamos un resultado como este (baja resolución / alta resolución):
Ejercicio 1:
Descarga este ejemplo y define un documento CSS donde, ayudándote de media queries, definamos tres posibles disposiciones:
- Para resoluciones bajas (hasta 768px), mostraremos las cajas una debajo de otra
- Para resoluciones intermedias (hasta 992px), mostraremos la caja 1 arriba, la caja 4 abajo, y las dos intermedias en paralelo. Además, cambiaremos el color de las cajas 1 y 4 a gris (ver imagen resultado)
- Para resoluciones mayores, mostraremos las 4 cajas en paralelo con sus colores originales
Flexbox (flexible boxes) es un mecanismo de diseño web responsive facilitado por CSS3, que permite especificar una serie de propiedades en las cajas para que se adapten automáticamente al tamaño de pantalla existente, dependiendo de si van a tener suficiente espacio para mostrarse de un modo u otro.
Del mismo modo que ocurre con el grid de CSS, es necesario que las cajas involucradas en el proceso responsive estén contenidas en otra, de forma que podemos especificar las propiedades generales de flexbox en la caja contenedora, y luego definir, adicionalmente, cómo queremos disponer las cajas en ese contenedor.
Entre las propiedades que podemos definir en la caja contenedora, podemos destacar las siguientes:
display
: en este caso, la propiedad display deberá tener el valor de flex para habilitar el contenedor como un contenedor de elementos flexibles. Alternativamente, también se le puede dar el valor inline-flex si queremos que los elementos de dentro se comporten como elementos en línea (no en bloque).flex-direction
: indica cómo se van a disponer las cajas dentro del contenedor. El valor por defecto es row, que hace que se dispongan de izquierda a derecha, pero también podemos utilizar row-reverse (horizontal pero invertido), column (de arriba a abajo) y column-reverse (vertical pero invertido). Podemos intuir, por tanto, que con Flexbox vamos a poder disponer los elementos en una dirección (bien horizontal, bien vertical) de forma flexible.justify-content
: indica cómo se va a rellenar el espacio entre cajas, si lo hay. Puede tomar los valores flex-start (se agrupan las cajas al inicio del espacio disponible), flex-end (al final), center (centradas en medio del espacio disponible), space-between (justificadas con espacio entre ellas) o space-around (justificadas con espacio también a los lados).flex-wrap
: indica cómo vamos a adaptar las cajas en caso de que no quepan todas en una misma fila (o columna). Su valor por defecto es nowrap, lo que indica que no hay ningún ajuste: las cajas se disponen según lo indicado en las propiedades anteriores, y si no caben se siguen disponiendo en esa dirección. Pero si lo establecemos a wrap, entonces se redistribuirán si no hay espacio suficiente. Es el valor más habitual si queremos establecer un diseño responsive.Existen algunas webs como esta donde podemos probar el comportamiento de estas y otras propiedades, y ver cómo funciona cada una en realidad.
Para cada caja contenida en el elemento contenedor, podemos configurar sus propiedades flexbox para indicar dónde se va a ubicar y cuánto espacio va a ocupar. Algunas de estas propiedades son:
order
: indica el orden de la caja dentro de la secuencia de cajas contenidas. Si no indicamos nada, cada caja se coloca a continuación de la anterior, siguiendo la disposición indicada en la caja contenedora. Pero podemos alterar ese orden natural reubicando las cajas. Se trata simplemente de un número; cuanto mayor sea, la caja se colocará más hacia el final de la secuencia.flex
: indica el tamaño de la caja respecto al resto. Son tamaños relativos, igual que ocurre con las unidades fr en la rejilla grid CSS. Si todas las cajas tienen un tamaño flex de 1, todas ocuparán lo mismo. Si a alguna le asignamos un tamaño de 2, ocupará el doble que el resto. Alternativamente, también podemos utilizar esta propiedad para dar un tamaño fijo en píxeles (por ejemplo, flex:200px) o en porcentaje (flex: 40%). Esta última opción es útil si queremos controlar mejor cuántas columnas queremos que haya en cada fila.min-width
: indica la anchura mínima que debe tener la caja para mostrar su contenido. Si esta anchura no se cumple y tenemos habilitada la opción flex-wrap: wrap
en el contenedor, entonces hará que vaya a la siguiente fila/columna disponible para mostrarse.Echemos un vistazo a este ejemplo:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Ejemplo flexbox</title>
<link rel="stylesheet" href="estilos.css">
</head>
<body>
<section id="contenedor">
<section id="caja1">Caja 1</section>
<section id="caja2">Caja 2</section>
<section id="caja3">Caja 3</section>
</section>
</body>
</html>
Imaginemos que queremos poner las tres cajas en horizontal, con la caja 2 ocupando el doble de espacio, y que todas tengan una anchura mínima de 250px. Si eso no puede cumplirse, queremos que las cajas se redistribuyan para cumplir con esa anchura mínima (normalmente una debajo de otra).
En primer lugar, definimos las características del elemento contenedor:
#contenedor
{
display: flex;
flex-direction: row;
justify-content: space-between;
flex-wrap: wrap;
}
Después, establecemos las propiedades de las cajas contenidas. Además de sus características particulares (color de fondo, padding, etc), indicamos sus propiedades flexbox: anchura (propiedad flex) y anchura mínima.
#caja1, #caja3
{
background-color:lightcoral;
padding: 10px;
margin: 10px;
flex: 1;
min-width: 250px;
}
#caja2
{
background-color:lightskyblue;
padding: 10px;
margin: 10px;
flex: 2;
min-width: 250px;
}
Si vamos variando el tamaño de la ventana del navegador, podemos comprobar cómo las propias cajas se van ajustando a distintos tamaños y posiciones para cumplir con lo establecido. Aquí vemos la evolución desde pantallas grandes a pequeñas:
Notar que, si eliminamos la propiedad flex-wrap: wrap
del elemento contenedor, las cajas ya no se redistribuyen. Se quedan ocupando su espacio original, y si encogemos demasiado la pantalla nos tocará hacer scroll para verlas.
Notar también que, utilizando flexbox, podemos reajustar las cajas automáticamente en cuanto el tamaño de la pantalla “choque” con los requisitos de cada caja, pero no podemos controlar del todo dónde va a parar cada caja. En el ejemplo anterior, llega un punto en que la caja 3 baja a la segunda fila, quedando la caja 1 y la 2 en primera fila… pero quizá preferiríamos otra distribución para esa situación intermedia.
Puedes leer más información sobre Flexbox en otras webs interesantes, como por ejemplo esta.
Ejercicio 2:
Descarga este ejemplo que ya hemos utilizado en el ejercicio previo. Ahora vamos a configurarlo mediante flexbox para que:
- Las dos cajas centrales ocupen el doble de tamaño que las laterales. Las laterales van a tener un color de fondo gris y las centrales amarillo-naranja.
- Las cajas laterales tengan una anchura mínima de 200px, y las centrales de 300px. Cuando esto no sea posible, se redistribuirán
Aquí tienes un ejemplo de cómo puede quedar, a algunas de las resoluciones posibles:
En general, flexbox es una buena opción para una distribución flexible unidimensional (es decir, colocar componentes en una misma fila o columna y que se auto-distribuyan dependiendo del tamaño disponible). Pero para disposiciones bidimensionales (tablas), flexbox se queda corto por sí mismo, si queremos controlar la distribución concreta de los elementos. Una alternativa a esto podría ser utilizar grid y media-queries para diferentes posibles tamaños.
Con lo visto hasta ahora, podemos optar por un diseño adaptativo (media queries + grid) si queremos controlar mejor la disposición bidimensional de los elementos de la web, o por un diseño responsive (flexbox) si sólo queremos controlar la disposición unidimensional (fila a fila, o columna a columna). El inconveniente de lo primero es que nos “obliga” a plantear distintos diseños complementarios para elegir automáticamente cuál de ellos cargar. Una alternativa a esto es utilizar algún framework de diseño web, como Bootstrap, que simplifica bastante esta tarea.