Replies: 7 comments 3 replies
-
The docs says:
https://nextjs.org/docs/basic-features/image-optimization#loaders So you cannot have a different URL within the loader. What you could do is split your component with the width at a higher level, where you switch between different Image components with different |
Beta Was this translation helpful? Give feedback.
-
thanks @balazsorban44 for your answer The issue splitting the component client side is that you only know the width once the page is rendered, and this bring other issues specially when using SSR. One approach that I used is using picture element with different sources like this <picture>
<source media="(max-width:767px)" srcSet={mobile.url} />
<source media="(min-width:768px)" srcSet={url} />
<img src={url} alt={alt} />
</picture> I was hopping to do something similar with the custom loader |
Beta Was this translation helpful? Give feedback.
-
Currently looking more into this, but as a note, your import Image from 'next/image'
const myLoader = ({ src, width, quality }) => {
return `https://example.com/${src}?w=${width}&q=${quality || 75}`
}
const MyImage = (props) => {
return (
<Image
loader={myLoader}
src="me.png" // <-- no base URL, that is appended in your loader
alt="Picture of the author"
width={500}
height={500}
/>
)
} https://nextjs.org/docs/api-reference/next/image#loader You are appending that domain to your URL in your loader instead. I was told there is actually nothing blocking you from using different domains in your loader based on width. |
Beta Was this translation helpful? Give feedback.
-
Is it correct to assume that you basically want to load different images on different screen sizes? I have this component here: <Image
loader={(props) => {
// This image loads for small screens
if (props.width < 768) {
return `https://www.fillmurray.com/${props.width}/${props.width}`
}
// This should load for bigger screens
return `https://www.fillmurray.com/${props.width * 1.2}/${
props.width * 1.2
}`
}}
src={"/me.png"}
alt=""
width={500}
height={500}
/> In my case just for testing purposes, the src isn't used, but you can should be able to switch on width and define different URLs. Could you maybe show me the output HTML of your image component? It should look something like this_ <img
alt=""
src="https://www.fillmurray.com/1296/1296"
decoding="async"
data-nimg="intrinsic"
style="position:absolute;top:0;left:0;bottom:0;right:0;box-sizing:border-box;padding:0;border:none;margin:auto;display:block;width:0;height:0;min-width:100%;max-width:100%;min-height:100%;max-height:100%"
srcset="https://www.fillmurray.com/640/640 1x, https://www.fillmurray.com/1296/1296 2x">
</img> As you can see, there is a You can check that the correct image loads through your browser inspector. Try to render the page as a high pixel density device (eg. an iPad), and notice it will use a different image. Tell me if that helps |
Beta Was this translation helpful? Give feedback.
-
yes!
<img alt="" src="https://..../c6d3df8b-a975-4745-9db1-e5fbe0f13a5b_bg_cat_hero_01.png?auto=compress,format&w=3840&q=75" decoding="async" data-nimg="true" srcset="https://.../c6d3df8b-a975-4745-9db1-e5fbe0f13a5b_bg_cat_hero_01.png?auto=compress,format&w=1920&q=75 1x, https://.../c6d3df8b-a975-4745-9db1-e5fbe0f13a5b_bg_cat_hero_01.png?auto=compress,format&w=3840&q=75 2x" style="position: absolute; inset: 0px; box-sizing: border-box; padding: 0px; border: none; margin: auto; display: block; width: 0px; height: 0px; min-width: 100%; max-width: 100%; min-height: 100%; max-height: 100%;"> This is the Image component <Image
loader={({ width, quality }) => {
// This image loads for small screens
if (width <= 768) {
const mobileSrc = background_image.mobile.url
const paramsIndex = mobileSrc.indexOf("?")
const paramsString = mobileSrc.substr(paramsIndex)
const searchParams = new URLSearchParams(paramsString)
searchParams.set("w", width.toString())
searchParams.set("q", "100")
const mUrl = `${mobileSrc.substr(0, paramsIndex)}?${searchParams.toString()}`
return mUrl
}
return `${background_image.url}&w=${width}&q=${quality || 75}`
}}
src={"/me.png"}
alt=""
width={background_image.dimensions.width}
height={background_image.dimensions.height}
/> The url of the mobile version should be
|
Beta Was this translation helpful? Give feedback.
-
The closest reproduction to yours I can create is this: export default function Page() {
const background_image = {
url: "https://www.fillmurray.com/1920/1080",
mobile: {
url: "https://www.fillmurray.com/320/640",
},
dimensions: {
width: 500,
height: 500,
},
}
return (
<Image
loader={({ width, quality = 75 }) => {
// This image loads for small screens
if (width <= 768) {
const mobileUrl = new URL(background_image.mobile.url)
mobileUrl.searchParams.set("w", width.toString())
mobileUrl.searchParams.set("q", "100")
return mobileUrl
}
return `${background_image.url}?${new URLSearchParams({
w: width,
q: quality,
})}`
}}
src={"/me.png"}
alt=""
width={background_image.dimensions.width}
height={background_image.dimensions.height}
/>
)
} Which produces the correct HTML: <img alt="" src="https://www.fillmurray.com/1920/1080?w=1080&q=75" decoding="async" data-nimg="intrinsic" style="position:absolute;top:0;left:0;bottom:0;right:0;box-sizing:border-box;padding:0;border:none;margin:auto;display:block;width:0;height:0;min-width:100%;max-width:100%;min-height:100%;max-height:100%" srcset="https://www.fillmurray.com/320/640?w=640&q=100 1x, https://www.fillmurray.com/1920/1080?w=1080&q=75 2x"> So when using different pixel density screens (Chrome Inspector > Toggle Device Toolbar > change to a high pixel density screen), upon reloading the page, I get a different image. So I believe this is not a bug in Next.js, we just have to figure out what configuration changes you have to make. Have you tried playing with the Also, check out the device and image seize sections: https://nextjs.org/docs/api-reference/next/image#device-sizes |
Beta Was this translation helpful? Give feedback.
-
yes I did, but in this case layout has no impact at all same as device/image sizes In your example, you are returning the same url just with different sizes. If you look closely to my example, the name of the image returned when the width is mobile is different. And if you look at the generated srcset, the name is not present there Could you try the same example but using something like this? const background_image = {
url: "https://www.fillmurray.com/desktop_image.png",
mobile: {
url: "https://www.fillmurray.com/mobile_image.png",
},
dimensions: {
width: 500,
height: 500,
},
} |
Beta Was this translation helpful? Give feedback.
-
What version of Next.js are you using?
11.1.0
What version of Node.js are you using?
14.17.0
What browser are you using?
Chrome, Safari, Firefox, Brave
What operating system are you using?
macOS
How are you deploying your application?
Other platform
Describe the Bug
I'm using the Image component with a custom loader to load an image from different sources based on different widths. So basically I have this
The issue is that this doesn't work. If the value returned from the custom loader has a different base url than the original src, it will ignore the value.
Expected Behavior
What I'm expecting is to be able to load different images from different sources based on the width. This allows me to load one image for certain sizes and some other for others.
Also each image could be optimized per it's own width
So I could have something like this
for a width > 768 I would use this src
https://example.com/mydesktop_img.png?w=1080&q=75
https://example.com/mydesktop_img.png?w=1280&q=75
and for width <= 768 I would have something like this
https://example.com/mymobile_img.png?w=368&q=75
https://example.com/mymobile_img.png?w=672&q=75
To Reproduce
As described in the bug, the way to reproduce this would be to return a different src value (base url) from the custom loader when using an Image component
Beta Was this translation helpful? Give feedback.
All reactions