fix(assets): Don't include asked width in srcset request
This commit is contained in:
parent
fc86fdf0c3
commit
bfe8e09ba6
4 changed files with 24 additions and 18 deletions
|
@ -6,7 +6,9 @@ Add support for generating multiple widths when using the Image component and a
|
||||||
|
|
||||||
## `srcset` support
|
## `srcset` support
|
||||||
|
|
||||||
The current usage is as follow:
|
Two new properties have been added to `Image` and `getImage`: `densities` and `widths`.
|
||||||
|
|
||||||
|
These props can be used to generate a `srcset` attribute with multiple sources. For example:
|
||||||
|
|
||||||
```astro
|
```astro
|
||||||
---
|
---
|
||||||
|
@ -14,17 +16,13 @@ import { Image } from "astro";
|
||||||
import myImage from "./my-image.jpg";
|
import myImage from "./my-image.jpg";
|
||||||
---
|
---
|
||||||
|
|
||||||
<Image src={myImage} densities={[2, 3]} alt="My cool image" />
|
<Image src={myImage} width={myImage.width / 2} densities={[2]} alt="My cool image" />
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively to `densities`, `widths` can be used for specific widths. In both cases, according images and the following code will be generated:
|
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<img src="..." srcset="... 2x, ... 3x" alt="My cool image" />
|
<img src="..." srcset="... 2x, ... 3x" alt="My cool image" />
|
||||||
```
|
```
|
||||||
|
|
||||||
(if `widths` is used the descriptor will be `w` instead of `x`)
|
|
||||||
|
|
||||||
## Picture component
|
## Picture component
|
||||||
|
|
||||||
The `Picture` component can be used to generate a `<picture>` element with multiple sources. It can be used as follow:
|
The `Picture` component can be used to generate a `<picture>` element with multiple sources. It can be used as follow:
|
||||||
|
@ -35,7 +33,7 @@ import { Picture } from "astro:assets";
|
||||||
import myImage from "./my-image.jpg";
|
import myImage from "./my-image.jpg";
|
||||||
---
|
---
|
||||||
|
|
||||||
<Picture src={myImage} formats=["avif", "webp"] alt="My super image in multiple formats!" />
|
<Picture src={myImage} formats={["avif", "webp"]} alt="My super image in multiple formats!" />
|
||||||
```
|
```
|
||||||
|
|
||||||
The above code will generate the following:
|
The above code will generate the following:
|
||||||
|
@ -48,4 +46,4 @@ The above code will generate the following:
|
||||||
</picture>
|
</picture>
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Picture` component takes all the same props as the `Image` component, including `densities` and `widths`.
|
The `Picture` component takes all the same props as the `Image` component, including the new `densities` and `widths` properties.
|
||||||
|
|
|
@ -45,7 +45,10 @@ interface SharedServiceProps<T extends Record<string, any> = Record<string, any>
|
||||||
*/
|
*/
|
||||||
getURL: (options: ImageTransform, imageConfig: ImageConfig<T>) => string | Promise<string>;
|
getURL: (options: ImageTransform, imageConfig: ImageConfig<T>) => string | Promise<string>;
|
||||||
/**
|
/**
|
||||||
* TODO: Document
|
* Generate additional `srcset` values for the image.
|
||||||
|
*
|
||||||
|
* While in most cases this is exclusively used for `srcset`, it can also be used in a more generic way to generate
|
||||||
|
* multiple variants of the same image. For instance, you can use this to generate multiple aspect ratios or multiple formats.
|
||||||
*/
|
*/
|
||||||
getSrcSet?: (
|
getSrcSet?: (
|
||||||
options: ImageTransform,
|
options: ImageTransform,
|
||||||
|
@ -226,8 +229,9 @@ export const baseService: Omit<LocalImageService, 'transform'> = {
|
||||||
|
|
||||||
const aspectRatio = targetWidth / targetHeight;
|
const aspectRatio = targetWidth / targetHeight;
|
||||||
const imageWidth = isESMImportedImage(options.src) ? options.src.width : options.width;
|
const imageWidth = isESMImportedImage(options.src) ? options.src.width : options.width;
|
||||||
const maxWidth = options.width ?? imageWidth ?? Infinity;
|
const maxWidth = imageWidth ?? Infinity;
|
||||||
|
|
||||||
|
// REFACTOR: Could we merge these two blocks?
|
||||||
if (densities) {
|
if (densities) {
|
||||||
const densityValues = densities.map((density) => {
|
const densityValues = densities.map((density) => {
|
||||||
if (typeof density === 'number') {
|
if (typeof density === 'number') {
|
||||||
|
@ -244,9 +248,12 @@ export const baseService: Omit<LocalImageService, 'transform'> = {
|
||||||
densityWidths.forEach((width, index) => {
|
densityWidths.forEach((width, index) => {
|
||||||
const maxTargetWidth = Math.min(width, maxWidth);
|
const maxTargetWidth = Math.min(width, maxWidth);
|
||||||
|
|
||||||
|
// If the user passed dimensions, we don't want to add it to the srcset
|
||||||
|
const { width: transformWidth, height: transformHeight, ...rest } = options;
|
||||||
|
|
||||||
const srcSetValue = {
|
const srcSetValue = {
|
||||||
transform: {
|
transform: {
|
||||||
...options,
|
...rest,
|
||||||
},
|
},
|
||||||
descriptor: `${densityValues[index]}x`,
|
descriptor: `${densityValues[index]}x`,
|
||||||
attributes: {
|
attributes: {
|
||||||
|
@ -254,7 +261,7 @@ export const baseService: Omit<LocalImageService, 'transform'> = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only set width and height if they are different from the original image
|
// Only set width and height if they are different from the original image, to avoid duplicated final images
|
||||||
if (maxTargetWidth !== imageWidth) {
|
if (maxTargetWidth !== imageWidth) {
|
||||||
srcSetValue.transform.width = maxTargetWidth;
|
srcSetValue.transform.width = maxTargetWidth;
|
||||||
srcSetValue.transform.height = Math.round(maxTargetWidth / aspectRatio);
|
srcSetValue.transform.height = Math.round(maxTargetWidth / aspectRatio);
|
||||||
|
@ -270,9 +277,11 @@ export const baseService: Omit<LocalImageService, 'transform'> = {
|
||||||
widths.forEach((width) => {
|
widths.forEach((width) => {
|
||||||
const maxTargetWidth = Math.min(width, maxWidth);
|
const maxTargetWidth = Math.min(width, maxWidth);
|
||||||
|
|
||||||
|
const { width: transformWidth, height: transformHeight, ...rest } = options;
|
||||||
|
|
||||||
const srcSetValue = {
|
const srcSetValue = {
|
||||||
transform: {
|
transform: {
|
||||||
...options,
|
...rest,
|
||||||
},
|
},
|
||||||
descriptor: `${width}w`,
|
descriptor: `${width}w`,
|
||||||
attributes: {
|
attributes: {
|
||||||
|
@ -280,7 +289,6 @@ export const baseService: Omit<LocalImageService, 'transform'> = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only set width and height if they are different from the original image
|
|
||||||
if (maxTargetWidth !== imageWidth) {
|
if (maxTargetWidth !== imageWidth) {
|
||||||
srcSetValue.transform.width = maxTargetWidth;
|
srcSetValue.transform.width = maxTargetWidth;
|
||||||
srcSetValue.transform.height = Math.round(maxTargetWidth / aspectRatio);
|
srcSetValue.transform.height = Math.round(maxTargetWidth / aspectRatio);
|
||||||
|
|
|
@ -50,9 +50,9 @@ const sharpService: LocalImageService = {
|
||||||
|
|
||||||
// Never resize using both width and height at the same time, prioritizing width.
|
// Never resize using both width and height at the same time, prioritizing width.
|
||||||
if (transform.height && !transform.width) {
|
if (transform.height && !transform.width) {
|
||||||
result.resize({ height: transform.height });
|
result.resize({ height: Math.round(transform.height) });
|
||||||
} else if (transform.width) {
|
} else if (transform.width) {
|
||||||
result.resize({ width: transform.width });
|
result.resize({ width: Math.round(transform.width) });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transform.format) {
|
if (transform.format) {
|
||||||
|
|
|
@ -77,12 +77,12 @@ const service: LocalImageService = {
|
||||||
if (transform.height && !transform.width) {
|
if (transform.height && !transform.width) {
|
||||||
operations.push({
|
operations.push({
|
||||||
type: 'resize',
|
type: 'resize',
|
||||||
height: transform.height,
|
height: Math.round(transform.height),
|
||||||
});
|
});
|
||||||
} else if (transform.width) {
|
} else if (transform.width) {
|
||||||
operations.push({
|
operations.push({
|
||||||
type: 'resize',
|
type: 'resize',
|
||||||
width: transform.width,
|
width: Math.round(transform.width),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue