diff --git a/README.md b/README.md index 2f470d63..f0ec6f4e 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ This will generate HTML similar to the following: Since imgix can generate as many derivative resolutions as needed, react-imgix calculates them programmatically, using the dimensions you specify. All of this information has been placed into the srcset and sizes attributes. -**Width and height known:** If the width and height are known beforehand, it is recommended that they are set explicitly: +**Width and height known and fixed:** If the width and height are known beforehand, and a fixed-size image is wanted, it is recommended that they are set explicitly: ```js import Imgix from "react-imgix"; @@ -127,17 +127,44 @@ import Imgix from "react-imgix"; [![Edit xp0348lv0z](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/charming-keller-kjnsq) +When width and height are specified, Imgix will give the image a srcset with resolution descriptors. + +**Width and height known but fluid:** If the image's intrinsic width and height are known but a fluid size image is wanted, [width and height should still be set to avoid layout shift](https://web.dev/optimize-cls/), but they must be set via `htmlAttributes` so as not to hint to Imgix to produce resolution descriptors in the srcset. + +```js +import Imgix from "react-imgix"; + + element + width: 200, + height: 100, + }} +/>; +``` + +In this example, Imgix will produce a srcset with width descriptors. + #### Server-Side Rendering React-imgix also works well on the server. Since react-imgix uses `srcset` and `sizes`, it allows the browser to render the correctly sized image immediately after the page has loaded. +If they are known, pass width and height attributes via `htmlAttributes` to help combat layout shift. ```js import Imgix from "react-imgix"; -; +; ``` -If the width and height are known beforehand, it is recommended that they are set explicitly: +If the width and height are known beforehand, and a fixed-size image is wanted, set width and height and do not set `sizes`: ```js import Imgix from "react-imgix"; diff --git a/src/react-imgix.jsx b/src/react-imgix.jsx index 2885b6c4..6c4557c9 100644 --- a/src/react-imgix.jsx +++ b/src/react-imgix.jsx @@ -247,8 +247,8 @@ class ReactImgix extends Component { const childProps = Object.assign({}, this.props.htmlAttributes, { [attributeConfig.sizes]: this.props.sizes, className: this.props.className, - width: width <= 1 ? null : width, - height: height <= 1 ? null : height, + width: width <= 1 ? null : width ?? this.props.htmlAttributes?.width, + height: height <= 1 ? null : height ?? this.props.htmlAttributes?.height, [attributeConfig.src]: src, ref: (el) => { this.imgRef = el; @@ -383,8 +383,8 @@ class SourceImpl extends Component { const childProps = Object.assign({}, this.props.htmlAttributes, { [attributeConfig.sizes]: this.props.sizes, className: this.props.className, - width: null, - height: null, + width: width <= 1 ? null : width ?? this.props.htmlAttributes?.width, + height: height <= 1 ? null : height ?? this.props.htmlAttributes?.height, ref: (el) => { this.sourceRef = el; if ( diff --git a/test/unit/react-imgix.test.jsx b/test/unit/react-imgix.test.jsx index b2e68e4a..b80874ab 100644 --- a/test/unit/react-imgix.test.jsx +++ b/test/unit/react-imgix.test.jsx @@ -232,6 +232,26 @@ describe("When in default mode", () => { }); }); }); + + describe("using the htmlAttributes prop", () => { + it("passes any attributes via htmlAttributes to the rendered element", () => { + const htmlAttributes = { + "data-src": "https://mysource.imgix.net/demo.png", + width: "200", + height: "100", + }; + sut = shallow( + + ); + expect(sut.props()["data-src"]).toEqual(htmlAttributes["data-src"]); + expect(sut.props()["width"]).toEqual(htmlAttributes["width"]); + expect(sut.props()["height"]).toEqual(htmlAttributes["height"]); + }); + }); }); describe("When in image mode", () => { @@ -359,10 +379,10 @@ describe("When in mode", () => { expect(srcSets[4].split(" ")[1]).toBe("5x"); }); - it("width and height should be nullable to pass HTML validation", () => { - const {width, height} = renderImage().props(); - expect(width).toBe(null); - expect(height).toBe(null); + it("width and height should be passed through to the img element", () => { + const { width, height } = renderImage().props(); + expect(width).toBe(100); + expect(height).toBe(100); }); }); @@ -417,6 +437,8 @@ describe("When in mode", () => { it("passes any attributes via htmlAttributes to the rendered element", () => { const htmlAttributes = { "data-src": "https://mysource.imgix.net/demo.png", + width: "200", + height: "100", }; sut = mount( mode", () => { expect(sut.props()["htmlAttributes"]["data-src"]).toEqual( htmlAttributes["data-src"] ); + expect(sut.props()["htmlAttributes"]["width"]).toEqual( + htmlAttributes["width"] + ); + expect(sut.props()["htmlAttributes"]["height"]).toEqual( + htmlAttributes["height"] + ); }); it("attaches a ref via htmlAttributes", () => {