Skip to content
Merged
21 changes: 19 additions & 2 deletions packages/next/client/image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,25 @@ allSizes.sort((a, b) => a - b)

function getWidths(
width: number | undefined,
layout: LayoutValue
layout: LayoutValue,
sizes: string | undefined
): { widths: number[]; kind: 'w' | 'x' } {
if (sizes && (layout === 'fill' || layout === 'responsive')) {
// Find all the "vw" percent sizes used in the sizes prop
const percentSizes = [...sizes.matchAll(/(^|\s)(1?\d?\d)vw/g)].map((m) =>
parseInt(m[2])
)
if (percentSizes.length) {
const smallestRatio = Math.min(...percentSizes) * 0.01
return {
widths: allSizes.filter(
(s) => s >= configDeviceSizes[0] * smallestRatio
),
kind: 'w',
}
}
return { widths: allSizes, kind: 'w' }
}
if (
typeof width !== 'number' ||
layout === 'fill' ||
Expand Down Expand Up @@ -146,7 +163,7 @@ function generateImgAttrs({
return { src, srcSet: undefined, sizes: undefined }
}

const { widths, kind } = getWidths(width, layout)
const { widths, kind } = getWidths(width, layout, sizes)
const last = widths.length - 1

return {
Expand Down
23 changes: 23 additions & 0 deletions test/integration/image-component/default/pages/layout-fill.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,29 @@ const Page = () => {
/>
</div>
<p>Layout Fill</p>
<div style={{ position: 'relative', width: '50vw', height: '50vh' }}>
<Image
id="fill3"
src="/wide.png"
layout="fill"
objectFit="cover"
objectPosition="left center"
sizes="(min-width: 1200px) 90vw,
(min-width: 800px) 30vw,
100vw"
/>
</div>
<p>Layout Fill</p>
<div style={{ position: 'relative', width: '50vw', height: '50vh' }}>
<Image
id="fill4"
src="/wide.png"
layout="fill"
objectFit="cover"
objectPosition="left center"
sizes="500px"
/>
</div>
</div>
)
}
Expand Down
10 changes: 9 additions & 1 deletion test/integration/image-component/default/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,14 @@ function runTests(mode) {
)
expect(objectFit).toBe('cover')
expect(objectPosition).toBe('left center')
await browser.eval(`document.getElementById("fill3").scrollIntoView()`)
expect(await browser.elementById('fill3').getAttribute('srcset')).toBe(
'/_next/image?url=%2Fwide.png&w=256&q=75 256w, /_next/image?url=%2Fwide.png&w=384&q=75 384w, /_next/image?url=%2Fwide.png&w=640&q=75 640w, /_next/image?url=%2Fwide.png&w=750&q=75 750w, /_next/image?url=%2Fwide.png&w=828&q=75 828w, /_next/image?url=%2Fwide.png&w=1080&q=75 1080w, /_next/image?url=%2Fwide.png&w=1200&q=75 1200w, /_next/image?url=%2Fwide.png&w=1920&q=75 1920w, /_next/image?url=%2Fwide.png&w=2048&q=75 2048w, /_next/image?url=%2Fwide.png&w=3840&q=75 3840w'
)
await browser.eval(`document.getElementById("fill4").scrollIntoView()`)
expect(await browser.elementById('fill4').getAttribute('srcset')).toBe(
'/_next/image?url=%2Fwide.png&w=16&q=75 16w, /_next/image?url=%2Fwide.png&w=32&q=75 32w, /_next/image?url=%2Fwide.png&w=48&q=75 48w, /_next/image?url=%2Fwide.png&w=64&q=75 64w, /_next/image?url=%2Fwide.png&w=96&q=75 96w, /_next/image?url=%2Fwide.png&w=128&q=75 128w, /_next/image?url=%2Fwide.png&w=256&q=75 256w, /_next/image?url=%2Fwide.png&w=384&q=75 384w, /_next/image?url=%2Fwide.png&w=640&q=75 640w, /_next/image?url=%2Fwide.png&w=750&q=75 750w, /_next/image?url=%2Fwide.png&w=828&q=75 828w, /_next/image?url=%2Fwide.png&w=1080&q=75 1080w, /_next/image?url=%2Fwide.png&w=1200&q=75 1200w, /_next/image?url=%2Fwide.png&w=1920&q=75 1920w, /_next/image?url=%2Fwide.png&w=2048&q=75 2048w, /_next/image?url=%2Fwide.png&w=3840&q=75 3840w'
)
} finally {
if (browser) {
await browser.close()
Expand All @@ -429,7 +437,7 @@ function runTests(mode) {
'/_next/image?url=%2Fwide.png&w=3840&q=75'
)
expect(await browser.elementById(id).getAttribute('srcset')).toBe(
'/_next/image?url=%2Fwide.png&w=640&q=75 640w, /_next/image?url=%2Fwide.png&w=750&q=75 750w, /_next/image?url=%2Fwide.png&w=828&q=75 828w, /_next/image?url=%2Fwide.png&w=1080&q=75 1080w, /_next/image?url=%2Fwide.png&w=1200&q=75 1200w, /_next/image?url=%2Fwide.png&w=1920&q=75 1920w, /_next/image?url=%2Fwide.png&w=2048&q=75 2048w, /_next/image?url=%2Fwide.png&w=3840&q=75 3840w'
'/_next/image?url=%2Fwide.png&w=16&q=75 16w, /_next/image?url=%2Fwide.png&w=32&q=75 32w, /_next/image?url=%2Fwide.png&w=48&q=75 48w, /_next/image?url=%2Fwide.png&w=64&q=75 64w, /_next/image?url=%2Fwide.png&w=96&q=75 96w, /_next/image?url=%2Fwide.png&w=128&q=75 128w, /_next/image?url=%2Fwide.png&w=256&q=75 256w, /_next/image?url=%2Fwide.png&w=384&q=75 384w, /_next/image?url=%2Fwide.png&w=640&q=75 640w, /_next/image?url=%2Fwide.png&w=750&q=75 750w, /_next/image?url=%2Fwide.png&w=828&q=75 828w, /_next/image?url=%2Fwide.png&w=1080&q=75 1080w, /_next/image?url=%2Fwide.png&w=1200&q=75 1200w, /_next/image?url=%2Fwide.png&w=1920&q=75 1920w, /_next/image?url=%2Fwide.png&w=2048&q=75 2048w, /_next/image?url=%2Fwide.png&w=3840&q=75 3840w'
)
expect(await browser.elementById(id).getAttribute('sizes')).toBe(
'(max-width: 2048px) 1200px, 3840px'
Expand Down