Skip to content

Commit

Permalink
feat: add sizes=auto fallback
Browse files Browse the repository at this point in the history
  • Loading branch information
atcastle authored and luqven committed Sep 23, 2024
1 parent 9de6cc0 commit 94e135c
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 2 deletions.
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,23 @@ For example, if the the developer would like to attach a custom `onLoad` callbac

#### Lazy Loading

If you'd like to lazy load images, we recommend using [lazysizes](https://github.com/aFarkas/lazysizes). In order to use react-imgix with lazysizes, you can simply tell it to generate lazysizes-compatible attributes instead of the standard `src`, `srcset`, and `sizes` by changing some configuration settings:
If you'd like to lazy load images, we recommend using browser-level lazy loading, with the [`loading`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/loading) property, passed in `htmlAttributes`:

```jsx
<Imgix
src="..."
sizes="..."
htmlAttributes={{
loading: "lazy"
}}
/>
```

This property has [strong browser support](https://caniuse.com/loading-lazy-attr), and functions without additional JavaScript. Additionally, using browser-level lazy loading enables optimization of the sizes attribute with `sizes="auto"`, which allows the browser to [automatically calculate the optimal size](https://ericportis.com/posts/2023/auto-sizes-pretty-much-requires-width-and-height/) for the image based on its layout.

If you need granular control over lazy-loading behavior such as loading distance, you can use the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API).

If you are using a library like [lazysizes](https://github.com/aFarkas/lazysizes), you can tell the Imgix component to generate compatible attributes instead of the standard `src`, `srcset`, and `sizes` by changing some configuration settings:

```jsx
<Imgix
Expand Down
12 changes: 11 additions & 1 deletion src/react-imgix.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,18 @@ class ReactImgix extends Component {
defaultAttributeMap,
this.props.attributeConfig
);

const fixedSize = !!(
(width || this.props.htmlAttributes?.width) &&
(height || this.props.htmlAttributes?.height)
);
let adjustedSizes = this.props.sizes;
if (this.props.sizes && this.props.htmlAttributes?.loading === "lazy" && !fixedSize) {
adjustedSizes = "auto, " + adjustedSizes ?? "";
}

const childProps = Object.assign({}, this.props.htmlAttributes, {
[attributeConfig.sizes]: this.props.sizes,
[attributeConfig.sizes]: adjustedSizes,
className: this.props.className,
width: width <= 1 ? null : width ?? this.props.htmlAttributes?.width,
height: height <= 1 ? null : height ?? this.props.htmlAttributes?.height,
Expand Down
84 changes: 84 additions & 0 deletions test/unit/react-imgix.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ describe("When in default mode", () => {
"data-src": "https://mysource.imgix.net/demo.png",
width: "200",
height: "100",
loading: "lazy"
};
sut = shallow(
<Imgix
Expand All @@ -250,6 +251,89 @@ describe("When in default mode", () => {
expect(sut.props()["data-src"]).toEqual(htmlAttributes["data-src"]);
expect(sut.props()["width"]).toEqual(htmlAttributes["width"]);
expect(sut.props()["height"]).toEqual(htmlAttributes["height"]);
expect(sut.props()["loading"]).toEqual(htmlAttributes["loading"]);
});
it("prepends 'auto, ' to the sizes prop if loading is lazy and not fixed size", () => {
const htmlAttributes = {
"data-src": "https://mysource.imgix.net/demo.png",
width: "200",
loading: "lazy",
};
sut = shallow(
<Imgix
src={"https://mysource.imgix.net/demo.png"}
sizes="100vw"
htmlAttributes={htmlAttributes}
/>
);
expect(sut.props()["sizes"]).toEqual("auto, 100vw");
});

it("does not prepend 'auto, ' to the sizes prop if loading is not lazy", () => {
const htmlAttributes = {
"data-src": "https://mysource.imgix.net/demo.png",
width: "200",
height: "100",
loading: "eager", // Not lazy loading
};
sut = shallow(
<Imgix
src={"https://mysource.imgix.net/demo.png"}
sizes="100vw"
htmlAttributes={htmlAttributes}
/>
);
expect(sut.props()["sizes"]).toEqual("100vw");
});

it("does not prepend 'auto, ' to the sizes prop if loading is omitted", () => {
const htmlAttributes = {
"data-src": "https://mysource.imgix.net/demo.png",
width: "200",
height: "100",
};
sut = shallow(
<Imgix
src={"https://mysource.imgix.net/demo.png"}
sizes="100vw"
htmlAttributes={htmlAttributes}
/>
);
expect(sut.props()["sizes"]).toEqual("100vw");
});

it("does not prepend 'auto, ' to the sizes prop if both width and height are present (htmlAttributes)", () => {
const htmlAttributes = {
"data-src": "https://mysource.imgix.net/demo.png",
width: "200",
height: "100",
loading: "lazy",
};
sut = shallow(
<Imgix
src={"https://mysource.imgix.net/demo.png"}
sizes="100vw"
htmlAttributes={htmlAttributes}
/>
);
expect(sut.props()["sizes"]).toEqual("100vw");
});

it("does not prepend 'auto, ' to the sizes prop if both width and height are present (element attributes)", () => {
const htmlAttributes = {
"data-src": "https://mysource.imgix.net/demo.png",
loading: "lazy",
};
sut = shallow(
<Imgix
src={"https://mysource.imgix.net/demo.png"}
sizes="100vw"
width={100}
height={100}
htmlAttributes={htmlAttributes}
/>
);
expect(sut.props()["sizes"]).toEqual("100vw");
});
});
});
Expand Down

0 comments on commit 94e135c

Please sign in to comment.