Создание адаптивных изображений в Astro 3

Для чего нужны адаптивные изображения

Если сайт просматривается на мобильном устройстве и изображения на странице высокого разрешения, а, следовательно, и большого размера, то они будут выглядеть хорошо, но загрузка сайта через мобильную сеть может быть очень медленной. С другой стороны, если на сайте будут размещены изображения низкого разрешения и небольшого размера, то на мобильных устройствах они будут загружаться быстро, но на мониторах с высоким разрешением эти изображения будут выглядеть размыто.

Адаптивные изображения - это набор методов, используемых для загрузки изображений подходящего размера, в зависимости от разрешения устройства, ориентации, размера экрана, сетевого подключения и макета страницы. Браузер не должен растягивать изображение, чтобы оно соответствовало макету страницы, а загрузка изображения не должна приводить к потере времени и трафика. Это улучшает взаимодействие с посетителями сайта, поскольку изображения загружаются быстро и выглядят чёткими на любом устройстве.

Адаптивные изображения в Astro

В Astro до версии 3 можно было подключить официальный плагин @astrojs/image, который позволял создавать адаптивные изображения «из коробки». Но, начиная с версии Astro 3, этот плагин считается устаревшим, а интеграция с ним невозможна.

Компоненты и функции для работы с изображениями теперь включены непосредственно в ядро Astro astro:assets, но создание адаптивных изображений пока не поддерживается, во всяком случае, на момент написания этой статьи.

Обновлено: Начиная с версии Astro 3.3 поддержка адаптивных изображений была включена в astro:assets, поэтому это решение можно считать неактуальным.

Решение

Создаём собственный компонент <Image /> с поддержкой адаптивных изображений:

// src/components/Image.astro
---
import { getImage } from "astro:assets";

const {
  src,
  widths = [400, 600, 800, 1000, 1200],
  loading = "lazy",
  decoding = "async",
  ...attrs
} = Astro.props;

const jpeg = await getImage({
  src: src,
  width: widths[widths.length - 1],
  format: "jpeg"
});

const webps = await Promise.all(
  widths.map((width) => getImage({ src: src, width: width })),
);

let srcset = "";
webps.forEach((webp) => {
  if (srcset) srcset += ", ";
  srcset += webp.src + " " + webp.attributes.width + "w";
});
attrs.srcset = srcset;
---

<img
  src={jpeg.src}
  width={jpeg.attributes.width}
  height={jpeg.attributes.height}
  loading={loading}
  decoding={decoding}
  {...attrs}
/>

Теперь этот компонент можно использовать для создания адаптивного изображения в любом шаблоне Astro:

// src/pages/page.astro
---
import Image from "../components/Image.astro";
---

<Image
  src={import("../assets/image.jpg")}
  sizes="(min-width: 1024px) 20vw, (min-width: 640px) 30vw, 60vw"
  class="..."
  alt="..."
/>

В результате мы получим примерно такой HTML-код адаптивного изображения:

<img
  src="/_astro/image.6455ce16_ZyNNt9.jpeg"
  width="1200"
  height="813"
  loading="lazy"
  decoding="async"
  sizes="(min-width: 1024px) 20vw, (min-width: 640px) 30vw, 60vw"
  class="..."
  alt="..."
  srcset="
    /_astro/image.6455ce16_Z1iQXLj.webp  400w,
    /_astro/image.6455ce16_Vta57.webp    600w,
    /_astro/image.6455ce16_1jXpBw.webp   800w,
    /_astro/image.7566di27_Y02kzN.webp  1000w,
    /_astro/image.6455ce16_Z91ryH.webp  1200w
  "
/>

При необходимости, можно указать любые дополнительные атрибуты изображения. Например, если изображение расположено в верхней части страницы, то его загрузку необходимо выполнить без задержек:

<Image
  src={import("../assets/image.jpg")}
  sizes="(min-width: 1024px) 20vw, (min-width: 640px) 30vw, 60vw"
  class="..."
  alt="..."
  loading="eager"
/>
AG & Dev © 2020 Moscow