JPG vs JPEG2000 vs WebP - reactjs

I'm building my website using React and have multiple images to display. After running an audit using the Google Chrome audit function, I've been getting the "Serve images in next-gen formats" opportunity message.
After reading about the various formats (WebP, JPEG2000, JPEGXR), it seems each is supported on only select browsers. For instance, I can't just convert all of my images to WebP because they won't show up on the Safari browser. So my issue is how to I "serve" each type of image depending on the browser being used? This is what I've tried:
I have 3 types of files, jpg, JPEG2000, and WebP. Each is being imported like:
import Imagejpg from './path/image.jpg'
import ImageJPEG2000 from './path/image.JPEG2000'
import ImageWebP from './path/image.webp'
Then in my class, I have an object array that contains the images. To use the images:
<picture>
<source>
srcSet={`
${project.Imagejpg},
${project.ImageJPEG2000},
${project.ImageWebP},
</source>
<img src={project.imageWebP} alt=""/>
</picture>
Now, if I only use the jpg image, it works fine on all browsers as most browsers can use jpg. But I'm trying to optimize my site and use the better types of image files. Is there a way to use the several types of files or is there something I am missing?

The solution is indeed in the <picture> element, but using multiple sources.
The code with correct syntax looks like this:
<picture>
<source srcSet={project.ImageWebP} type="image/webp" />
<source srcSet={project.ImageJPEG2000} type="image/jp2" />
<source srcSet={project.Imagejpg} type="image/jpeg" />
<img src={project.Imagejpg} alt="" />
</picture>
Explanation
Seeing the picture element, a browser will download the first source it can support. If it's an old browser that doesn't support <picture> at all, it will fall back to the <img /> tag which has a jpeg source.
This is a quick and easy win to improve your page's speed. The tiny overhead in extra HTML bytes does not negate the speed improvements except in extreme scenarios, like very small and simple images.

Related

Issue with next/image in NextJS V12.3.0 specifically with alt attribute

I use next/image to render images on the site and set the alt tag appropriately. The images I use originate from a CDN. I have a NextJS-based repository. The issue is that, despite the fact that the image is rendering correctly, whenever I check my site's Google cache and switch to the text-only version, Google attempts to replace the image with the text specified in the alt attribute, which is somehow repeating itself. As a result, instead of displaying "Some Image ALT," Google displays "Some Image ALTSome Image ALT."
Here's my implementation for reference:
<div className="videoCard__image">
<Image
src={bannerUrl}
alt={titleLabel}
layout="responsive"
width={123.6}
height={120}
className="videoCard__image--banner"
priority={loadPriority}
sizes="33vw"
quality={80}
/>
<PlayCircleOutline className="videoCard__image--play-icon" />
</div>
Rendered image HTML from next/image ->
Rendered image HTML from next/image
Google cache text only version ->
Google cache text only version
Expectation: ALT attributte text to occur to once instead of twice.

React - pixel ratio - set 2x 3x images for retina devices

I am creating a react app.
I want the browser to server an image (twice bigger in resolution) to retina devices.
I am trying with 2x. I am trying in different ways:
The png is imported.
{retina} is the URL of the twice bigger image.
{logo} is the normal size image.
I have tried to implement it this way:
<picture>
<source srcset={`${retina} 2x, ${logo} 1x`} />
<img src={logo} alt="Flowers" />
</picture>
also this way:
<img srcset={`
${ratina} 2x,
${Logo} 1x,
`}
src={Logo}
></img>
and this way:
<picture>
<img src={logo} srcset={`${retina} 2x`} />
</picture>
and this way:
<img src={logo} srcset={`${retina} 2x`} />
For testing purposes I gave the retina png image a different color, just to notice it immediately when it works.
Problem 1:
In some of the above cases it shows twice the normal image, sometimes twice the retina images, but in none of the above cases it shows a normal image for 1x and 2x for retina devices. I am testing it on PC, iPhone, and with Chrome emulator with custom device set to pixel ratio 2.
Problem 2 (that's not really a problem, but...):
In all cases the images are loaded in the browser as:
Can
anybody point out what I am doing wrong so that the 2x image is not
showing up?
How can I import the image, so that the real image URL
will be rendered and not a base64 without the need to create a
.env file and set the IMAGE_INLINE_SIZE_LIMIT to 0? Any other way to achieve the same?
Thank you
Almost there. You just need to name the attribute according to JSX style, which is srcSet. Also, whatever you put in src is considered the default resolution load, so in srcSet you just need the 2x and 3x, if applicable.
Full Code Example using an image called logo:
import logo from '../path-to/logo.png'
import logo2x from '../path-to/logo#2x.png'
import logo3x from '../path-to/logo#3x.png'
<img
src={logo}
srcSet={`${logo2x} 2x, ${logo3x} 3x`}
/>

React and srcSet: images loading time

I am working with React. I have a grid with some images, with srcset —srcSet in React—. Each image looks something like this:
<img
class="App-gridImage"
src="https://picsum.photos/1200?image=5" sizes="600px"
srcSet="
https://picsum.photos/200?image=5 200w,
https://picsum.photos/400?image=5 400w,
https://picsum.photos/1200?image=5 1200w,
https://picsum.photos/2400?image=5 2400w,
"
/>
Even using srcSet, the images need some time to load. I just created a sandbox to demonstrate it. You will only notice the delay in the first load; after it, images are cached, so it will be necessary to delete caché to appreciate it again: https://codesandbox.io/s/x21y88q39o
I would like to know if srcset is properly used here, and what other strategies can I use to avoid that problem

How to deal with spaces in image source

I have a lot of images that unfortunately have spaces in their URL's. These are submitted through user input in another system and saved to a database.
I'm having a problem with angular's management of image sources. It doesn't seem to like spaces or "%20" in the ng-src or src attributes.
This
<img ng-src="{{smallImg}}" alt="" />
Will output this
<img ng-src="" alt="" />
While this
HERE
will output this
HERE
Is there a way to do this without having to go back and rename all these folders?
I got the answer, it is working for me.
You can get this like:-
$scope.smallImg = "http://example.com/path to my/image with/spaces.jpg";
when you bind this do like
<img ng-src="{{smallImg .replace(' ','')}}" alt="" >
I haven't been able to make <img> src empty when using %20, but perhaps you're using an older version of Angular.
$scope.smallImg = "http://www.google.com/my images here/pic.jpg".replace(/ /g, "%20");
...
<img ng-src="{{smallImg}}" alt="Pic goes here" />
Here's a working demo: https://plnkr.co/edit/hTFw8rAg0CRxDGjROjjp
(tried to find an image on the web that had a space in the name, but no luck)
Well, as it turns out it was a secondary plugin, magic360 that was interfering with the image source

Why do my angular <img ng:src .../> behave different depending on the browser?

My angular page which I reduced to a to a minimal example here I tried three different ways to show the same img (just a red rectangle) in the "img"-Page:
The first image uses the XML-Style Parameter "ng:src" to specify the file location.
The second image uses the "ng-"-Prefix style
The third image just uses the src attribute (which I thought will probably not work well (the documentation here says that as well).
In Firefox all three images are displayed just fine.
In Opera the page shows only the later two images.
Chromium refuses to even load the page at all (it says "Error: An invalid or illegal string was specified." on the console). (It works if I remove the XML-Style img).
Why is this happening? Since I believe in XML my preference would be to get the XML-Style Parameter to work in all browsers. Note that I don't care about Internet Explorer.
Archive with my (broken) project: http://cipher-code.de/tmp/angular.zip
The XHTML spec outlines this algorithm that Chrome does not implement fully. Chrome returns the error you observe when the XML is not well formed, which is true when the following step in the algorithm is not followed:
If there is a context element, feed the parser just created the string corresponding to the start tag of that element, declaring all the namespace prefixes that are in scope on that element in the DOM, as well as declaring the default namespace (if any) that is in scope on that element in the DOM.
The result of not following this step means you have to set xmlns:ng on the root element of the fragment you are appending (or technically, any element or parent thereof that uses the ng namespace)
Edit after further discussion in comments: element.setAttribute on Opera doesn't do anything if the attribute doesn't exist. AngularJS has a compatibility fix for this for Internet Explorer. Enabling this fix for Opera solves the issue on Opera as well. A bug is issued with AngularJS here. Internet Explorer and Opera seem to misinterpret the spec on this.
Chrome appears to be quite strict when injecting fragments of XML into an XML document, with regards to namespaces. Your partial of images
<section>
<h1>Img</h1>
<p>With ng:src: <img ng:src="{{img}}" /></p>
<p>With ng-src: <img ng-src="{{img}}" /></p>
<p>With src: <img src="{{img}}" /></p>
<p>As link: Go to img</p>
</section>
is using the ng namespace, but it's not declared. The following fixes it in Chrome
<section xmlns:ng="http://angularjs.org">
<h1>Img</h1>
<p>With ng:src: <img ng:src="{{img}}" /></p>
<p>With ng-src: <img ng-src="{{img}}" /></p>
<p>With src: <img src="{{img}}" /></p>
<p>As link: Go to img</p>
</section>
Alas not sure why it then doesn't work in Opera.
Edit:
After a bit more testing, it looks like Opera can't quite cope with attributes src and ng:src on the same element. A solution is to roll your own ngSrc directive, called something like myImgsrc,
myModule.directive('myImgsrc', function() {
return {
link: function(scope, element, attrs) {
attrs.$observe('myImgsrc', function(src) {
attrs.$set('src', src);
});
}
}
});
Used as:
<img my:imgsrc="{{img}}" />
(Remembering to properly declare the namespace xmlns:my="http://mydomain.com" in both the document and the partial, so as not to break Chrome)

Resources