can't get NgOptimizedImage to be responsive in Angular 15 - html

In an Angular 15.1.x project, i'm trying implement an image that is responsive on mobile and desktop using NgOptimizedImage. The mandatory img width and height attributes are overriding the sizes attribute.
<img ngSrc="image.png" width="617" height="505" sizes="(max-width: 768px) 276w, 317w">.
According to the docs, this should mean if viewport 768px or less image width should display 276px wide otherwise 317px. I'm using the intrinsic for width/height as per docs. The image always shows at whatever the width/height attribute is (617px X 505px).
Essentially i'm trying to achieve this but using ngSrc:
<img src="image.png" srcset="img.png 617w" sizes="(max-width: 768px) 276px, 317px" >

Related

How To Serve Image Size Based on Container, Not Screen Size

I've been scouring responsive image posts and examples, but I can't find a solution. It seems like this should be easy, I might just be missing something: How would I serve the appropriate image size based on container width rather than screen width?
I.e. I have a desktop screen, 1980px wide, but a flex container that's 1/3 of the screen, so the max image size would only need to be 660px wide, so it should show the 800w image. But srcset will only go off of the screen size, so even if I'm displaying thumbnails, it will load the 1200w image. Is there a way to do this dynamically. i.e. still use flebox and dynamic widths, but have it serve the appropriate size based off of container width not screen width? Any help would be greatly appreciated, thanks!
<div class="flex justify-center w-1/3 mx-auto">
<img
srcset=" srcset="size-1.jpg 400w,
size-2.jpg 800w,
size-3.jpg 1200w,"
sizes=" (min-width: 1200px) 1200px, (min-width: 800px) 800px, 400px"
/></div>
You could mathematically describe how big the image would be displayed inside the sizes attribute. You can use calc() to achieve more complex calculation, for example if there is margin between your images and you want to be precise or if the container is not full width.
Example without calc():
<div class="flex justify-center w-1/3 mx-auto">
<img
srcset="size-1.jpg 400w,
size-2.jpg 800w,
size-3.jpg 1200w"
sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 33.33vw"
/>
</div>
Example with calc():
<div class="flex justify-center w-1/3 mx-auto">
<img
srcset="size-1.jpg 400w,
size-2.jpg 800w,
size-3.jpg 1200w"
sizes="(max-width: 600px) calc(100vw - 30px), (max-width: 1200px) calc(50vw - 30px), calc(33.33vw - 30px)"
/>
</div>
Why do you want to use 3 different source files? Are they just different sizes of the same image or do you have completely different images you want to show on each container size?
If all you want is for the picture to fit its container you can handle that by just setting one source file and using the CSS property width: 100% Pixels get translated into a unit of distance like inches*. By setting the width of the image in units of % it automatically sizes the image relative to the width of its parent element, in your case the <div>.
There are other units you can use for width besides % and px. Check out this article Viewport Units.
If you actually want to use three different images depending on container size then you will need to have all three sources listed as you currently do.
This article should help: Responsive Images
This excerpt from it in particular:
<img
sizes="(min-width: 400px) 80vw, 100vw"
srcset="examples/images/small.jpg 375w,
examples/images/big.jpg 1500w"
alt="…"
>
The information in the markup above gives the browser what it needs to figure > out the best image for it. The browser knows 1) it’s own viewport size and 2) > it’s own pixel density.
Perhaps the browser viewport is 320px wide and it’s a 1x display. It now also
knows it will be displaying this image at 100vw. So it has to pick between
the two images provided. It does some math.
375 (size of image #1) / 320 (pixels available to show image) = 1.17
1500 (size of image #2) / 320 (pixels available to show image) = 4.69
1.17 is closer to 1 (it’s a 1x display), so the 375w image wins. It’ll try to > not go under, so 1.3 would beat 0.99, as far as I understand it.
* Technically pixels are a measure of an angle, like degrees and radians, and are based on an assumption about the distance the screen is being viewed from.

How to use HTML img srcset in fluid layout?

I have a web page design where the layout size and image sizes are based on em's. For example:
<html style="width:50em; font-size:16pt">
<body>
<p>Lorem ipsum
<img src="..." style="float:right; width:20em">
</p>
</body>
</html>
Because the image size is specified in em's, it is always in lockstep with the text size. Unfortunately, we don't know how many CSS pixels wide an image is. We also don't know how many device pixels wide an image is, which depends on the size of an em, the magnification, etc.
The <img> srcset and sizes attributes appear to be nearly the solution I want. But I'm not sure if it applies to my situation here. I can generate multiple asset sizes, e.g. 320×240, 480×360, 640×480, etc.
I want the web browser to look at the content box for the <img> element, calculate how many device pixels wide it is, and download the most appropriate image from a list of alternatives. How can I do this?
Note: I did read about the srcset x syntax, but it doesn't seem to be the right tool.
Srcset is definitely a great way to approach this. You basically have a number of images you save out for multiple sizes, usually you'll want to have the image be the same width of the element if possible. Then you set the image that you want to use for each screen width.
<img src="image.jpg" alt="Name"
srcset="
/img-2400.jpg 2400w,
/img-1800.jpg 1800w,
/img-1200.jpg 1200w,
/img-900.jpg 900w,
/img-600.jpg 600w,
/img-400.jpg 400w"
sizes = "(min-width: 2400px) 900px,
(min-width: 1800px) 600px,
(min-width: 1200px) 500px,
(min-width: 900px) 500px,
(min-width: 600px) 600px,
400px" />
So /img-2400.jpg 2400w would use /img-2400.jpg when the screen is closest to 2400px wide.
In the sizes attribute, you can also specify if what the image size will be at certain screen sizes as it may not always be 100% of the width of the browser.
So (min-width: 2400px) 900px is telling the browser that when the window is at least 2400px wide, the image will be 900px wide on the screen. So that should be telling the browser to then grab /img-900.jpg when the window is 2400px wide since that image is set to 900w which is the closest to 900px (its exact).
You can still approximately calculate this if you are using em, by multiplying the em you are using by 16 (this may vary depending on browser settings or settings you impose in your css). So if you set your width of an image in css to be 20em, thats 16 * 20 = 320px.
When these are used in combination, modern browsers should be able to detect the best image to grab dependent on the screen size. See browser compatability for srcset here: https://caniuse.com/#search=srcset
Based on Eric Portis's article, this solves the problem:
<img style="width:20em" sizes="20em"
src="pic-1000.png"
srcset="
pic-150.png 150w,
pic-220.png 220w,
pic-330.png 330w,
pic-470.png 470w,
pic-680.png 680w,
pic-1000.png 1000w">
After the web page is loaded, if the most appropriate image changes for some reason (e.g. using zoom to change the device pixel ratio), then Firefox will always change the image to the most appropriate one at the moment. By contrast, Chrome seems to change the image if the new one is bigger, but won't change to a small image unless you reload the page - the image resolution is sticky upwards.

Responsive image mapping does not work to scaled images

I use picturefill.js for responsive image feature. When I place original image without specifying height and width, image is shown in <picture> tag and pull up different size of same images according to screen size.
But when i specify height and width, responsive feature does not work. Image is loaded with <img> tag.
here is link
The documentation of the library explains you should manage the image size by using the sizes tag:
<img
sizes="(min-width: 40em) 80vw, 100vw"
srcset="examples/images/medium.jpg 375w,
examples/images/large.jpg 480w,
examples/images/extralarge.jpg 768w"
alt="…">
By defining a style with a width and height you are forcing the image to keep that aspect.
From the site:
The sizes syntax is used to define the spaces your image will occupy in your layout. srcset then defines a list of images and their inherent widths. This allows the browser to choose the smallest appropriate source for the size available in that part of the layout, rather than the viewport size alone.

srcset and viewport width

I have 2 images: one desktop version, one mobile version.
I would like the desktop image to be replaced by the mobile image when the viewport width resizes below 480px, just as would with the following CSS with background-image property :
.logo { background-image: url(http://placehold.it/400x200&text=desktop); }
media screen and (max-width: 480px) {
.logo { background-image: url(http://placehold.it/300x150&text=mobile); }
}
I thought I could achieve this with the srcset HTML attribute :
<img src="http://placehold.it/400x200&text=desktop" alt="" srcset="http://placehold.it/300x150&text=mobile 480w">
But it does not work, the browser shows the mobile image all the time and rescales it on viewport resize, but I wish the 2 images remains in their respective original size.
Is it possible to achieve this behavior with srcset?
It sounds like you want to do "art direction", i.e. the images are different more than just the smaller being scaled down version of the bigger image. If so, you need to use the picture element.
<picture>
<source srcset="http://placehold.it/300x150&text=mobile"
media="(max-width: 480px)">
<img src="http://placehold.it/400x200&text=desktop" alt="...">
</picture>
However, if your small image is actually a scaled-down version of the bigger image, then you can use srcset, but then you have no control over which image gets chosen. It's up to the browser to pick the best one based on screen density, network conditions, user preference, browser cache, etc.
<img src="http://placehold.it/400x200&text=desktop"
srcset="http://placehold.it/400x200&text=desktop 400w,
http://placehold.it/300x150&text=mobile 300w"
sizes="(max-width: 480px) 300px, 400px">
Note: If srcset is used and the larger image candidate is in cache, Chrome will always display this cached image candidate - no matter of the actual viewport size.

Correct sizes attribute for img with srcset in a fluid, padded, media-queried container?

I'm trying to implement the new srcset attribute for <img> and I've run into some edge cases that are not working or I'm missing something.
I'm using the picturefill 2.1.0 polyfill, and I've read some articles like http://ericportis.com/posts/2014/srcset-sizes/ or https://html.spec.whatwg.org/multipage/embedded-content.html#embedded-content.
I get the idea of very simple examples, e.g:
<img
src="small.jpg"
srcset="
small.jpg 100w,
medium.jpg 200w,
large.jpg 300w
"
sizes="100vw"
>
The browser loads small.jpg, medium.jpg or large.jpg depending on screen size, pixel density, zoom and other factors. It may load medium.jpg for a 200px simple screen or a 100px hdpi(2x) display. So far so good.
The problem relies on the sizes attribute. In the previous example we are telling the browser that the picture takes up the whole (100%) viewpoint width (vw).
The project I'm working in uses Foundation, which has fluid, em-padded grids that may have more or less columns based on screen sizes (media queries).
Let's say, for instance, that we want a grid in which small screens have 2 columns, and medium screens (min-width: 40em) 4 columns. Every column contains an image. What would be the correct sizes keeping in mind that each column is width-fluid and has a padding defined in ems?
<ul class="small-block-grid-2 medium-block-grid-4">
<li>
<img
src="small.jpg"
srcset="
small.jpg 160w,
medium.jpg 320w,
large.jpg 480w
"
>
</li>
</ul>
sizes="(min-width: 40em) 25vw, 50vw"
sizes="(min-width: 40em) ???em, ???em"
sizes="(min-width: 40em) ???px, ???px"
The vw approach ignores the padding of the columns. The em or px approach ignores the fact that columns are fluid (and I'm not even sure which values should they have).
Any ideas?
Thanks in advance.
Well Foundation doesn't work like that, for the moment they are use javascript data-interchange to deal with the new attr srcset:
<img
data-interchange="[/path/to/default.jpg, (default)],
[/path/to/small.jpg, (small)],
[/path/to/retina.jpg, (retina)],
[/path/to/medium.jpg, (medium)],
[/path/to/bigger-image.jpg, (large)]"
>
<!-- or your own queries -->
<img
data-interchange="[/path/to/default.jpg, (only screen and (min-width: 1px))],
[/path/to/bigger-image.jpg, (only screen and (min-width: 1280px))]"
>
Using Interchange With Images
data-interchange="[image_path, (media query)], [image_path, (media query)]"
Using Retina Images
data-interchange="[image/path/to/retina.jpg, (retina)]"
Custom Named Queries
$(document).foundation('interchange', {
named_queries : {
my_custom_query : 'only screen and (max-width: 200px)'
}
});
In your case you could just make new custom Named Queries and pass it to your Img.