Responsive images via picture element and media queries via CSS - html

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/

Related

Is it possible not to make download image for the mobile users if these images are in display none in the mobile version?

I have a site in Laravel with tailwindcss and I have some articles with images in the desktop version and these images are in display:none for the mobile version, my question is: is it possible not to make to download the image for my mobile users? To make my site faster and less heavy for phones (sorry if I make english mistake, it's not my main languages).
For the moment I use the picture tag with an image of 1 x 1 px with a media query max-width, in order to have a minimal download, but I wonder if there is not a more appropriate technique.
<picture class="hidden lg:inline object-cover rounded-l-xl max-w-xl">
<source media="(max-width: 599px)" srcset="{{asset('img/student-medium.jpg')}}">
<source media="(min-width: 600px)" srcset="{{asset('img/student.jpg')}}">
<img src="{{asset('img/student.jpg')}}" alt="photo d'étudiants qui travaillent">
</picture>
Use the attribute loading: lazy on a img tag seem to be a good solution to my problem.
<img class="hidden lg:inline object-cover rounded-l-xl max-w-xl" loading="lazy"
src="{{asset('img/student.jpg')}}" srcset="{{asset('img/student-medium.jpg')}} 1x,
{{asset('img/student.jpg')}} 2x" alt="photo d'étudiants qui travaillent">

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

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>

Source of picture tag doesn't work, it always goes to fallback

I have version 90 of Chrome so <picture> tag should work here. But it always goes to fallback. When I comment <img>, nothing is shown on the screen.
The code:
<picture>
<source media="(max-width: 400px)" srcset="./public/forest_400.jpg, ./public/forest_768.jpg 2x">
<source media="(min-width: 401px)" srcset="./public/forest_768.jpg">
<img
class="srcset"
src="./public/forest_768.jpg"
alt="a beautiful art in blue and yellow colors with river and forest on both sides of it during sunset or sundown"
>
</picture>
I couldn't find any solution on internet. Would appreciate any help!
As #DanMacák said in his comment:
MDN says to that it serves 2 purposes. One is the fallback, the other is indeed displaying selected source (or fallback): "The selected image is then presented in the space occupied by the element." developer.mozilla.org/en-US/docs/Web/HTML/Element/picture
So there is no problem in this code. I'm closing this question.

Simple rollover effect using picture source srcset with next-gen images like .webp

Updating code and optimizing site speed so trying to change this simple html rollover effect:
<img src="img1.jpg" onmouseover="this.src='img2.jpg'" onmouseout="this.src='img1.jpg'">
To something along the lines of this:
<picture>
<source srcset="img1.webp" type="image/webp" onmouseover="this.src='img2.webp'" onmouseout="this.src='img1.webp'">
<source srcset="img1.jpg" type="image/jpeg" onmouseover="this.src='img2.jpg'" onmouseout="this.src='img1.jpg'">
<img src="img1.jpg" onmouseover="this.src='img2.jpg'" onmouseout="this.src='img1.jpg'">
</picture>
I didn't really expect the latter to work, but am mentally blocked as to the correct approach for this basic effect so the browser will access the appropriate image format.
Assuming one is already using Modernizr js, here is one possible solution using CSS & HTML:
.webp .rollover{
background:url("/img3/img1.webp")
}
.webp .rollover:hover{
background:url("/img3/img2.webp")
}
.no-webp .rollover{
background:url("/img3/img1.jpg")
}
.no-webp .rollover:hover{
background:url("/img3/img2.jpg")
}
<div class="rollover"></div>
I know there are other solutions as well, but this one worked for me.
One downside of this approach is there is a lag while img2.xxx is loaded 'onHover'. However, this also means img2 is not explicitly 'preloaded', hence speeding up overall page download time. (One could finesse this too).

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>