In the srcset attribute of img element in html, we can specify either the width or the pixel density of each source. We use w to specify width and x to specify pixel density. I have some questions about w and x.
Does 500w mean that the width of the image is 500 pixels? If so, why is it w and not px, as used when in the size attribute?
Does 1x means a pixel density of 72pixels/inch
Why does an image have pixel density? I thought pixel density means the number of pixels within a physical length/space. For example, the number of pixels per inch. But a digital image doesn't occupy a physical length/space, it only occupies a number of pixels. So what does the pixel density of a digital image mean?...This is my guess, please tell me if I'm right: An image only occupies a number of pixels, but it could have been intended for a physical length. For example, an image of a button of 144 pixels width was intended to occupy a physical space of 1 inch. Therefore, it was intended for a device of 2x. We tell the browser this by specifying 2x in the srcset attribute. To sum up, the pixel density means the pixel density of the system the image is intended for.
#1. The 'w' value that appears to the right of each file listed in the srcset attribute of the <img> tag is known as the "w descriptor." The value of each 'w' descriptor is the intrinsic width, in pixels, of the file the 'w' descriptor is associated with. "Intrinsic width" means the native width of the image when it is was originally created or the last time its width changed. You can view a file's intrinsic width in Photoshop or the Windows 10 Photo Viewer (click the three-dot menu "..." and select File Info). "px" is not used to describe intrinsic width because it is used to describe various other types of image widths. The 'w' descriptor describes a specific type of image width that is measured in pixels - intrinsic width - and is used only with the srcset attribute of the <img> tag.
#2. "1x" does NOT mean a pixel density of 72 pixels per inch. That's because pixel density is NOT device resolution. Pixel density is the ratio of browser image width in pixels (known as "CSS pixels") to the native pixel width of the device's display screen. Pixel density has nothing to do with device resolution.
#3. An image does NOT have pixel density. It has only two types of width measurements - both in pixels. One width measure is the width the browser is displaying the image at. The other width measure is the intrinsic width of the image (see #1). For example, suppose I have an image whose intrinsic width is 800px wide. Also suppose that the browser is displaying the image at 650px wide. These two measures are not related in any way (this is NOT pixel density!) - they're just two different ways an image can be viewed which results in two different width measurements.
I've answered your questions directly, without any other context or explanation, and I'm certain that you are scratching your head saying, "That didn't help!" That's the exact same reaction I had when I first started to educate myself about how inline images (images that are specified with the <img> tag in HTML) are selected and displayed by browsers. I suggest you read this post to begin to gain a thorough understanding about how inline images are specified in HTML markup and how browsers select the appropriate image from the srcset attribute of the <img> tag. You can expect several weeks of study before this topic comes into sharp focus. And when you've finished mastering inline images, background images are waiting for you to master with a completely different set of rules. :>)
Related
I have an image that gets displayed in various sizes on my website:
The website is responsive and the apparent image size is often the size of the browser, with some exceptions when the browser is very wide. So, the image's width can vary between 200 and over 1000 pixels.
We want the image to be displayed in native resolution on high-resolution devices (Retina).
So, our image is present in three resolutions, let's call them i1.png, i2.png and i3.png.
What I would like to do is just this:
<img src="i1.png" srcset="i1.png 420w, i2.png 840w, i3.png 1260w" />
In my opinion, the browser should have enough information to figure out which image it needs.
On a standard-resolution device (no retina screen), it just takes the width of the <img /> element and then loads the image that has a width higher or equal to the width of the element. E.g. if the image element is 600px wide, then it will load i2.png.
On a retina device, it would just multiply the width of the <img /> element with the device-pixel ratio. E.g. on a "2x" device, it would load i3.png for a 600px image, because 2 x 600 = 1200, so it would need the image with a width of 1260px.
It seems the browser indeed does something like that, but in some cases it would load the 840px image even though the 420px image would be enough.
What factors does the browser use to determine the size of the image to load?
Is it using CSS rules to determine the image's apparent width?
Or does it ignore CSS and just look at width and height attributes on the <img />, if present?
What if some parts of CSS are not yet loaded?
Crucial point: I do not want to use the sizes attribute, because I would need media queries for all possible combinations of device-pixel ratios and browser window widths. This should not be necessary, because as I said, the browser should have enough information.
I checked the Mozilla Docs about the topic, but they say that if sizes is omitted, then we need to use 2x descriptors (instead of 420w descriptors) in the srcset attribute. This is useless for my scenario: the goal is to have the browser find out which image to load, not just based on device-pixel ratio, but also based on responsiveness.
Seems that the browser does not respect any CSS to decide which image to load. After all, it is not clear which CSS files have already been loaded when the image starts loading.
Instead, it treats each image as if it was stretched to the full page width. If the screen is non-retina and 600px wide, it would load the next-higher image size (840px in the above example), regardless of the actual size that the image would occupy on the screen.
For retina screens, it would just multiply the required image width by the device-pixel ratio.
This question presumes: device-pixels are absolute (fixed, not relative to anything).
Following reading this article,
My device (MacBook Pro 2019) has a pixel ratio of 2 (2 device pixels in every CSS pixel when zoom-level 100%; calculated by .devicePixelRatio). At 100% zoom-level, CSS pixels (as measured with .innerWidth) are the same as device pixels (as measured with screen.width & Cmd + Shift + 4 + click). I was expecting CSS pixels to be half the value of device pixels.
Why does MDN say CSS pixel is an absolute value when zooming in actually increases the size of a CSS pixel (by increasing the amount of device pixels it equals to)? Why is this in MDN?
In your case the scaling is done at the OS level, so everything will "lie" because your OS is set to lie to every applications, including the browsers.
The window.screen.width value will be the one reported by your OS, but in your system preferences, it says that you want the resolution of your display to be set to half of its real resolution, that's what you'll get.
So even these values are not device pixels, but some kind of CSS pixels (well window.screen.width is really 'CSS pixels', the one from the ScreenShot app isn't).
However, while "lying" about the number of pixels, it correctly exposes the pixel density (number of physical pixel used per px). That's what you'll have in window.devicePixelRatio when the browser doesn't apply any zoom by itself. Unfortunately, we don't know when the browser applies such a zoom, so as web-devs, we can't know the OS pixel density, nor the true resolution of the device.
As for the second point, I will assume you asked why MDN says CSS pixels are absolute rather than relative as written in your question.
This doesn't mean that a CSS pixel will always have the same physical dimension outputted (which is impossible btw, think of a video-projector), it's in contrast with relative lengths like %, em, vw, etc. which are relative to an other length.
CSS pixels are absolute in that they don't rely on any other length, even though the physical output may vary.
Say I have the following image:
<img src="//picsum.photos/100" srcset="//picsum.photos/100 100w">
It appears that the sizes attribute I have not included defaults to 100vw, hence the small image is upscaled to the width of the viewport.
What do I do if I don't want this behavior, but instead want the image to default to its intrinsic size?
I would expect that this image would default to 100px in width on a normal display, and 50px on a 2x (retina) display.
If I specify my own sizes attribute of 100px, this doesn't solve the problem of displaying it at 50px when on a retina display.
The reason I need this behavior is because in my system users are allowed to upload images of any size and place them on a page, and I am generating an srcset with multiple steps up to the max size of their image, and I need a way for the image to display at the correct width given the size of the image and the pixel density of the user's screen.
Can this behavior for auto-width images be achieved using srcset?
In my research I've found this article which addresses the issue directly. The author recommends adding the width attribute with the maximum size of the image to revert what the sizes attribute does to the image's intrinsic size. However, he does not address how to make this work with differing pixel densities.
Unfortunately it seems there isn't a way to have an image with srcset default to its natural size, taking DPR into account. The sizes attribute, which defaults to 100vw if not set on an image with srcset, redefines the image's intrinsic width, and there doesn't seem to be a way to reset it without providing an explicit width yourself.
In my specific situation I discovered that we were already storing the user's DPR in a cookie, so server-side I've started setting the width attribute on images to the max width of the image divided by the user's DPR. This prevents the image from being displayed larger than the original size, and ensures that the image is sized appropriately for devices with high pixel densities.
Of course, you'll probably want to combine this with max-width: 100%; in your CSS to prevent the image from displaying larger than its container.
Example solution:
<!-- Width generated server-side for standard displays: -->
<img src="//picsum.photos/100" srcset="//picsum.photos/100 100w" width=100>
<!-- Width generated server-side for displays with a DPR of 2: -->
<img src="//picsum.photos/100" srcset="//picsum.photos/100 100w" width=50>
I have written a JavaScript filler to implement srcset, but I need to clarify the specified behaviour.
While srcset allows you to specify conditions for width or resolution, I can’t work out whether it is OK to specify both. For example:
<img src="images/oh1x408.jpg"
srcset="images/oh1x192.jpg, images/oh1x408.jpg 420w,
images/oh2x192.jpg 2x, images/oh2x408.jpg 2x 420w">
This is supposed to cover single and double resolutions, and smaller and wider screens.
I have seen no examples where both the width and resolution are specified. The question is:
Is the last image in the srcset example above within specs?
Is anything else in the example incorrect?
Thanks
No, you can only specify one of both. It seems, that you don't understand how the width descriptor works. As soon as you use the width descriptor, you won't need the x descriptor anymore.
Here is a example:
<img srcset="img-300.jpg 1x, img-600.jpg 2x" />
The above example can be also described with the width descriptor, it would look something like this:
<img srcset="img-300.jpg 300w, img-600.jpg 600w" sizes="300px" />
srcset is all about resolution switching (no art direction). While the density descriptor can only handle static width images, the width descriptor can also handle adaptive images using the sizes attribute. The width descriptor describes the width of each image candidate in physical pixels, the sizes attribute describes the (different) width(s) of the image in layout pixels.
Here is a more complicated example:
<img srcset="img-300.jpg 300w, img-480.jpg 480w, img-720.jpg 720w" sizes="(min-width: 480px) 400px, 100vw" />
The example above says we have 3 candidates one with a width of 300, another with 480 and last with a width of 720 pixels, additionally the image is displayed at 400 pixels if the viewport is min-width: 480px otherwise it is displayed at the full viewport width (100vw).
The browser then automatically calculates the width according to your sizes attribute. For example, if you are looking with a 360px wide device the sizes 100vw is taken (because it is lower 480px) and computed to 360px layout pixel. Then the browser calculates the density of each candidate by division: width descriptor / calculated size):
300 / 360 = 0.83
480 / 360 = 1.34
720 / 360 = 2
And then the browser chooses the best candidate for the device depending on the pixel ratio of your device. So it takes the 480 wide image on a 1x device and the 720 wide image on a 2x device.
And as you see, you don't need to use density descriptor anymore. The density descriptor is simply a shorter version.
And yeah, there is already a polyfill handling this just fine.
No, both is not allowed. The srcset spec says that the attribute is made up of image candidate strings, separated by commas, and that each such string has
Zero or one of the following:
A width descriptor, consisting of: a space character, a valid non-negative integer giving a number greater than zero representing
the width descriptor value, and a U+0077 LATIN SMALL LETTER W
character.
A pixel density descriptor, consisting of: a space character, a valid floating-point number giving a number greater than zero
representing the pixel density descriptor value, and a U+0078 LATIN
SMALL LETTER X character
From my experience up to now the pixel size is something very relevant and intepreted differently based on many factors. My question is how do pixels work in html pages.
For example we can set the width and height of an image:
<img src="lalala.jpg" width="100px;" height="100px;">
What does 100 pixels actually mean?
How are the 100 pixels translated on screen?
How are the 100 pixels translated if on print papper?
To be more specific. If I set the image size to 100px then is it going to be the same size in inches on different screen sizes ? Ad if so..Is it going to be the same size if I print the same page while using a different screen size?
In HTML, pixel lengths of the height and width attributes are controlled by CSS. In some instances, these are refereed to as "CSS pixels". HTML itself does not provide a definition for what a pixel should represent (thus why I added the css tag into your question).
CSS itself has its own Units and Values documentation which defines the Pixel in its section on Absolute Lengths:
5.2. Absolute lengths: the ‘cm’, ‘mm’, ‘in’, ‘pt’, ‘pc’, ‘px’ units
The absolute length units are fixed in relation to each other and anchored to some physical measurement. They are mainly useful when the output environment is known. The absolute units consist of the physical units (in, cm, mm, pt, pc) and the px unit:
unit definition
---- ----------
‘cm’ centimeters
‘mm’ millimeters
‘in’ inches; 1in is equal to 2.54cm
‘px’ pixels; 1px is equal to 1/96th of 1in
‘pt’ points; 1pt is equal to 1/72nd of 1in
‘pc’ picas; 1pc is equal to 12pt
100 pixels is equal to roughly 1.041in, which itself is equal to roughly 2.65cm.
I'm not going to answer the further questions you've asked about different monitors and printing as this would make my answer incredibly long and dull. If you want to find out these answers yourself, a good place to start is in the same document I've already linked, which goes into detail about the Reference Pixel. Values in CSS are based upon a value of 96dpi (which means that 96 pixels on a monitor which has a pixel dencity of 96dpi will be equal to one inch if you were to measure it with a ruler).
Because every screen has diferent pixel size HTML/CSS or whatever software language is going to be made never gonna match the physical pixel size.
To calculate pixel size you need Hardware machine language not software.