Search code examples
cssmedia-queriesstandards

Can we map inches on screen CSS accurately now?


All right. This is an old one, but fun.

I know that we have 1in physical unit mapped to 96px on screen dpi. This mapping comes from way back in the 90s when monitors/screens used to be of a much lower resolve. That was a different time. Web was 'desktop only' utility then and as one would suspect implementations today haven't kept pace with the new landscape of the web.

Circa 2020.

I want to declare a css variable --inch at the :root of my webpage and map it to absolute inches for different devices using media queries. I can do that on the devices that I currently own, like so:

/* css */
:root {
   --inch: 130px; /* this value is from my Macbook Pro 2017 for example. */
}

.square {
  width: var(--inch);
  height: var(--inch);
  background: red;
}

And then with a ruler I measured the dimensions of the square on the screen. I even made a codepen for this to test and compare absolute inch with the in unit supported by your browser/machine.

Now. How should we go about setting --inch variable across mobile, watchos, iPads, desktops and if possible TVs and projectors as well?


UPDATE 1: Nailed the scope a little bit.

The following media-queries cover the wide selection of screens available on market. This list is from 2013 (credits) and may not be exhaustive but could be improved upon:

@media only screen and (min-width: 320px) {

  /* Small screen, non-retina */

}

@media
only screen and (-webkit-min-device-pixel-ratio: 2)      and (min-width: 320px),
only screen and (   min--moz-device-pixel-ratio: 2)      and (min-width: 320px),
only screen and (     -o-min-device-pixel-ratio: 2/1)    and (min-width: 320px),
only screen and (        min-device-pixel-ratio: 2)      and (min-width: 320px),
only screen and (                min-resolution: 192dpi) and (min-width: 320px),
only screen and (                min-resolution: 2dppx)  and (min-width: 320px) { 

  /* Small screen, retina, stuff to override above media query */

}

@media only screen and (min-width: 700px) {

  /* Medium screen, non-retina */

}

@media
only screen and (-webkit-min-device-pixel-ratio: 2)      and (min-width: 700px),
only screen and (   min--moz-device-pixel-ratio: 2)      and (min-width: 700px),
only screen and (     -o-min-device-pixel-ratio: 2/1)    and (min-width: 700px),
only screen and (        min-device-pixel-ratio: 2)      and (min-width: 700px),
only screen and (                min-resolution: 192dpi) and (min-width: 700px),
only screen and (                min-resolution: 2dppx)  and (min-width: 700px) { 

  /* Medium screen, retina, stuff to override above media query */

}

@media only screen and (min-width: 1300px) {

  /* Large screen, non-retina */

}

@media
only screen and (-webkit-min-device-pixel-ratio: 2)      and (min-width: 1300px),
only screen and (   min--moz-device-pixel-ratio: 2)      and (min-width: 1300px),
only screen and (     -o-min-device-pixel-ratio: 2/1)    and (min-width: 1300px),
only screen and (        min-device-pixel-ratio: 2)      and (min-width: 1300px),
only screen and (                min-resolution: 192dpi) and (min-width: 1300px),
only screen and (                min-resolution: 2dppx)  and (min-width: 1300px) { 

  /* Large screen, retina, stuff to override above media query */

}

UPDATE 2:

The following clause handles pixel to --inch mapping for all retina MBPs of 2017, for example.

@media (resolution: 192dpi) and (-webkit-device-pixel-ratio: 2) {
  :root {
    --inch: 130px;
  }
}

.square {
  width: var(--inch);
  height: var(--inch);
  background: orangered;
}

Where the --inch variable implies real physical inch to measure. Notice that we are not using min/max on media-queries to fit in a range of screen dpis here. This mapping is exactly for MBP'17 only with a returned dpi of 192 and dpr of 2.


Solution

  • It is possible to map css pixels to real physical inches now. It is cumbersome, obviously, but possible. To do this, we will use CSS custom properties that are otherwise known as CSS variables, like so:

    /* 13.3-inch MBP (2012) (1280 x 800) */
    @media (resolution: 96dpi) and (device-width: 1280px) {
      :root {
        --inch: 116px;
      }
    }
    
    /* 17" Retina MBP/Chrome values */
    @media (resolution: 192dpi) and (device-width: 1680px) {
      :root {
        --inch: 130px;
      }
    }
    
    /* Windows 10 @100% (1366 x 768) landscape*/
    @media (resolution: 96dpi) and (device-width: 1366px) {
      :root {
        --inch: 114px;
      }
    }
    
    /* Windows 10 Pro @100% (1920 x 1080px) landscape. */
    @media (resolution: 96dpi) and (device-width: 1920px) {
      :root {
        --inch: 144px;
      }
    }
    
    /* Windows 10 Pro @125% (1920 x 1080px) landscape. */
    @media (resolution: 120dpi) and (device-width: 1536px) {
      :root {
        --inch: 115px;
      }
    }
    
    /* 27" EIZO monitor (2560 x 1440)*/
    @media (resolution: 115dpi) and (device-width: 2560px) {
      :root {
        --inch: 92px;
      }
    }
    
    /****************/
    /* MOBILE ZONE */
    /****************/
    
    /* iPhone 11 Pro Max */
    
    @media (device-width: 414px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait) {
      :root {
        --inch: 370px;
      }
    }
    
    @media (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape) {
      :root {
        --inch: 189px;
      }
    }
    /****************/
    /* MOBILE ZONE */
    /****************/
    
    /* iPhone 11 Pro Max */
    
    @media (device-width: 414px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait) {
      :root {
        --inch: 370px;
      }
    }
    
    @media (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape) {
      :root {
        --inch: 189px;
      }
    }
    
    /* …and so on. */
    
    

    Hardware-specific mappings for all the major devices on the market or those you wish to support can be included at the root level of your application CSS. Then simply use var(--inch) on the stylesheets for layout, like so:

    /* Desktop instance */

    .heroBanner { width: 100%; height: calc(1/3 * var(--inch)); /* 1/3rd of an inch in height. */ }

    I have turned this idea into an open-source polyfill that covers some of the devices of the day. Feel free to fork and submit PRs to add newer --inch: pixels mappings if a device-browser combination isn't already covered. 🙏🏻