How to use next.js Image component with HTML <picture> element? - html

Next.js has an Image component that lazy loads images and also provides a srcset for a given image.
However, sometimes we want to deliver different images for different devices (art redirection).
Mozilla says we should use <picture> element for this purpose, providing different images for different media queries.
I can't find an article (even in next.js official docs) to tell us how can we do that using <Image> component.
Is it possible? How can I use next.js <Image> component and HTML <picture> element together?

I have searched for hundreds of websites, this is the only solution I found which workable on Next.js ( with tailwindcss ).
import Image from 'next/image'
<div>
<div className="md:hidden">
<Image src="Banner-767x500.webp" height={500} width={767} />
</div>
<div className="hidden md:inline-flex lg:hidden">
<Image src="Banner-1023x500.webp" height={500} width={1023} />
</div>
<div className="hidden lg:inline-flex xl:hidden">
<Image src="Banner-1400x500.webp" height={500} width={1400} />
</div>
<div className="hidden xl:inline-flex">
<Image height={500} width={2000} src="Banner-2000x500.webp" />
</div>
</div>

The new version of Next Image component removes a lot of the extraneous HTML and styles and allows full flexibility of the img tag. With that new improvement in the component we can use the picture tag and the image component as normal.
Plus, Web.dev explains the way the picture element works really well: https://web.dev/learn/design/picture-element/
In the same way that srcset builds upon the src attribute, the picture element builds upon the img element. The picture element wraps around an img element.
If there is no img element nested inside the picture element, the picture element won't work.
Like the srcset attribute, the picture element will update the value of the src attribute in that img element. The difference is that where the srcset attribute gives suggestions to the browser, the picture element gives commands. This gives you control.
So, understanding that the picture element is just a wrapper of the img element which the browser still requires, and using the new version of next/image (Nextjs v. 13), you can write it as:
import Image from "next/image";
<picture>
<source srcset=".." media="..."/>
<Image src="..." height="..." width="..." alt="..." />
</picture>

A better approach is to use vanilla HTML as the following example, tested in Next.js 13.
Pros:
Full control of what you're showing and when.
Cons:
Manual optimization of assets.
<picture>
<source srcSet="/portrait/my-dog.webp" media="(orientation: portrait)" />
<img src="/my-dog.webp" alt="A beautiful labrador" loading="lazy" />
</picture>

Related

Responsive images via picture element and media queries via CSS

I have the below image HTML code, working great on responsive websites and loading images only when needed based on screen-size, saving the user bandwidth. I'm also already lazy-loading images based on whether they show in the browser viewport.
<picture>
<source media="(max-width: 300px)" srcset="/images/thumb.png ">
<source media="(max-width: 500px)" srcset="/images/largethumb.png ">
<img src="/images/original.png">
</picture>
However, I have many images on my page, so how can I reduce the HTML payload? I'm looking for something like this, but not sure if it's possible at all:
HTML
<picture>
<source srcset="/images/thumb.png ">
<source srcset="/images/largethumb.png ">
<img src="/images/original.png">
</picture>
PSEUDO CSS
picture source:nth-child(1){
media:(max-width: 300px);
}
picture source:nth-child(2){
media:(max-width: 500px);
}
But I can't find anything on Google.
I already checked:
https://alligator.io/html/picture-element/
https://bitsofco.de/the-srcset-and-sizes-attributes/
I'd suggest going with lazy loading.
It literally defers the loading of resources on the page as long as they are not needed. E.g using Intersection Observer API images will never be loaded if users never get to that point of the website. This means serious savings in bandwidth.
There are couple ways how to do this:
Native lazy loading
<img src="yourimage.jpg" loading="lazy" alt="..." />
More info here: https://web.dev/browser-level-image-lazy-loading/
Using the Intersection Observer API
All details here: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
Here is also great article how to match all technics perfectly with responsive images: https://css-tricks.com/tips-for-rolling-your-own-lazy-loading/

Does the picture tag dislike React?

This question has been asked before but there was no given solution. At least nothing that worked for my problem.
In React, the picture tag does not work. It is written in plain html in JSX. No functions, no variables, etc. Just plain hard coded tags.
It had failed to load local images as well as online images.
I had copied the very same html in the JSX file and pasted into an html file. The html file rendered without fail.
This is the code snippet below was the that could render in a html file but not a jsx file through React.
<picture className="dice">
<source id="img512" className="img512" media="" srcSet="./512x512.png" />
<source id="img256" className="img256" media="" srcSet="./256x256.png" />
<source id="img144" className="img144" media="" srcSet="./144x144.png" />
<source id="img96" className="img96" media="" srcSet="./96x96.png" />
<img src="./512x512.png" alt="Icon" />
</picture>
I have tried a single source tag. I have tried removing every attribute exluding srcSet. I have tried using src instead of srcSet and also tried srcset. All have failed rendering an image. The only thing that rendered was the alt text.
Am I missing something here? Is there something that React doesn't like what I have done here?
Here is a link of the post I initially had read before posting:
picture tag in React
Update:
So as "Jesper We" mentioned I be using className instead of class. I personally already knew that this was a common mistake and would have caught this mistake. Since I posted the wrong code early I had ran the code again for the sake of confirmation. Still a no pictures unfortunately
I worked towards "Robin's" comment and check out his suggestion. I copied the code he provided in the link and pasted it into my code. Everything was working. Then I filled in the media queries of my original code. Oddly enough it did not work. Then I used other online images then those images worked. I had tried both png and jpg images and the both worked. Then I used my own images again that were png images and none of them worked.
Now it looks like there something wrong with the images I have but I think problem now no longer revolves around the code. I hope...
You need to modify your code, then it will work perfectly, see this code
https://stackblitz.com/edit/react-jessyq
Resize the output window, you will see the different images for different sizes. Hope your problem will be solved. HAPPY CODING :)
picture tag is used for responsive image, As far i know image will be change according to device width. For this purpose you should use picture tag with media query like this
<picture>
<source media="(min-width: 650px)" srcset="img_pink_flowers.jpg">
<source media="(min-width: 465px)" srcset="img_white_flower.jpg">
<img src="img_orange_flowers.jpg" alt="Flowers" style="width:auto;">
</picture>
For Details: https://www.w3schools.com/tags/tag_picture.asp
And you can't use class in react, use className instead of class.
<picture>
<source media="(min-width: 650px)" srcset="logo.png" width="170" height="100"/>
<img src="smallLogo.png" alt="smallLogo" width="50" height="50" />
</picture>

TYPO3 DCE (Fluid): How to generate an SVG Object instead of an image tag?

Our TYPO3 users (editors) need to exchange / update SVG files to the TYPO3 website. The svg files are clickable, hence the <img> html tag does not work for them. We decided in favour of the <object> tag, with <img> fallback (Do I use <img>, <object>, or <embed> for SVG files?).
The Fluid code for the fronted is easy for generating normal img tags:
<f:layout name="Default" />
<f:section name="main">
<div class="container">
<f:for each="{dce:fal(field:'image1', contentObject:contentObject)}" as="fileReference" iteration="iterator">
<f:if condition="{iterator.isFirst}">
<f:image src="{fileReference.uid}" alt="" treatIdAsReference="1" />
</f:if>
</f:for>
</div>
</f:section>
However, according to FluidTYPO3 vhs ViewHelper for SVG Images?, I might be able to use fluid code like this:
<img src="{f:uri.image(src: 'uploads/tx_myext/{imgIcon}')}">
which, adapted to object, would be:
<object data="{f:uri.image(src: 'xxx')}" type="image/svg+xml">
<img src="{f:uri.image(src: 'xxx')}">
</object>
Unfortunately, I have no idea what to provide as src. {fileReference.uid} only inserts the unique id of the file (a number).
How can I convert the file id to the relative or absolute URI of the picture?
I think the viewhelper attribute treatIdAsReference is what you are looking for.
f:image as well as f:uri:image can handle Files and FileReferences.
It looks like you have a FileReference, so you should add the attribute with value 1
Here is an example with inline notation:
{f:uri.image(src: '{fileReference.uid}', treatIdAsReference:'1')}
The result of this is the path to your file, it can be used in regular HTML-Tags.

How do I make Pinterest pin it button work with HTML5 picture srcset?

I have a basic custom Pin it button. This picks up images inline to the page, but it's not picking up images using the HTML5 picture element with srcset.
<img src="//assets.pinterest.com/images/pidgets/pinit_fg_en_rect_red_28.png" />
Here's an example of the picture element in use, where the button is not working:
<picture>
<img srcset="https://s3-us-west-2.amazonaws.com/s.cdpn.io/652/coffee5.jpg">
</picture>
A very stripped down demo to play with that illustrates the problem: http://codepen.io/michaelpumo/pen/eZyddp
Any ideas?
Update: I might actually have to add that my usecase is a bit more complicated than this. The above is a simplified / stripped down version to illustrate the point. I'm lazy loading these too you see.
Please use the following. It works.
<picture>
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/652/coffee5.jpg" srcset="https://s3-us-west-2.amazonaws.com/s.cdpn.io/652/coffee5.jpg" data-pin-description="Hello World">
</picture>
I thought src and description should be there for Pinterest.

itemprop="image" on element not <img>?

I have a product page that uses Microdata. At the moment the itemprop="image" attribute is specified on the first thumbnail from my thumbnail gallery. What I'd like to do is specify it for the high-res image I have.
The trouble is, that's not actually displayed on the page, it's loaded via JavaScript using a lighbox. I know I can do something like:
<img itemprop="image" src="/img/high-res.jp" style="display:none" />
and the image won't show and it's tagged as the product image. But, of course the image is still download.
Any way I can specify itemprop="image" on an image but not actually download the image?
I tried changing <img> to <span> but the testing tool didn't recognise it.
Perhaps the link element would be useful here - it's not displayed in the rendered HTML, but it is available in the HTML source and therefore available to JavaScript:
<link itemprop="image" href="/img/high-res.jpg">