En anteriores temas hemos visto como con grid
y flex
ya podíamos hacer algunas cosas que se ajustaran al tamaño de la pantalla, lo que llamamos responsivo. En este tema vamos a ver mas formas de hacer responsivo una página.
Mas información:
Hacer un diseño responsivo es que la misma página se adapte a distintos tamaños de pantalla. Hacer un diseño adaptativo es hacer páginas distintas según el tamaño de la pantalla.
Ejemplo de diseño adaptativo es la página de AliExpress:
La ventaja de las webs adaptativas es que en la versión móvil solo se cargan las cosas que se necesitan para el movil además de que está hecha pensando en móvil. El inconveniente es que hay que desarrollar dos páginas.
Añadir a todas las páginas la siguiente linea en el <head>
del HMTL
<meta name="viewport" content="width=device-width, initial-scale=1">
Con esto se consigue que la página tenga el tamaño del dispositivo, ya que sino se pone , el dispositivo podría hacer que la página se haga mas grande y crear barras de desplazamiento.
Mas información:
Podemos hacer ciertos tamaños que sean en función del tamaño de la pantalla. Para ello se usan las unidades como vw
o vh
que hacen referencia al tamaño de la pantalla. CSS Viewport Units: A Quick Start
vh
Es la altura de la ventana. Un valor de 1vh es igual al 1% del alto.vw
Es el ancho de la ventana. Un valor de 1vw es igual al 1% del ancho.vmin
Mínimo entre el ancho y el alto. Es la dimensión más pequeña de la ventana. Si el alto de la ventana gráfica es menor que el ancho, el valor de 1vmin será igual al 1% de la altura. De manera similar, si el ancho es menor que la altura, el valor de 1vmin será igual al 1% del ancho.vmax
Máximo entre el ancho y el alto. Es la dimensión más grande de la ventana. Si el alto de la ventana gráfica es mayor que el ancho, el valor de 1vmin será igual al 1% de la altura. De manera similar, si el ancho es mayor que la altura, el valor de 1vmin será igual al 1% del ancho.
.c-titulo { font-size: 10vw; }
<p class="c-titulo">Hola mundo</p>
En el ejemplo anterior, el tamaño de la fuente se hace mas grande a medida que se hace mas ancha la ventana.
Podemos pensar que 100vw
es similar a 100%
, pero hay dos diferencias Difference between Width:100% and width:100vw?.
100%
hace referencia al tamaño de donde está el elemento donde estamos , no al tamaño de la ventana.100%
no incluye el tamaño de las barras de desplazamiento , mientras que 100vw
si que lo hace. Para ésto último a veces se hace lo siguiente:
.ejemplo { width: 100vw; height: 100vw; max-width: 100%; }
vw
o vh
.c-titulo { font-size: 3.14vw; }
La unidad rem
hace referencia al tamaño de fuente del HTML. El tamaño en píxeles se obtiene de multiplicar el valor de rem
por el tamaño de la fuente de la página
html { font-size:12px; }
Otra forma de cambiar el font-size
por defecto es configurar el tamaño de 1rem
en el propio navegador. Lo suele hacer gente con diversidad visual. En chrome es en "Configuración --> Aspecto --> Personalizar fuentes"
Veamos ahora como se usa rem
en bootstrap para los botones:
Tamaño botón | Tamaño de fuente | Padding horizontal | Padding vertical |
---|---|---|---|
Normal | 1rem | 0.75rem | 0.375rem |
Grande btn-lg | 1.25rem | 1rem | 0.5rem |
Pequeño btn-sm | 0.875rem | 0.5rem | 0.25rem |
Vamos ahora los mismo datos pero en px
suponiendo que el tamaño de fuente es 16px
.
Tamaño botón | Tamaño de fuente | Padding horizontal | Padding vertical |
---|---|---|---|
Normal | 16px | 12px | 6px |
Grande btn-lg | 20px | 16px | 8px |
Pequeño btn-sm | 14px | 8px | 4px |
Y por último veamos la relación que hay entre en padding y el tamaño de fuente en %
Tamaño botón | Padding horizontal respecto del tamaño de fuente | Padding vertical respecto del tamaño de fuente |
---|---|---|
Normal | 75% | 37,5% |
Grande btn-lg | 80% | 40% |
Pequeño btn-sm | 57,142% | 28,571% |
Resulta que no hay una relación constante entre el tamaño de la fuente y el tamaño del padding.
Es decir para un tamaño normal el padding horizontal es el 75% del tamaño de la fuente pero en un botón grande (que el tamaño de fuente es más grande) el padding horizontal es el 80% del tamaño de la fuente y para terminar en un botón pequeño el padding horizontal es el 57% del tamaño de la fuente. ¿No debería ser constante el tamaño del padding respecto del tamaño de fuente? Por lo tanto si aumentamos el tamaño de fuente en el navegador , los padding no deberían aumentar proporcionalmente sino como vemos que lo hace bootstrap.
La unidad em
hace referencia al tamaño de fuente del elemento donde está. El tamaño en píxeles se obtiene de multiplicar el valor de em
por el tamaño de la fuente de ese elemento
px
ya que con los modificadores responsivos y nuestro sistema de tamaños , podemos controlar como queda todo.
Podemos usar funciones en CSS para calcular valores.
Retorna el mínimo de los dos valores.
.c-titulo { font-size: min(100px,10vw); }
<p class="c-titulo">Hola mundo</p>
En el ejemplo el tamaño máximo de la fuente nunca será mayor que 100px por mucho que se haga grande la ventana.
Retorna el máximo de los dos valores.
.c-titulo { font-size: max(40px,10vw); }
<p class="c-titulo">Hola mundo</p>
En el ejemplo el tamaño mínimo de la fuente nunca será menor que 40px por mucho que se haga pequeña la ventana.
Retorna un valor pero sin ser menos que un mínimo ni mayor que un máximo
.c-titulo { font-size: clamp(40px,10vw,100px); }
<p class="c-titulo">Hola mundo</p>
En el ejemplo el tamaño mínimo de la fuente nunca será menos que 40px por mucho que se haga pequeña la ventana ni será mayor que 100px por mucho que se haga grande la ventana.
Mas información:
Permite hacer cálculos en CSS
.c-titulo { font-size: calc(10vw - 10px); }
.c-titulo { font-size: calc( ( 1 / 3 ) * 100vw); }
.c-titulo { font-size: clamp(40px,10vw - 10px,100px); }
clamp
se pueden hacer cálculos directamente sin necesidad de usar calc
.
Por ejemplo, la siguiente expresión no es correcta:
calc(50%-8px)
debiendose corregir y quedando así:
calc(50% - 8px)
.
Aunque los operadores *
y /
no necesitan espacio en blanco, se sugiere agregarlos por razones de consistencia.
<p class="c-titulo">Hola mundo</p>
La siguiente gráfica muestra como funciona clamp(200px,60vw,400px)
.
Para calcular los tamaños de pantalla donde se producen los cambios (puntos rojos) las variable son las siguientes:
$$
pendiente=60
\\
min=200
\\
max=400
$$
$$
w_{lower} * \frac {pendiente}{100}=min_{value}
\\
w_{lower} = \frac {min_{value}*100}{pendiente}= \frac {200*100}{60}=333px
$$
$$
w_{upper} * \frac {pendiente}{100}=max_{value}
\\
w_{upper} = \frac {max_{value}*100}{pendiente}= \frac {400*100}{60}=667px
$$
De forma genérica podemos establecer los valores de las 4 variables de la siguiente forma:
Siendo los valores de $pendiente$ y $coeficiente_{posición}$ los siguientes:
$$ pendiente=\frac {max_{value} - min_{value}}{w_{upper} - w_{lower}}*100 \\ coeficiente_{posición}=min_{value} - \frac{pendiente}{100}*w_{lower} $$
Veamos el ejemplo en el que queremos que la propiedad font-size
siga estas reglas:
Entonces
$$ pendiente=\frac {max_{value} - min_{value}}{w_{upper} - w_{lower}}=\frac {20-12}{600-230}*100=2,1621622 \\ coeficiente_{posición}=min_{value} - \frac{pendiente}{100}*w_{lower}=12-\frac{2,1621622}{100}*230=7,02702694 $$
Por lo tanto el css será:
.c-titulo { font-size: clamp(12px,2.1621622vw + 7.02702694px,20px); }
import numpy as np import matplotlib.pyplot as plt from matplotlib.ticker import AutoLocator min_value=200 max_value=400 pendiente=60 coeficiente_posición=15 #b def decore_axes(axes,title,xlabel,ylabel): axes.set_title(title, fontsize=14,pad=5,color="#000000") axes.set_xlabel(xlabel, fontsize=10,labelpad=5,color="#003B80") axes.set_ylabel(ylabel, fontsize=12,labelpad=5,color="#003B80") axes.set_xlim(xmin=0) axes.grid(visible=True, which='major', axis='both',color="#FFFFFF",linewidth=1) axes.set_axisbelow(True) axes.yaxis.set_major_locator(AutoLocator()) axes.set_facecolor('#E9F0FC') max_w_size=1200 x=np.linspace(0,max_w_size,3000) y=[] for xi in x: yi=xi*(pendiente/100)+coeficiente_posición if (yi<min_value): yi=min_value elif (yi>max_value): yi=max_value y.append(yi) min_corte_x=((min_value-coeficiente_posición)*100)/pendiente max_corte_x=((max_value-coeficiente_posición)*100)/pendiente figure=plt.figure(figsize=(8,4)) axes = figure.add_subplot(1,1,1) axes.plot(x,y) axes.scatter(min_corte_x,min_value,c="red", zorder=2) axes.scatter(max_corte_x,max_value,c="red", zorder=2) decore_axes(axes,f"clamp({min_value}px,{pendiente}vw + {coeficiente_posición}px,{max_value}px)","Tamaño pantalla","Valor propiedad CSS") _=axes.set_xticks( [0,min_corte_x,max_corte_x,max_w_size])
Hay muchas opciones al respecto de las imágenes responsivas. La técnica consiste principalmente en usar una imagen u otra en función de:
Una explicación completa la puedes ver en el siguiente enlace: Responsive Images.
Aquí solo vamos a ver como carga una imagen u otra en función del ancho del dispositivo.
Veamos un ejemplo: Según la resolución , no queremos cargar siempre la misma imagen sino que cambiamos la perspectiva de la foto ya que tenemos menos sitio.
<picture> <source media="(min-width: 900px)" srcset="https://logongas.es/lib/exe/fetch.php?media=responsive-large.jpg" /> <source media="(min-width: 500px)" srcset="https://logongas.es/lib/exe/fetch.php?media=responsive-medium.jpg" /> <img src="https://logongas.es/lib/exe/fetch.php?media=responsive-small.jpg" /> </picture>
Para hacer tablas responsivas, realmente lo único que podemos hacer es que haya barras de Scroll. Para eso ponemos un div sobre la tabla con la propiedad overflow: auto;
<html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> .c-table { overflow: auto; } .c-table__head { } .c-table__head--min-width-1 { min-width: 100px; } .c-table__head--min-width-2 { min-width: 150px; } .c-table__head--min-width-3 { min-width: 200px; } .c-table__head--max-width-1 { max-width: 100px; } .c-table__head--max-width-2 { max-width: 150px; } .c-table__head--max-width-3 { max-width: 200px; } .c-table__head--width-1 { width: 100px; min-width: 100px; } .c-table__head--width-2 { width: 150px; min-width: 150px; } .c-table__head--width-3 { width: 200px; min-width: 200px; } </style> </head> <body> <h1 >Ejemplo de tablas responsivas</h1> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> <div class="c-table"> <table> <thead> <tr> <th class="c-table__head c-table__head--min-width-2 c-table__head--max-width-3">Author</th> <th class="c-table__head c-table__head--min-width-2 c-table__head--max-width-3 ">Title</th> <th class="c-table__head c-table__head--min-width-1 c-table__head--max-width-2">Year</th> <th class="c-table__head c-table__head--width-3">ISBN-13</th> <th class="c-table__head c-table__head--width-2">ISBN-10</th> </tr> </thead> <tbody> <tr> <td>Miguel De Cervantes</td> <td>The Ingenious Gentleman Don Quixote of La Mancha</td> <td>1605</td> <td>9783125798502</td> <td>3125798507</td> </tr> <tr> <td>Gabrielle-Suzanne Barbot de Villeneuve</td> <td lang="fr">La Belle et la Bête</td> <td>1740</td> <td>9781910880067</td> <td>191088006X</td> </tr> <tr> <td>Sir Isaac Newton</td> <td>The Method of Fluxions and Infinite Series: With Its Application to the Geometry of Curve-lines</td> <td>1763</td> <td>9781330454862</td> <td>1330454863</td> </tr> <tr> <td>Mary Shelley</td> <td>Frankenstein; or, The Modern Prometheus</td> <td>1818</td> <td>9781530278442</td> <td>1530278449</td> </tr> <tr> <td>Herman Melville</td> <td>Moby-Dick; or, The Whale</td> <td>1851</td> <td>9781530697908</td> <td>1530697905</td> </tr> <tr> <td >Emma Dorothy Eliza Nevitte Southworth</td> <td>The Hidden Hand</td> <td>1888</td> <td>9780813512969</td> <td>0813512964</td> </tr> <tr> <td>F. Scott Fitzgerald</td> <td>The Great Gatsby</td> <td>1925</td> <td>9780743273565</td> <td>0743273567</td> </tr> <tr> <td>George Orwell</td> <td>Nineteen Eighty-Four</td> <td>1948</td> <td>9780451524935</td> <td>0451524934</td> </tr> <tr> <td>Nnedi Okorafor</td> <td>Who Fears Death</td> <td>2010</td> <td>9780756406691</td> <td>0756406692</td> </tr> </tbody> </table> </div> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> </body> </html>
Mas información:
Permiten tener un CSS distinto según el tamaño de la pantalla
.c-titulo { font-size: 40px; } @media (min-width: 576px) { .c-titulo { font-size: 50px; } } @media (min-width: 768px) { .c-titulo { font-size: 55px; } } @media (min-width: 992px) { .c-titulo { font-size: 70px; } }
<p class="c-titulo">Hola mundo</p>
Como vemos para cada resolución se usa un CSS distinto y por lo tanto el tamaño es distinto según la resolución.
Pasemos ahora a ver como poder hacer las cosas responsivas con una simple arquitectura.
.g--font-size-1 { font-size: 40px; } .g--font-size-2 { font-size: 50px; } .g--font-size-3 { font-size: 55px; } .g--font-size-4 { font-size: 70px; } @media (min-width: 576px) { .g--font-size-1\@tablet { font-size: 40px; } .g--font-size-2\@tablet { font-size: 50px; } .g--font-size-3\@tablet { font-size: 55px; } .g--font-size-4\@tablet { font-size: 70px; } } @media (min-width: 768px) { .g--font-size-1\@desktop { font-size: 40px; } .g--font-size-2\@desktop { font-size: 50px; } .g--font-size-3\@desktop { font-size: 55px; } .g--font-size-4\@desktop { font-size: 70px; } } @media (min-width: 992px) { .g--font-size-1\@fulldesktop { font-size: 40px; } .g--font-size-2\@fulldesktop { font-size: 50px; } .g--font-size-3\@fulldesktop { font-size: 55px; } .g--font-size-4\@fulldesktop { font-size: 70px; } }
<p class="g--font-size-1 g--font-size-3@fulldesktop">Hola mundo</p>
En el ejemplo por defecto el tamaño de la fuente será de 40px pero en resoluciones mayores de 992px será de 55px.
Lo que hacemos es crear todas los modificadores globales o modificadores de bloques para las distintas resoluciones pero añadiendo el sufijo @tablet
, @desktop
o @fulldesktop
. E indicando en el HTML que tamaño usar según la resolución de la pantalla.
Otro ejemplo de ello lo podemos ver en Notes on using CSS Grid in production
También en Boostrap qu permite clases responsivas: Utility API indicando responsive=true
Al crear la arquitectura responsiva es necesario indicar los pixeles de cada pantalla así como los tamaños. En los siguientes artículos se indica cuales se usan en diversos frameworks css.
Nombre | Descripcion | Ancho Mínimo |
---|---|---|
-- | Extra small devices (portrait phones) | none |
sm | Small devices (landscape phones) | 576px |
md | Medium devices (tablet) | 768px |
lg | Large devices (desktops) | 992px |
xl | Extra large devices (large desktops) | 1200px |
xxl | Extra Extra large devices (extra large desktops) | 1400px |
Nombre | Ancho Mínimo |
---|---|
sm | 640px |
md | 768px |
lg | 1024px |
xl | 1280px |
<div class="main-menu"> <ul class="main-menu__items main-menu__items--movil-hide"> <li class="main-menu__item"><a href="#home">Home</a></li> <li class="main-menu__item"><a href="#news">News</a></li> <li class="main-menu__item"><a href="#contact">Contact</a></li> <li class="main-menu__item"><a href="#about">About</a></li> </ul> <a href="javascript:void(0);" class="main-menu__hamburger" onclick="toggleVisibilityMenu()">☰</a> </div> <h1 style="text-align: center">Mi empresa</h1> <p style="height: 1200px;width: 500px;"></p>
.main-menu { display: flex; flex-direction: row; } @media (max-width: 499px) { .main-menu { position: fixed; top: 0; left: 0; } } .main-menu__hamburger { display: none; } @media (max-width: 499px) { .main-menu__hamburger { display: block; } } .main-menu__items { display: flex; flex-direction: row; } @media (max-width: 499px) { .main-menu__items { flex-direction: column; } } .main-menu__item { padding: 10px; color: #ffffff; background-color: #c0c0c0; } @media (max-width: 499px) { .main-menu__item { padding-left: 2px; background-color: #00ff00; } } @media (max-width: 499px) { .main-menu__items--movil-visible { display: block; } .main-menu__items--movil-hide { display: none; } }
function toggleVisibilityMenu() { var itemsElements = document.getElementsByClassName("main-menu__items"); var hamburgerElements = document.getElementsByClassName("main-menu__hamburger"); if (itemsElements[0].className.indexOf("main-menu__items--movil-visible") >= 0) { itemsElements[0].className = " main-menu__items main-menu__items--movil-hide"; hamburgerElements[0].innerHTML = "☰"; } else { itemsElements[0].className = "main-menu__items main-menu__items--movil-visible"; hamburgerElements[0].innerHTML = "Cerrar"; } }
Hemos visto varias formas de hacer las cosas responsivas. Veamos ahora una tabla en la que se explican las 4 formas posibles:
Interno | Externo | |
---|---|---|
Fluido | El propio componente decide como se hace responsivo y lo hace de forma fluida al tamaño del dispositivo. | El que usa el componente decide como se hace responsivo y lo hace de forma fluida al tamaño del dispositivo. |
Escalonado | El propio componente decide como se hace responsivo y lo hace solo para diversos tamaños de pantalla | El que usa el componente decide como se hace responsivo y lo hace solo para diversos tamaños de pantalla |
.c-titulo { font-size: 10vw }
<h1 class="c-titulo">Hola mundo</h1>
.c-titulo { font-size: 40px; } @media (min-width: 768px) { .c-titulo { font-size: 55px; } }
<h1 class="c-titulo">Hola mundo</h1>
<thead> <tr> <th class="c-table__head c-table__head--min-width-2 c-table__head--max-width-3">Author</th> <th class="c-table__head c-table__head--min-width-2 c-table__head--max-width-3 ">Title</th> <th class="c-table__head c-table__head--min-width-1 c-table__head--max-width-2">Year</th> <th class="c-table__head c-table__head--min-width-1 c-table__head--max-width-2">ISBN-13</th> <th class="c-table__head c-table__head--min-width-1 c-table__head--max-width-2">ISBN-10</th> </tr> </thead>
@tablet
o @desktop
, etc.
<p class="g--font-size-1 g--font-size-3@tablet">Hola mundo</p>
Crea una página HTML con lo siguiente:
Ahora:
Crea una página HTML con lo siguiente:
De forma que:
px
rem
em
Añade ahora el siguiente CSS:
html { font-size:24px; }
Y comprueba que solo se ha modificado el tamaño del cuadrado Verde.
Crea una página HTML con lo siguiente:
Haz una página HTML de forma que se cargue una imagen distinta según el siguiente ancho de la pantalla:
Dado el típico layout de cabecera, menú lateral, cuerpo y pie. Haz una página HTML pero de forma que si el tamaño de la pantalla es menor que 500px no se vea el menú lateral. Deberás hacerlo usando BEM
Crea una clase css llamada .g--color-fondo-responsivo
de forma que cambia el color de fondo si el ancho del dispositivo (o ventana) tiene:
Lo usarán en una página HTML donde estará un cuadrado de 200px x 200px
Crea las siguientes clases css:
.g--bg-color-red { background-color:#FF0000; } .g--bg-color-green { background-color:#00FF00; } .g--bg-color-blue { background-color:#0000FF; } .g--bg-color-orange { background-color:#FFA500; }
Y modificalas con el sufijo "@tabled", "@desktop" y "@fulldesktop" y repite el ejercicio anterior pero en vez de usar la clase .g--color-fondo-responsivo
uses las clases que acabas de crear
Crea modificadores globales para las siguientes propiedades CSS:
width
min-width
max-width
Los posibles valores de cada uno de ellos serán: 100px, 150px , 200px, 250px, 300px, 350px, 400px, 450px, 500px, 550px, 600px
Crea también otro modificador global para overflow: auto;
Crea una clase BEM para tablas HTML de forma que:
Con todo los anterior, haz una página HTML con una tabla en la que:
Modifica el ejercicio anterior de forma que ahora los modificadores globales se puedan usar de forma responsiva con
Modifica el ejemplo de la tabla HTML de forma que las columnas ahora tenga siempre tamaños fijos (es decir no usar min o max), pero que cambien según la resolución de la pantalla.
Usando las clases de BEM y los modificadores globales que has ido usando durante el curso, añade de forma que ahora se puedan usar de forma responsiva con
Modifica la página del tema anterior para hacerla responsiva de forma que según la resolución se cambie el tamaño :