Skip to content

Commit 53f0973

Browse files
authored
Fix next/image blur placeholder when JS is disabled (#28269)
This PR does a few things: - Moves `<noscript>` usage below the blur image since so that the `<noscript>` image renders on top of the blur image - Remove the `isVisible` check for `<noscript>` since we can't rely on client-side JS - Add `loading=lazy` to the `<noscript>` image to take advantage of native lazy loading (can't rely on JS lazy loading) Fixes #28251
1 parent f2fa4f3 commit 53f0973

File tree

4 files changed

+27
-22
lines changed

4 files changed

+27
-22
lines changed

packages/next/client/image.tsx

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -597,26 +597,6 @@ export default function Image({
597597
) : null}
598598
</div>
599599
) : null}
600-
{!isVisible && (
601-
<noscript>
602-
<img
603-
{...rest}
604-
{...generateImgAttrs({
605-
src,
606-
unoptimized,
607-
layout,
608-
width: widthInt,
609-
quality: qualityInt,
610-
sizes,
611-
loader,
612-
})}
613-
decoding="async"
614-
data-nimg
615-
style={imgStyle}
616-
className={className}
617-
/>
618-
</noscript>
619-
)}
620600
<img
621601
{...rest}
622602
{...imgAttributes}
@@ -629,6 +609,26 @@ export default function Image({
629609
}}
630610
style={{ ...imgStyle, ...blurStyle }}
631611
/>
612+
<noscript>
613+
<img
614+
{...rest}
615+
{...generateImgAttrs({
616+
src,
617+
unoptimized,
618+
layout,
619+
width: widthInt,
620+
quality: qualityInt,
621+
sizes,
622+
loader,
623+
})}
624+
decoding="async"
625+
data-nimg
626+
style={imgStyle}
627+
className={className}
628+
loading={loading || 'lazy'}
629+
/>
630+
</noscript>
631+
632632
{priority ? (
633633
// Note how we omit the `href` attribute, as it would only be relevant
634634
// for browsers that do not support `imagesrcset`, and in those cases

packages/next/types/index.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ declare module 'react' {
4040
interface LinkHTMLAttributes<T> extends HTMLAttributes<T> {
4141
nonce?: string
4242
}
43+
44+
// <img loading="lazy"> support
45+
interface ImgHTMLAttributes<T> extends HTMLAttributes<T> {
46+
loading?: 'auto' | 'eager' | 'lazy'
47+
}
4348
}
4449

4550
export type Redirect =

test/integration/export-image-loader/test/index.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ describe('Export with custom loader next/image component', () => {
7474
it('should contain img element with same src in html output', async () => {
7575
const html = await fs.readFile(join(outdir, 'index.html'))
7676
const $ = cheerio.load(html)
77-
expect($('img[alt="icon"]').attr('src')).toBe('/custom/i.png')
77+
expect($('img[src="/custom/o.png"]')).toBeDefined()
7878
})
7979

8080
afterAll(async () => {

test/integration/image-component/default/test/index.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ function runTests(mode) {
151151
const els = [].slice.apply($html('img'))
152152
expect(els.length).toBe(2)
153153

154-
const [noscriptEl, el] = els
154+
const [el, noscriptEl] = els
155155
expect(noscriptEl.attribs.src).toBeDefined()
156156
expect(noscriptEl.attribs.srcset).toBeDefined()
157157

0 commit comments

Comments
 (0)