Genera imágenes adaptables con la etiqueta picture

Hace poco compartí una función similar en blogger con la etiqueta img, para aplicarle distintos atributos y propiedades fácilmente. Pero me ví en la necesidad de crear una función similar para la etiqueta picture, con el fin de resolver un tema que me estaba dando dolores de cabeza, optimizar la versión móvil.

Situación

Una de las formas que tenemos para poder crear imágenes responsivas es el atributo srcset, Blogger de hecho posee una función similar llamada `sourceSet, que podemos aplicarla de la siguiente manera:

<img expr:src='data:view.featuredImage'
  expr:srcset='sourceSet(data:view.featuredImage, [300,400])'/>
<img src="/s1600/demo.png" srcset="/300w/demo.png 300w, /400w/demo.png 400w">

Pero esta sintaxis nos impide conocer el servidor que se usa y no podremos agregar parámetros de imagen al atributo srcset generado.

Función en Blogger

Para estos casos he creado una nueva funcion que se construye en torno a la etiqueta picture, se que hay muchas cualidades de esta etiqueta, pero por ahora solo se encarga de servir como un reemplazo al atributo srcset de la etiqueta image.

<b:includable id='@picture'>
  <b:comment><!--
  // @param {image} src - Url de la imagen
  // @param {array} [resizeSet] - Tabla de dimensiones
  // @param {string} [alt=data:messages.image] - Texto alternativo
  // @param {string} [id] - Identificador único
  // @param {string} [class] - Clases adicionales
  // @param {string} [width] - Ancho personalizado
  // @param {string} [height] - Alto personalizado
  // @param {string} [ratio] - Relación de aspecto (4:3, 16:9 etc)
  // @param {string} [loading] - Valor para el atributo loading
  // @param {string} [params] - Parámetros adicionales (zkreations.com/image-params)
  --></b:comment>
  <b:if cond='data:src'>
  <picture>
    <b:with value='data:src.isYoutube
      ? data:src.youtubeMaxResDefaultUrl
      : data:src' var='source'>
    <b:with value='{
        set: resizeImage(data:source, (data:resizeSet ?: [700,400]), data:ratio),
        size: resizeImage(data:source, (data:resizeSet.first ?: 600), data:ratio),
      }' var='images'>
      <b:loop reverse='true' index='i' values='data:images.set' var='image'>
        <b:with value='[
          "content.com/img/a/",
          "content.com/blogger_img_proxy"
        ]' var='servers'> 
        <b:with value='data:params and (data:servers any (server => server in data:image.url))
          ? (data:image.url + "-" + data:params)
          : data:image.url' var='imageUrl'>
          <b:if cond='data:images.set.size != (data:i + 1)'>
            <source expr:media='"(min-width:" + data:image.size + "px)"' expr:srcset='data:imageUrl'/>
          <b:else/>
            <b:tag expr:src='data:imageUrl' expr:alt='data:alt ?: data:messages.image' name='img'>
              <b:attr name='b:whitespace' value='remove'/>
              <b:class cond='data:class' expr:name='data:class'/>
              <b:attr name='width' expr:value='data:width ?: data:images.size.width'/>
              <b:attr name='height' expr:value='data:height ?: data:images.size.height'/>
              <b:attr name='id' expr:value='data:id'/>
              <b:attr name='loading' expr:value='data:loading'/>
            </b:tag>
          </b:if>
        </b:with>
        </b:with>
      </b:loop>
    </b:with>
    </b:with>
  </picture>
  <b:else/>
    <b:comment render='true'>Parameter [src] is required.</b:comment>
  </b:if>
</b:includable>

Explicación

Solo el parámetro src es obligatorio, el resto son opcionales. En cuanto a las comprobaciones se realizan las mismas que puedes encontrar en mi otra función para imagenes.

Lo importante de esta función es que nos permite agregar las mismas propiedades y parametros a todas las imágenes que se generen a partir de la tabla de dimensiones. Esta función también esta presente en mi proyecto Hamlet.

Modo de uso

Solo necesitas agregar la inclusión como un marcado predeterminado "Common" y ya podrás llamar a la función en cualquier parte de tu plantilla. Vamos a repasar los parámetros que puedes usar:

Url de la imagen

La url puede especificarse explícitamente o a través de un dato tipo imagen de Blogger, en ambos casos recomiendo que solo uses imágenes alojadas en los servidores de Google.

<b:include data='{ src: data:view.featuredImage }' name='@picture'/>
<picture>
  <source media="(min-width:700px)" srcset="/w700/demo.png">
  <img alt="Imagen" src="/w400/demo.png" width="700">
</picture>

Tabla de dimensiones

La tabla de dimensiones es un arreglo de números que representan el ancho de las imágenes que se generarán, por defecto es [700,400] si no se especifica.

<b:include data='{
      src: data:view.featuredImage,
      resizeSet: [300,400,500]
    }' name='@picture'/>
<picture>
  <source media="(min-width:500px)" srcset="/w500/demo.png">
  <source media="(min-width:400px)" srcset="/w400/demo.png">
  <img alt="Imagen" src="/w300/demo.png" width="500">
</picture>

Texto alternativo

El texto de respaldo que se mostrará cuando la imagen no se pueda cargar. Por defecto es la etiqueta data:messages.image si no se especifica.

<b:include data='{
    src: data:view.featuredImage,
    alt: "Texto alternativo"
  }' name='@picture'/>

Identificador y clases

Estos valores se agregan a la etiqueta img y no a picture, es importante tener esto en cuenta.

<b:include data='{
    src: data:view.featuredImage,
    id: "test",
    class: "ejemplo"
  }' name='@picture'/>

Relación de aspecto

Este parámetro es opcional pero recomiendo siempre usarlo, ya que nos permite generar imágenes con la misma relación de aspecto y ademas generará el alto y ancho de la imagen de forma automática.

<b:include data='{
    src: data:view.featuredImage,
    ratio: "16:9"
  }' name='@picture'/>

Altura y ancho

También es posible especificar el alto y ancho de la imagen, estos valores tendrán prioridad sobre la relación de aspecto, aunque yo desaconsejo usarlos.

<b:include data='{
    src: data:view.featuredImage,
    width: 300,
    height: 200
  }' name='@picture'/>

Atributo loading

Este atributo nos permite especificar el valor del atributo loading de la etiqueta img, si no se especifica simplemente no se agregará.

<b:include data='{
    src: data:view.featuredImage,
    loading: "lazy"
  }' name='@picture'/>

Parámetros de imagen

Si quieres agregar parámetros de imagen a la imagen, puedes hacerlo a través del parámetro params, este se agregará a todas las imágenes generadas si provienen del servidor compatible.

<b:include data='{
    src: data:view.featuredImage,
    params: "rw-e30"
  }' name='@picture'/>

Conclusión

Esta función es una alternativa al atributo srcset de la etiqueta img. Aunque en un principio me resistí a hacerlo de esta manera, pienso que es una inclusión que vale la pena tener en cuenta y que espero mejorar a futuro.

Si quieres comprender mejor este código, en los adjuntos de este post encontrarás un archivo con el código completo para usarlo. Si este articulo te ha gustado no olvides compartirlo y comentar, te lo agradecería mucho.