Lección 10: Defensivo
El CSS Defensivo son un conjunto de técnicas que evitan romper el diseño cuando no se tiene control sobre el contenido. Es decir, cuando el contenido es generado por el usuario, o por un CMS como puede ser WordPress, cuya longitud desconocemos.
Los problemas más habituales aparecen cuando el contenido es:
- … más largo de lo esperado y la altura es fija. Desbordará por debajo.
- … corto y no ocupar todo el espacio. Dejará un espacio en blanco.
- … de varias líneas pero el diseño solo contempla 1. Desbordará por un lateral o se supondrá con el contenido de la siguiente línea.
- … una imagen y no se conoce su tamaño, debido a que es el usuario es quien la proporciona. Se distorsionará si su aspecto no corresponde con el diseño (el espacio es cuadrado pero la imagen en rectangular).
- … en varias idiomas, con palabras más largas o cortas que lo previsto. Habrá desbordamiento en algunas líneas que tengan contenedores con un ancho fijo.
Vamos a evitar todos los problemas anteriores con un ejemplo práctico donde iremos reparando una tarjeta de presentación con imagen, nombre completo (de una línea), una descripción y algunos botones con texto variable.
Redimensiona para visualizar el diseño terminado que queremos conseguir.
Partiremos con el siguiente HTML usando la nomenclatura BEM en formato de bloques anidados o un componente:
<article class="speaker">
<img aria-hidden="true" class="image speaker__avatar" alt="Avatar" src="">
<h2 class="speaker__fullname">Christina Zamora Mccormick</h2>
<p class="speaker__bio">Egestas dui, id ornare arcu odio ut sem nulla pharetra! Sit amet cursus sit amet, dictum sit amet justo donec enim diam, vulputate ut pharetra sit amet, aliquam id diam!</p>
<nav class="nav">
<ul class="nav__list speaker__nav">
<li class="nav__item">
<a href="#" class="button">Website</a>
</li>
<li class="nav__item">
<a aria-label="Twitter" href="#" class="button">🐦</a>
</li>
<li class="nav__item">
<a aria-label="Mastodon" href="#" class="button">🐘</a>
</li>
</ul>
</nav>
</article>
Empezaremos a partir del momento que ya hemos definido su Grid tanto en dispositivos con pantalla pequeña como en grandes.
Técnicas
1. Evitar distorsión de imágenes
Cuando el usuario sube una imagen, no se conoce su tamaño. Si no coincide las proporciones con el contenedor, la imagen se distorsionará inevitablemente.
En el ejemplo la imagen es rectangular.
Pero debe ocupar un espacio cuadrado, que posteriormente redondearemos.
Queda aplastado por los laterales.
Para evitarlo, siempre que diseñes un componente adaptable debes aplicar los siguientes estilos a todas la imágenes (si puede ser de forma global):
img {
width: 100%;
object-fit: cover;
object-position: center;
}
width: 100%
para que la imagen ocupe todo el ancho del contenedor.object-fit: cover
para que la imagen se ajuste al contenedor sin deformarse, recortando el contenido que sobresalga.object-position: center
para que la imagen se centre en el contenedor.
2. Romper palabras largas
Cuando trabajamos con textos en varios idiomas, es posible que algunas palabras sean más largas de lo esperado. Por ejemplo, en inglés la palabra antidisestablishmentarianism tiene 28 caracteres y existe. Si el diseño no contempla palabras tan largas, el texto desbordará de su contenedor.
Aplicaremos las propiedades overflow-wrap
y min-width
siempre que esperemos una situación similar.
.speaker__fullname {
overflow-wrap: break-word;
min-width: 0;
}
3. Prevenir la rotura de una línea
Por razones de diseño, en ciertos momentos un texto no podrá ocupar más de una línea. Por ejemplo, en el nombre completo de la tarjeta. Si el nombre es muy largo, se romperá en dos líneas y el diseño quedará feo y roto.
Reduce la anchura para ver el efecto.
Una solución elegante es ocultar todo el texto que desborde y añadir unos puntos suspensivos al final. Para ello usaremos las propiedades white-space
, overflow
y text-overflow
.
.speaker__fullname {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
white-space: nowrap
evita que el texto se rompa en varias líneas.overflow: hidden
oculta el texto que desborda.text-overflow: ellipsis
añade unos puntos suspensivos al final del texto.
4. Incluir espacios de seguridad
Para evitar que el contenido termine a sangre con los límites del componente podemos incluir un espacio de seguridad. Es decir, un margen interno que separe el contenido del borde. En caso contrario no se verá bien.
Cuando trabajamos con Flex o Grid, incluye siempre gap
para que el texto no acabe a sangre con otros elementos. Y si es necesario, añade un padding
para dar más aire al contenido respecto al borde del componente.
.speaker {
gap: 1rem
padding: 1rem;
}
5. Anchura mínima de un elemento cuando el contenido es más corto
Nuestros botones apenas tienen contenido y se ven muy pequeños, reduciendo la zona pulsable además de estropear el diseño.
Podemos solucionarlo con una anchura mínima.
.button {
min-width: 4rem;
}
Adicionalmente hará más visible el botón, mejorando en accesibilidad.
6. Fijar la anchura máxima de un componente
Cuando un componente ha sido diseñado teniendo en mente una anchura determinada pero necesitas que sea adaptable, tenemos un problema. Si el contenedor es más ancho de lo esperado, acabaremos con un diseño desproporcionado.
Aplicaremos una anchura máxima. De esta forma, no podrá crecer más de lo esperado pero sí reducirse.
.speaker {
max-width: 40rem;
}
7. Envoltura flexible contra la falta de espacio en Flex
Cuando utilices Flex, es posible que el espacio disponible no sea suficiente y los elementos desborden. Para evitarlo, utiliza la propiedad flex-wrap
con el valor wrap
.
.elemento {
display: flex;
flex-wrap: wrap;
}
A continuación NO se ha aplicado flex-wrap: wrap
y los botones desbordan cuando reducen la anchura.
Ahora SI se ha aplicado flex-wrap: wrap
y los botones saltan a otra linea.
8. Desactivar hover accidental en dispositivos táctiles
Un problema común en los dispositivos táctiles es que el usuario cuando realiza scroll y coloca su dedo sobre un elemento que se ha diseñado con un hover, se activa accidentalmente. Esto puede ser molesto para el usuario ya que deja el hover activo hasta que pulsa en otro lugar de la pantalla.
Podemos evitar este comportamiento con la siguiente regla:
@media (hover: hover) {
.button:hover {
background-color: red;
}
}
Solo aplicará el hover (en el ejemplo, un fondo rojo) cuando el dispositivo tenga un puntero como un ratón o un trackpad, nunca en un dispositivo táctil.
Con SASS podemos crear un mixin para evitar repetir la regla y simplificar su utilización:
/*
* Create a hover that prevents the hover from appearing when you scroll in mobile
*
* Examples: @include hover()
*/
@mixin hover()
@media (hover: hover)
&:hover
@content
.button
@include hover()
background-color: red
En lugar de &:hover
podemos usar @include hover()
.
Prueba a realizar scroll en la siguiente demo. Con un dispositivo táctil no se activa el color negro de fondo, pero en cambio si posas el cursor del ratón sí que ocurrirá.
A continuación se ha aplicado la estrategia con los botones.
Apuntes finales
Hemos aprendido a crear un diseño defensivo con las soluciones más comunes frente a un contenido dinámico. La tarjeta que hemos creado esta plagado de pequeños detalles y ajustes que hacen que el diseño más fiable. Según adquieras experiencia irás incorporando cada estrategia de manera natural a los diseños que realices. Ponte siempre en lo peor, desde poco a mucho texto. Al igual que preparas tus diseños para diferentes tamaños de pantalla, prepara tus diseños para diferentes tamaños de contenido.
Esta obra está bajo una Licencia Creative Commons Atribución-NoComercial-SinDerivadas 4.0 Internacional.
¿Me invitas a un café? ☕
Puedes hacerlo usando el terminal.
ssh customer@andros.dev -p 5555
Comentarios
Nuevo comentario
Nueva replica {{ formatEllipsisAuthor(replyComment.author) }}
Escribe el primer comentario
{{ comments.length }} comentarios