Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change experimental layout=raw to use native img lazy loading #36985

Merged
merged 10 commits into from
May 18, 2022
14 changes: 7 additions & 7 deletions docs/api-reference/next/image.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,13 @@ The `<Image />` component accepts a number of additional properties beyond those

The layout behavior of the image as the viewport changes size.

| `layout` | Behavior | `srcSet` | `sizes` | Has wrapper and sizer |
| ---------------------------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | -------- | --------------------- |
| `intrinsic` (default) | Scale *down* to fit width of container, up to image size | `1x`, `2x` (based on [imageSizes](#image-sizes)) | N/A | yes |
| `fixed` | Sized to `width` and `height` exactly | `1x`, `2x` (based on [imageSizes](#image-sizes)) | N/A | yes |
| `responsive` | Scale to fit width of container | `640w`, `750w`, ... `2048w`, `3840w` (based on [imageSizes](#image-sizes) and [deviceSizes](#device-sizes)) | `100vw` | yes |
| `fill` | Grow in both X and Y axes to fill container | `640w`, `750w`, ... `2048w`, `3840w` (based on [imageSizes](#image-sizes) and [deviceSizes](#device-sizes)) | `100vw` | yes |
| `raw`[\*](#experimental-raw-layout-mode) | Insert the image element with no automatic layout behavior | Behaves like `responsive` if the image has the `sizes` prop, and like `fixed` if it does not | optional | no |
| `layout` | Behavior | `srcSet` | `sizes` | Has wrapper and sizer |
| ---------------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | -------- | --------------------- |
| `intrinsic` (default) | Scale *down* to fit width of container, up to image size | `1x`, `2x` (based on [imageSizes](#image-sizes)) | N/A | yes |
| `fixed` | Sized to `width` and `height` exactly | `1x`, `2x` (based on [imageSizes](#image-sizes)) | N/A | yes |
| `responsive` | Scale to fit width of container | `640w`, `750w`, ... `2048w`, `3840w` (based on [imageSizes](#image-sizes) and [deviceSizes](#device-sizes)) | `100vw` | yes |
| `fill` | Grow in both X and Y axes to fill container | `640w`, `750w`, ... `2048w`, `3840w` (based on [imageSizes](#image-sizes) and [deviceSizes](#device-sizes)) | `100vw` | yes |
| `raw`[\*](#experimental-raw-layout-mode) | Raw `<img>` without styles and native lazy loading | Behaves like `responsive` if the image has the `sizes` prop, and like `fixed` if it does not | optional | no |

- [Demo the `intrinsic` layout (default)](https://image-component.nextjs.gallery/layout-intrinsic)
- When `intrinsic`, the image will scale the dimensions down for smaller viewports, but maintain the original dimensions for larger viewports.
Expand Down
15 changes: 11 additions & 4 deletions packages/next/client/image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ export default function Image({
rootMargin: lazyBoundary,
disabled: !isLazy,
})
const isVisible = !isLazy || isIntersected
const isVisible = !isLazy || isIntersected || layout === 'raw'

const wrapperStyle: JSX.IntrinsicElements['span']['style'] = {
boxSizing: 'border-box',
Expand Down Expand Up @@ -571,6 +571,11 @@ export default function Image({
`Image with src "${src}" has "layout='raw'" and 'objectFit' or 'objectPosition'. For raw images, these and other styles should be specified using the 'style' attribute.`
)
}
if (layout === 'raw' && (lazyRoot || lazyBoundary)) {
throw new Error(
`Image with src "${src}" has "layout='raw'" and 'lazyRoot' or 'lazyBoundary'. For raw images, native lazy loading is used so lazyRoot and lazyBoundary cannot be used.`
)
}
if (
sizes &&
layout !== 'fill' &&
Expand Down Expand Up @@ -677,7 +682,7 @@ export default function Image({
}
}

const imgStyle = Object.assign({}, style, layout === 'raw' ? {} : layoutStyle)
const imgStyle = layout === 'raw' ? {} : Object.assign({}, style, layoutStyle)
const blurStyle =
placeholder === 'blur' && !blurComplete
? {
Expand Down Expand Up @@ -882,7 +887,7 @@ const ImageElement = ({
blurStyle,
isLazy,
placeholder,
loading,
loading = 'lazy',
srcString,
config,
unoptimized,
Expand All @@ -904,6 +909,8 @@ const ImageElement = ({
decoding="async"
data-nimg={layout}
className={className}
// @ts-ignore - TODO: upgrade to `@types/react@17`
loading={layout === 'raw' ? loading : undefined}
style={{ ...imgStyle, ...blurStyle }}
ref={useCallback(
(img: ImgElementWithDataProp) => {
Expand Down Expand Up @@ -974,7 +981,7 @@ const ImageElement = ({
style={imgStyle}
className={className}
// @ts-ignore - TODO: upgrade to `@types/react@17`
loading={loading || 'lazy'}
loading={loading}
/>
</noscript>
)}
Expand Down