diff --git a/packages/next/client/future/image.tsx b/packages/next/client/future/image.tsx index 46a8d92adfd2..d4a11ae14605 100644 --- a/packages/next/client/future/image.tsx +++ b/packages/next/client/future/image.tsx @@ -130,6 +130,7 @@ type ImageElementProps = Omit & { placeholder: PlaceholderValue onLoadingCompleteRef: React.MutableRefObject setBlurComplete: (b: boolean) => void + setShowAltText: (b: boolean) => void noscriptSizes: string | undefined } @@ -403,6 +404,7 @@ export default function Image({ } const [blurComplete, setBlurComplete] = useState(false) + const [showAltText, setShowAltText] = useState(false) let widthInt = getInt(width) let heightInt = getInt(height) const qualityInt = getInt(quality) @@ -576,6 +578,7 @@ export default function Image({ width: '100%', } : {}, + showAltText || placeholder === 'blur' ? {} : { color: 'transparent' }, style ) const svgBlurPlaceholder = `url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http%3A//www.w3.org/2000/svg' viewBox='0 0 ${widthInt} ${heightInt}'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='50'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='discrete' tableValues='1 1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Cimage filter='url(%23b)' x='0' y='0' height='100%25' width='100%25' href='${blurDataURL}'/%3E%3C/svg%3E")` @@ -655,6 +658,7 @@ export default function Image({ srcString, onLoadingCompleteRef, setBlurComplete, + setShowAltText, noscriptSizes: sizes, ...rest, } @@ -704,6 +708,7 @@ const ImageElement = ({ loader, onLoadingCompleteRef, setBlurComplete, + setShowAltText, onLoad, onError, noscriptSizes, @@ -756,6 +761,8 @@ const ImageElement = ({ } }} onError={(event) => { + // if the real image fails to load, this will ensure "alt" is visible + setShowAltText(true) if (placeholder === 'blur') { // If the real image fails to load, this will still remove the placeholder. setBlurComplete(true) diff --git a/test/integration/image-future/default/test/index.test.js b/test/integration/image-future/default/test/index.test.js index 962d94517908..fb800d9a36d8 100644 --- a/test/integration/image-future/default/test/index.test.js +++ b/test/integration/image-future/default/test/index.test.js @@ -361,6 +361,10 @@ function runTests(mode) { () => browser.eval(`document.getElementById("msg1").textContent`), 'no error occured for img1' ) + await check( + () => browser.eval(`document.getElementById("img1").style.color`), + 'transparent' + ) await browser.eval( `document.getElementById("img2").scrollIntoView({behavior: "smooth"})` ) @@ -368,11 +372,19 @@ function runTests(mode) { () => browser.eval(`document.getElementById("msg2").textContent`), 'no error occured for img2' ) + await check( + () => browser.eval(`document.getElementById("img2").style.color`), + 'transparent' + ) await browser.eval(`document.getElementById("toggle").click()`) await check( () => browser.eval(`document.getElementById("msg2").textContent`), 'error occured while loading img2' ) + await check( + () => browser.eval(`document.getElementById("img2").style.color`), + '' + ) }) it('should work with image with blob src', async () => { @@ -444,7 +456,9 @@ function runTests(mode) { ) expect(childElementType).toBe('IMG') - expect(await browser.elementById('img1').getAttribute('style')).toBeNull() + expect(await browser.elementById('img1').getAttribute('style')).toBe( + 'color:transparent' + ) expect(await browser.elementById('img1').getAttribute('height')).toBe( '700' ) @@ -459,7 +473,7 @@ function runTests(mode) { ) expect(await browser.elementById('img2').getAttribute('style')).toBe( - 'padding-left:4rem;width:100%;object-position:30% 30%' + 'color:transparent;padding-left:4rem;width:100%;object-position:30% 30%' ) expect(await browser.elementById('img2').getAttribute('height')).toBe( '700' @@ -474,7 +488,9 @@ function runTests(mode) { 'lazy' ) - expect(await browser.elementById('img3').getAttribute('style')).toBeNull() + expect(await browser.elementById('img3').getAttribute('style')).toBe( + 'color:transparent' + ) expect(await browser.elementById('img3').getAttribute('srcset')).toBe( `/_next/image?url=%2Ftest.png&w=640&q=75 1x, /_next/image?url=%2Ftest.png&w=828&q=75 2x` ) @@ -591,14 +607,14 @@ function runTests(mode) { const browser = await webdriver(appPort, '/style-prop') expect(await browser.elementById('with-styles').getAttribute('style')).toBe( - 'border-radius:10px;padding:10px' + 'color:transparent;border-radius:10px;padding:10px' ) expect( await browser.elementById('with-overlapping-styles').getAttribute('style') - ).toBe('width:10px;border-radius:10px;margin:15px') + ).toBe('color:transparent;width:10px;border-radius:10px;margin:15px') expect( await browser.elementById('without-styles').getAttribute('style') - ).toBeNull() + ).toBe('color:transparent') }) if (mode === 'dev') {