Imágenes responsivas y sostenibles en markdown

Markdown es una fantástica herramienta para la creación y gestión de contenido en la web, no obstante no permite crear ciertos atributos HTML avanzados como srcset de forma simple. En esta guía introducimos conceptualmente que son imágenes responsivas y sostenibles en la web junto con una posible solución basada en la librería Haskell MMark.
- Introducción
- Un breve paréntesis de propiedades de una imagen web
- Imágenes responsivas y sostenibles
- Cómo usar srcset, sizes y lazy en Markdown?
- Conclusión
- Notas
- Referencias
Introducción
Uno de los objetivos primordiales del lenguaje de marcado Markdown es de ser simple de leer y escribir e idealmente separar la capa de contenido de la capa de publicación. No obstante, dependiendo del caso de uso, algunos autores prefieren un poco más de control sobre la publicación, tales como definir ciertos atributos de un elemento.
Definir ciertos atributos en imágenes es un ejemplo típico, especialmente si se quieren responsivas y sostenibles.
La forma canónica de crear imágenes en markdown es la sintaxis:
MARKDOWN

lo cual se transforma al equivalente HTML de:
HTML
<img alt="soyunalt" src="archivo.png">
Algo tan simple como definir el tamaño de una imagen no es posible en la sintaxis. No obstante, Markdown permite la creación de HTML directamente y basta escribir:
MARKDOWN
Párrafo bla bla que incluye una imagen
<img alt="soyunalt" src="archivo.png" width=300 height=300>
Otro texto
Sin embargo, qué ocurre cuando se usa librerías Markdown estrictas, que no permiten escribir HTML directo en el archivo, o simplemente se prefiere no agregar HTML sino que usar sintaxis Markdown nativa?
Una solución es usar una variante Markdown que permita dicha sintaxis. El problema de ello es que se pierde estandarización1, o puede ser una opción no viable (quien toma la decisión no es quien edita los archivos).
Otra solución más simple, que no implica cambiar de variante de Markdown ni tampoco escribir HTML en el archivo markdown, es usar CSS. Se puede definir una regla global como:
CSS
img {width:200px; height:200px;}
que afecta a todas las imágenes y aplica dicha regla o bien se puede definir una regla para casos específicos identificando el elemento en cuestión vía selectores CSS, por ejemplo
CSS
p:nth-of-type(3) > img {width:200px; height:200px;}
Cabe señalar que también se puede definir una regla css tipo
CSS
img {width:100%; height:auto;}
que resuelve el problema de responsividad para uno de los casos de uso más comunes que es el caso dónde se quiere que la imagen se pueda achicar pero que nunca pase el tamaño original del archivo.
Si bien esa solución es práctica, basta una línea de código y todas las imágenes son responsivas en caso de verlas desde el celular, no es sostenible porque no es eficiente. Si el archivo original es 1200 x 600 pixels pesando 1MB, al visitar dicha página desde un dispositivo móvil con resolución de ancho digamos 600px, entonces el archivo se mostrará a lo más de 600 x 300 pixels no obstante igualmente serán transferidos 1MB.
Un breve paréntesis de propiedades de una imagen web
Es importante notar que diferentes industrias tienen diferentes términos y nomenclaturas. Imprentas, fotógrafos (y productores de cámaras), productores de hardware y diseñadores web pueden usar la misma palabra tamaño o resolución para referise a diferentes atributos o aspectos de una imagen en diferentes medios y contextos (impreso, en la cámara, en un computador, en una pantalla).
Los términos usados en este artículo son para el contexto web, que puede diferir al contexto impreso
-
pixel: Es el elemento del menor tamaño posible en una imagen ráster que puede ser manipulado por software. O dicho de otro modo es una muestra de una imagen en dónde mientras más muestras más precisa es la representación. Un pixel no tiene tamaño intrínsico, pero cuando es impreso o visualizado entonces un pixel tiene una tamaño físico (dimensión) y una densidad (ppi).
-
dimensiones de una imagen: Es el alto por ancho en pixeles. Ejemplo una imagen de 200 x 200 pixels.
-
densidad de pixel ppi o ppp: Es una medida de calidad de la imagen, la cual se nota al momento de visualizarla en algún medio (impreso, pantalla, etc). Es uma medida de densidad de pixeles medida como “pixeles por pulgada” ppp (ppi en inglés “pixels per inch”) en dónde el término pulgada hace referencia al tamaño real (”vida real, no digital”) de la pantalla o medio. Es decir dos imágenes de las mismas dimensiones en pixeles, ejemplo 300 x 300, pueden tener diferentes ppi, una 150 ppi y otra de 75 ppi, lo que significa que si bien ambas se veran de la misma dimensión en la pantalla, una tendra la mitad de pixeles haciendo que pueda verse “pixeleada” más rápido al hacer zoom.
-
imagen ráster o de mapa de bits: Imagen que es posible de representar digitalmente usando pixels. En adelante al referirnos a una imagen sin indicar su tipo, nos referiremos a las imágenes de este tipo. Esto incluye los formatos de imágenes típicos en la web tales como .jpg , .png, .jpeg, .gif, .webp, .avif, etc. Cabe señalar que imágenes de formato .svg o llamadas imágenes vectoriales, no son imágenes ráster pudiendo cambiar sus dimensiones sin perder calidad. Notar que el proceso de transformar una imagen a svg se llama vectorización y que lo contrario (por ejemplo de svg a png) se llama rastarización.
-
resolución de pantalla: Nos referimos a cuantos pixeles de ancho y alto soporta un dispositivo o monitor. Por ejemplo, una monitor de resolución de 1920 x 1080 pixels o uno llamado 4K de 3840×2160. También la llamaremos de tamaño o dimensiones de la pantalla.
-
tamaño del archivo de una imagen: Usaremos mayor frecuentemente el término “peso” (no confundir con la moneda) como indicador de cuantos bytes posee una imagen. Kilobytes (KB), megabytes (MB), etc. Ejemplo imagen que pesa 250KB.
-
compresión de imagen: Métodos de reducir el costo de almacenamiento y transporte de una imagen digital. Puede ser “lossy” (compresión con pérdida) o “lossless” (compresión sin pérdida), en dónde pérdida se refiere a diferencias con el archivo original antes y despúes de la compresión. Para cierto tipo de archivos, las pérdidas son aceptables (ejemplo dos pixeles juntos que tienen una variante de color mínima puede definirse del mismo color) lo que dependiendo del número de pixeles es imperceptible por el ojo humano. JPEG es ejemplo de algoritmo “lossy” y PNG es ejemplo de algoritmo “lossless”. WEBP y AVIF son ejemplos que pueden utilizar ambos algoritmos.
Imágenes responsivas y sostenibles
Por sostenibles nos referimos a que sean eficientes en su compresión y transferencia, sin necesitar transferir más bytes de los necesarios para cada consumo hecho por diferentes dispositivos. Esto implica usar formatos de compresión más eficientes como .avif y .webp por un lado, y por el otro optimizar los request hechos del navegador solicitando archivos menores cuando haga sentido, junto con uso de cache.
Por responsivas, a que se vean apropiadamente de acuerdo a la resolución y densidad de pixeles del dispositivo desde el cual se visualizan.
CSS tiene grandes propiedades de responsividad siendo bien interesante la propiedad image-set()
1 que le permite al navegador escoger la images CSS apropiada desde un set definido, especialmente útil para casos de dispositivos móviles con alta densidad de pixels.
No obstante, imágenes CSS no tienen descripción ALT perdiendo SEO y además definir los archivos de las imágenes en el CSS lo consideramos como algo para eventos particulares de diseño estético (ejemplo una imagen de background en cierta página) y como excepciones más que la norma. De hecho si usas markdown, lo natural es definir las imágenes como parte y dentro del contenido.
Por lo mismo nos interesa atributos responsivos en imágenes HTML. En dónde básicamente se traduce a la utilización del elemento HTML <picture>
y/o bien al uso del atributo srcset
en el elemento HTML <img>
o <picture>
junto con el atributo loading
del elemento <img>
El elemento HTML <picture>
sirve para hacer cambio de “dirección de arte” que no es otra cosa que usar imágenes modificadas o recortadas según diferentes tamaños de pantalla. Un ejemplo típico es el caso de una imagen tipo “wide” o “landscape” en un header de una página a todo ancho, en dónde aparece un gato en el medio. Usuarios que ven la imagen desde el pc no tendran problemas, pero desde el celular es posible que no se vea el gato. El elemento <picture>
resuelve el problema entregando diferentes versiones de la imagen para diferentes tamaños de pantallas. A su vez, permite ahorrar ancho de banda y mejorar carga de la página al cargar la imagen más apropiada según tamaño de la pantalla. Cabe señalar que el elemento <picture>
le permite al programador definir exactamente lo que desea y el navegador debe cumplir dicha regla, a diferencia del atributo srcset
que entrega “hints” al navegador en dónde es el nagevador quien decide que archivo mostrar.
Un aspecto interesante desde el punto de vista de sostenibilidad web es dejar que el navegador tome ciertas decisiones de optimización pues tiene mayor información del usuario tales como ancho de banda, tipo de conexión, etc pudiendo adaptarse de manera efectiva con menor código explícito.
El atributo srcset
le permite al navegador tener opciones de archivos diferentes para una imagen dependiendo de variables tales como el tamaño de pantalla, bando de ancho de la conexión, capacidad de densidad de pixeles del dispositivo entre otras. A su vez, le permite al desarrollador influenciar dicha decisión usando “media querys” de css que establece reglas de acuerdo al tamaño de la pantalla, vía el uso de otro atributo del elemento <img>
llamado sizes
.
Debido a ambas razones, nos enfocaremos al uso del atributo srcset
junto con sizes
en el elemento HTML <img>
como forma simple de lograr imágenes responsivas y sostenibles en la web.
Ejemplo de una imagen en HTML usando srcset y sizes:
HTML
<img src="archivo.jpg" width="400" height="400" srcset="archivo_400.avif 400w, archivo_800.avif 800w, archivo_1000.avif 1000w" sizes="(max-width:600px) 90vw, (max-width:1200px) 45vw, 1000px">
En este ejemplo le estamos entregando la siguiente información al navegador: tienes 3 archivos para escoger, donde sus anchos son 400px, 800px y 1000px respectivamente. Cuando la pantalla sea menor a 600px, la imagen se muestra al 100% del ancho del dispositivo, cuando el ancho de pantalla es entre 600px y 1200px la imagen se muestra al 45% del ancho del dispositivo (por ejemplo en un layout de 2 columnas), y por último cuando el ancho de la pantalla es mayor a 1200px, la imagen se muestra de un ancho de 1000px. Veamos cada tributo por parte.
srcset
define una lista separada por comas, pudiendo especificar archivos según su densidad de pixeles denotado por una letra x, o según su ancho intrínsico denotado por letra w. Usar el srcset con densidad de pixeles es útil especialmente en caso de uso de dispositivos tipo retina. Por otro lado, al usar el ancho en vez de la densidad, permite usar el atributo sizes
entregando mayor información al navegador quien podrá tomar decisiones inteligentes. En la práctica este atributo es automatizable, definiendo un set de tamaños de imágenes por cada imagen según alguna regla de negocio. Por ejemplo tener tamaños small, medium, large.
sizes
acepta opcionalmente media querys de css que orienta (pero no obliga) al navegador cuando se cumple dicho tamaño de la pantalla del dispositivo e indica el ancho que la imagen debería ocupar en la pantalla en cuestión. También es una lista separada por comas. Con dicha información el navegador puede tomar decisiones más precisas y eficientes. Cabe señalar que este atributo es complejo y depende de cómo es visualizada la imagen en el dispositivo cosa que sólo se sabe a ciencia cierta despúes de que se renderiza. Por ejemplo, si la imagen se muestra en 2 columnas en dispositivos hasta 800px, entonces el valor de sizes
podría ser (max-width:800px) 50vw
. No obstante, si existen márgenes o padding laterales probablemente el valor sea otro (menos a 50vw). Además, se esta agregando css en html (anti-patrón al no separar capa de estructura y estilo) no obstante es la manera de entregar información útil al navagador antes de cargar archivos css y js.
Definir el atributo sizes
es complejo con una proporción de uso no menor incorrecta según algunas estadísticas web hechas por Web Almanac (lectura recomendada) Estadísticas de uso de imágenes y atributos en la web existiendo algunas utilidades para determinar correctamente los valores. No obstante, nuestra recomendación es simplificar el layout de las páginas y establecer reglas que hagan sentido para la mayoría de los casos en cada página. Por ejemplo el blog del sitio web.dev usa la regla (max-width: 840px) 100vw, 856px
la cual dice que toda imagen en pantallas menores a 840px se muestran a todo ancho del dispositivo, y que cuando el ancho de pantalla es mayor a 840px, la imagen se muestra de ancho 856px.
Finalmente mencionar que el atributo loading
del elemento <img>
con valor “lazy” es un excelente aliado para imágenes sostenibles pero que debe usarse dependiendo de la visibilidad inicial de la imagen.
-
Si la imagen está por sobre la pantalla inicial de vista (es decir lo que se ve antes de hacer scroll), usar
loading="lazy"
es un anti-patrón haciendo que la carga sea más lenta, y por lo mismo no debe agregarse dicho atributo para dichas imagenes. Dependiendo del caso de uso se puede agregar el atributofetchpriority="high"
indicando que se desea cargar dicho activo con cierta prioridad (como en el caso de que sea el elemento de mayor tamaño en la carga inicial). -
Si la imagen está por debajo (”below the fold”), es decir para verlas el usuario debe hacer scroll, entonces se recomienda agregar el atributo
loading="lazy"
que le indica al navegador no cargar las imágenes hasta que sea necesario, que se traduce en suficientemente próximas al “viewport” (vista visible del navegador) según la implementación de cada navegador. En otras palabras, dejar que el navegador tome decisiones según contexto para evitar cargar una imagen innecesariamente.
Usar
srcset
ysizes
en conjunto conlazy
yfetchpriority
según corresponda, es una manera eficaz de lograr imágenes responsivas y sostenibles.
Cómo usar srcset, sizes y lazy en Markdown?
Markdown permite dentro de su especificación usar HTML por lo que basta escribir HTML directo con los atributos mencionados para obtener imágenes sostenibles y responsivas.
No obstante, se pueden tener las siguientes razones por las que se prefiere usar otra alternativa a HTML directo en Markdown:
- Se prefiere una sintaxis más simple (idea original de Markdown, que sea fácil de escribir)
- Se desea separar lo máximo posible la capa de contenido de la capa de publicación (idea original de Markdown, que sea fácil de leer)
- El sistema o librería markdown usado no permite agregar HTML
- Aumentar el nivel de seguridad (se elimina o reduce un vector de ataques) al limitar la sintaxis
Existe una considerable cantidad de variantes de Markdown y librerías en diferentes lenguajes de programación por lo que la solución muchas veces implica el seleccionar una variante que tenga dicha sintaxis como opción configurable. No obstante al usar una sintaxis diferente se puede obtener un markdown que produce errores en la transformación o visualización de dicho Markdown en otras librerías o sistemas.
En Injeniero consideramos que usar CommonMark 2 tiene un potencial mayor de sostenibilidad al intentar ser un esfuerzo de estándar que permite elaborar librerías que definen de forma precisa errores de sintaxis y que administra y regula la sintaxis3. Cabe señalar que al ser estándar su discusión es lenta y no trivial 4. Entonces cómo lograr imágenes responsivas y sostenibles en Markdown sin usar HTML directo y usando librerías compatibles con CommonMark?
Una posible solución es usando una librería que permita crear extensiones. En particular mostraremos un ejemplo de cómo usando la librería estricta de Markdown, MMmark5 en el lenguaje Haskell que usa especificación de CommonMark:
Cómo crear imágenes responsivas y sostenibles en Markdown usando librería Haskell MMark
Conclusión
Las imágenes son el plato fuerte a optimizar para la web sostenible. Atributos HTML del elemento <img>
tales como srcset
, sizes
, fetchpriority
y loading
permiten de forma práctica obtener imágenes responsivas y sostenibles en dónde presentamos una solución posible de implementación usando Markdown como parte del proceso de publicación de contenido.
En Injeniero es nuestro core crear sitios y sistemas web sostenibles usando imágenes responsivas y sostenibles por defecto, con proceso de creación de contenido que usa CommonMark
Notas
- La falta de definición de la sintaxis de forma inequívoca y la falta de “error de sintaxis” motivó la creación de CommonMark, como candidato de estándar de la especificación del lenguaje Markdown. ↩
Referencias
-
^ Propiedad css
image-set()
Mozilla Foundation image-set - ^ CommonMark commonmark.org
- ^ Especificación CommonMark commonmark spec
- ^ Ejemplo discusión foro CommonMark definición de sintaxis de elemento audio y video embedded audio and video
- ^ Librería Haskell MMark, Autor Mark Karpov Announcing MMark