6

When viewing a raster image, all more or less recent Mozilla products (e. g.: Firefox and SeaMonkey) transform it into a full HTML document, e. g.:

<html>
  <head>
    <meta name="viewport" content="width=device-width; height=device-height;">
    <link rel="stylesheet" href="resource://gre/res/ImageDocument.css">
    <link rel="stylesheet" href="resource://gre/res/TopLevelImageDocument.css">
    <link rel="stylesheet" href="chrome://global/skin/media/TopLevelImageDocument.css">
    <title>googlelogo_color_272x92dp.png (PNG Image, 544&nbsp;×&nbsp;184 pixels)</title>
  </head>
  <body>
    <img src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" alt="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png">
  </body>
</html>

The content of the default CSS styles can be viewed here:

The problem is, on HiDPI displays, low-resolution images often get up-scaled (for instance, on a 4k display they're enlarged by a factor of x1.5).

Which extra styles do I need to apply to the generated HTML in order for images to be always displayed in their original size (i. e. 1:1)?

I'm looking for the proper way to customize either userContent.css or userChrome.css.

More on userChrome.css:

jhpratt
  • 6,841
  • 16
  • 40
  • 50
Bass
  • 4,977
  • 2
  • 36
  • 82
  • Why dont you use inline styling `style="width: 200px;height: 50px;` – Ashwin Geet D'Sa Jul 19 '19 at 13:45
  • @AshwinGeetD'Sa Because I want the CSS to be generic, suitable to viewing **any** image. – Bass Jul 19 '19 at 21:15
  • Is this an issue only in Firefox? If not, it should be relatively easy to fix with CSS. – jhpratt Jul 20 '19 at 00:32
  • @jhpratt my question is exactly about how this can be fixed with pure CSS, but in a size independent way (i. e. the one which allows to fix it once and for all). – Bass Jul 20 '19 at 13:00
  • Looking into this a bit more, it's definitely possible to do in CSS _to an extent_, but it would require an exhaustive list of DPIs / pixel ratios. A tiny bit of JS could solve this if you're willing to accept such a solution. – jhpratt Jul 20 '19 at 17:34
  • check `style="width: 100%; height: auto;"` – doc-han Jul 20 '19 at 19:11
  • I don't have 4k display, so I tried to reproduce it with latest Firefox and device emulation. No success. Also I don't see anything in browser CSS which could affect image width/height. Could you please check that you zoom level set to normal? Also check for browser extensions – Evgenii Malikov Jul 22 '19 at 20:10
  • @Doc-Han Thanks, I've already seen [the corresponding answer](https://stackoverflow.com/a/24198922/1343979), but if an `` element is a direct child of the `` (which is the way _Mozilla_ displays images), the image gets scaled up to fill the whole body area. Which is even worse. – Bass Jul 23 '19 at 17:20
  • @jhpratt Thanks, I appreciate your effort, but, as stated above, I do need a pure CSS solution. If I could use JavaScript, I would've come up with my own solution already. – Bass Jul 23 '19 at 17:22
  • @EvgeniiMalikov Since you don't have any 4k display, no wonder you can't reproduce the behavior I've described. It's a 4k-only feature. – Bass Jul 23 '19 at 17:25
  • Unfortunately, using CSS will limit you to specific DPIs, I'll certainly give you an answer in a bit using some of the more common DPIs (like 1.5, 1.6, 2). – jhpratt Jul 23 '19 at 21:31

3 Answers3

4

As you've indicated you are solely interested in a CSS solution, I will not be including a JavaScript alternative.

Using CSS only will inherently restrict you to an enumeration of DPIs, as CSS doesn't support any way to get the device pixel ratio. In the future, there may be an environment variable set, though I'm not aware of any such proposal.

In my approach, I've opted to use min-resolution over resolution, as this will at least select something close if the exact DPI isn't matched. For this to work, you must not be setting the width property of the img elsewhere. height will be automatically calculated, as is the default behavior.

@media (min-resolution: 1.5dppx) {
  img {
    transform: scale(calc(1 / 1.5), calc(1 / 1.5));
  }
}

@media (min-resolution: 2dppx) {
  img {
    transform: scale(calc(1 / 2), calc(1 / 2));
  }
}

@media (min-resolution: 2.5dppx) {
  img {
    transform: scale(calc(1 / 2.5), calc(1 / 2.5));
  }
}

@media (min-resolution: 3dppx) {
  img {
    transform: scale(calc(1 / 3), calc(1 / 3));
  }
}
<meta name="viewport" content="width=device-width; height=device-height;">
<link rel="stylesheet" href="resource://gre/res/ImageDocument.css">
<link rel="stylesheet" href="resource://gre/res/TopLevelImageDocument.css">
<link rel="stylesheet" href="chrome://global/skin/media/TopLevelImageDocument.css">

<img src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" alt="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png">

I've only included a few here, but the general idea is pretty straightforward — scale the image down by the same amount the browser is scaling it up.

If Sass is your thing, there's a simple way to loop over your supported DPIs and generate the resulting code. A similar result can be obtained in PostCSS with a couple plugins.

$resolutions: 1.5 2 2.5 3

img
  @each $res in $resolutions
    @if $res != 1
      @media (min-resolution: #{$res}dppx)
        transform: scale(1 / $res, 1 / $res)
jhpratt
  • 6,841
  • 16
  • 40
  • 50
  • Thanks, this approach works, with the only drawback that the image gets scaled up to occupy the whole rectangle of the immediate parent element (`

    `). In other words, I need 100% of the image width, **not** 100% of the `body` element (which tends to be the width of the browser window). How do I fix that? **Update:** I've experimented with `object-fit: none`, but I can't yet confirm this latter won't mess up the scaling.

    – Bass Jul 24 '19 at 09:33
  • Managed to achieve partial success by using `transform: scale(0.5, 0.5);` instead of `width: calc(100% / 2);` for `2dppx`, have to further test it. – Bass Jul 24 '19 at 09:52
  • 1
    @Bass using `scale` should work as expected, at least off the top of my head. – jhpratt Jul 24 '19 at 10:50
1

CSS has no way to use physical pixels instead of CSS pixels corresponding to pixel density (devicePixelRatio). The only way to prevent scaling of an image opened in a separate tab in Firefox is setting the image size dynamically via JS depending on devicePixelRatio and do this on each resize event.

Also, there is some implicit weird program logic that forces some things like cursor changes (similar — apparently hard-coded — logic sets the title of the image-view page). So the only way to get rid of this weirdness is cloning the image, hiding the original image, and dealing with the cloned copy instead. But such cloned copy is affected by so called Content Security Policy and might not be displayed at all — this is the case with e.g. user avatars on GitHub.

Marat Tanalin
  • 13,927
  • 1
  • 36
  • 52
1

There is an extension called Viewhance which implements this functionality. It is hidden behind an undocumented setting.

To tritter the switch, one needs to open the extension's configuration parameters, change to the Option/Info tab and enter {"scaling": "*"} prior clicking Import. (source)

Images will then be displayed at the native resolution.

almereyda
  • 96
  • 4