Tom
Tom

Reputation: 8127

Why is my device resolution / devicePixelRatio not equal to my CSS' viewport width?

My device (Macbook Pro 2019 16") has a resolution of 3072 x 1920. When entering the realm of CSS, pixel units are "normalized". From my understanding, each CSS pixel is equal to my window.devicePixelRatio in device pixels. In my case, window.devicePixelRatio === 2. If my understanding is correct, this would mean that a CSS grid column with a width of 3072 / 2 = 1536px should take my entire viewport width. Surprisingly this is not the case: the actual viewport with is 1792px.

If I divide my screen width by the viewport width, this gives me a "real" device to css pixel ratio of 3072 / 1792 = 1.7142857142857142. Why is this not returned by window.devicePixelRatio?

To make matters more confusing, when I take a screenshot with Chrome's API, it gives me a screenshot with width 3584px. Weirdly, all these numbers somehow seem to come together: (3584px * 1.7142857142857142) / 2 = 3072px which is my real device width. How does this make sense?

Finally, is there a way to get to 1.7142857142857142 programmatically?

Upvotes: 5

Views: 1322

Answers (2)

nd.
nd.

Reputation: 8932

Display Scaling

What you are seeing are the effects of Apple's Display Scaling concept.

For High Resolution (Retina) screens, macOS allows you to set an effective screen resolution that is different from the native 2× scaling.

For example, for the Macbook Pro 2019 there are 5 possible values in macOS 13.5 (I am using the same model):

  • Larger Text 1152×720
  • (unnamed) 1344×840
  • (unnamed) 1536×960
  • Standard 1792×1120
  • More Space 2048×1280

The native resolution of the display is 3072×1920, meaning that the middle setting of 1536×960 is the native 2× resolution.

The display pipeline is as follows:

  1. The view is rendered at the selected resolution using a 2× scaling factor - this is the value that you get via window.devicePixelRatio
  2. If the display has a different resolution than the rendered view (i.e. at any setting except 1536×960), then the view gets scaled to the native resolution.
  3. The resulting view gets displayed

It is true that the native 2× resolution is crisper than the scaled variants, but the tradeoff is that there is more space on the higher settings.

On the current generation MacBook Pros (2023), the Standard value is a native 2× resolution, but the default for MacBook Airs remains a scaled resolution.

Accessing native resolution via API

For iOS/macOS Catalyst, UIScreen.nativeScale can be used to get the real scale factor – the Display Scaling technique is also used on the Plus models of iPhone 6-8 for 3× scaling

On macOS, I haven't found a documented API to get the native scaling factor directly, but there are workarounds using Core Graphics APIs.

I am not aware of any official API to get the native resolution of the display in CSS. If you are working with grid layouts, this shouldn't be an issue, just stick to the scaled resolution, this will result in something that the user expects.

Upvotes: 1

deepanshu223
deepanshu223

Reputation: 965

This is an interesting question, I ended up in a rabbit hole about pixels and displays.

So, the inconsistency you noted appears due to the way Mac handles scaled resolutions. Basically on a Macbook, the value of window.devicePixelRatio isn't reflected exactly and shows either 1 or 2 for the different screen resolutions.

Take a look at this bug thread for chromium where the same issue is being discussed.

Also, the 1792px viewport you noted is due to the screen resolution for the specific Macbook model you mentioned, lists the resolution 1792x1120 as a supported resolution, which I assume you are on.

I also tested this on my Macbook and saw the same results all the scaled resolutions gave me a devicePixelRatio of 2, and had to go to all resolutions where I got 1

Scaled resolutions show same device ratio

Non-Scaled resolutions show same device ratio

As far as trying to programmatically identify the exact screen resolution and scaling, I don't think that would be possible in the web.

Upvotes: 0

Related Questions