Skip to content
This repository has been archived by the owner on May 5, 2022. It is now read-only.

Preloading for HiDPI images (image srcset 2x) #31

Closed
Krinkle opened this issue Sep 4, 2015 · 14 comments
Closed

Preloading for HiDPI images (image srcset 2x) #31

Krinkle opened this issue Sep 4, 2015 · 14 comments

Comments

@Krinkle
Copy link
Member

Krinkle commented Sep 4, 2015

Currently prefetch and preload are insufficient to e.g. preload a website's logo or header graphic due to it being limited to a fixed url.

For example, Wikipedia specifies their logo in a stylesheet (with a high-res variant specified via media query). Right now the logo isn't fetched until after the browser has loaded the stylesheet and parsed the relevant page HTML that the rules apply to.

If it were an <img> tag it could use srcset and be seen by the look-ahead pre-parser (assuming the pre-parser supports srcset). Though that limits how the image can be used (due to limitations in CSS), and is still seen fairly late due to how Wikipedia body HTML is ordered (content is before nav sidebar). And using an image is impractical as it would require purging edge caches in order to effectively change the logo (as opposed to changing a stylesheet).

A preload instruction is relatively easy to add with an HTTP header.

@igrigorik
Copy link
Member

I don't think "fixed URL" is an issue here. If you're using CSS image-set or media queries then you already have different URLs for various resolutions. Also, the preload spec does indicate that the "right time to load the resource" is when there is a matching media query... So, you could do <link rel=preload media=MQ-here href=...> to indicate the right resource for each resolution.

@Krinkle
Copy link
Member Author

Krinkle commented Sep 4, 2015

I couldn't find any mention of a media attribute for the preload link. That's essentially what I was requesting here. I must've looked over that, it's right there in the spec. Thanks!

I assume it would support something like media="(min-resolution: 2dppx)", right? That means it'll require a second link tag (with negated query, for the 1dppx varant). It feels fragile to have to make them mutually exclusive by hand. A srcset-like way of providing a set of urls would be cleaner as it's guaranteed to select only one. E.g. /static/logo-1.png 1.5x, /static/logo-2.png 2x.

@yoavweiss
Copy link
Contributor

I agree that a srcset-like option could make sure that:

  • The browser would pick the same image as it would using srcset or image-set.
  • The browser has the freedom to "downgrade" the resource when bandwidth is constrained.
  • As a bonus: Authors don't have to "translate" from srcset to MQs

Potentially, we could also harness Client-Hints for that purpose, if Accept-CH is sent as a header. That (similarly to srcset) would require us to add a sizes equivalent.

One problem with responsive resource preloading as a Link: header is that viewport declarations (<meta content=viewport>) would be parsed after the browser have potentially sent the requests out. There currently no way for us to declare the viewport dimensions in the navigational response headers. We need one in order to address this.

@igrigorik
Copy link
Member

Personally, I don't think we want to introduce the srcset complexity at this point..

a) You can unroll srcset into multiple declarations with different media queries
b) If you don't want (a)'s complexity you're better of using Client Hints

I'm inclined to close this, any objections?

@yoavweiss
Copy link
Contributor

The problem with using media for this is the scenario of downgrading srcset/image-set due to bandwidth constraints, as that would result in a double download.
So, if this pattern is adopted widely, it'd mean browsers will no longer be able to "downgrade".

Client-Hints would be a better option, if we're just talking about the HiDPI scenario.

@igrigorik
Copy link
Member

@yoavweiss I'm not aware of any browsers that have taken advantage of the srcset/image-set downgrade.. yet, at least. FWIW, this may be a reasonable v2 feature, but for now I'd prefer to keep things simple.

@yoavweiss
Copy link
Contributor

I agree we haven't done anything with the "downgrade" possibilities yet, but am also afraid that enabling media without proper viewport mechanisms and srcset equivalent would prevent us from doing so in the future (and would do more damage than good).

I think that we should enable the current case using DPR, but delay media support until we have all the required mechanisms in place.

@igrigorik
Copy link
Member

I think that we should enable the current case using DPR

Agreed. You can use preload + Client Hints to get the desired behavior.

delay media support until we have all the required mechanisms in place.

FWIW, I don't think we should. Put the ~srcset use case aside (solved via DPR), and consider the typical stylesheet example where media queries are often critical -- e.g. load this stylesheet for this breakpoint, and that one if insert-other-MQ-here. We need media support to enable many use cases around preloading critical assets (JS, CSS).

@igrigorik
Copy link
Member

@Krinkle @yoavweiss I don't believe there are spec-related issues here. Can we close this? We can continue implementation discussions elsewhere (e.g. crbug).

@igrigorik
Copy link
Member

closing, please feel free to reopen if there is more to discuss here.

@Krinkle
Copy link
Member Author

Krinkle commented Apr 10, 2017

@igrigorik It appears there may be a missing component here that wasn't considered. Where in CSS, multiple media queries naturally cascade/de-duplicate, preload does not.

.mw-logo {
  background-image: url(/static/wikipedia.png);
  background-size: 135px auto;
}

@media (min-resolution:1.5dppx),(min-resolution:144dpi) {
  .mw-logo {
    background-image:url(/static/wikipedia-1.5x.png);
  }
}
@media (min-resolution:2dppx),(min-resolution:192dpi) {
  .mw-logo {
   background-image:url(/static/wikipedia-2x.png);
  }
}

The closest we've come up with is the following, which seems rather.. suboptimal.

Link: </img/logo.png>;rel=preload;as=image;media=(max-resolution: 1.4999dppx),
</img/logo-1.5x.png>;rel=preload;as=image;media=(min-resolution: 1.5ppx) and (max-resolution: 1.9999dppx),
</img/logo-2x.png>;rel=preload;as=image;media=(min-resolution: 2dppx)

Would there be a better way that doesn't involve .9999?

@Krinkle
Copy link
Member Author

Krinkle commented Apr 10, 2017

Was able to improve it slightly by using the not keyword to express < (less than) as not >=.

Although the middle image still has to use .9999 because there is only min/max inclusive (<= and >=, but no < or >) and it is not supported to have multiple conditions where only one is negated (can't express >= 1.5 and not >= 2).

Link: </img/logo.png>;rel=preload;as=image;media=not all and (min-resolution: 1.5dppx),
</img/logo-1.5x.png>;rel=preload;as=image;media=(min-resolution: 1.5dppx) and (max-resolution: 1.9999dppx),
</img/logo-2x.png>;rel=preload;as=image;media=(min-resolution: 2dppx)

(example code in PHP, https://gerrit.wikimedia.org/r/215061)

@igrigorik
Copy link
Member

Glad you got it to work 👍 There are definitely limitations to media via element attributes.. but those are also not restricted to preload, as we're reusing generic HTML plumbing.

@Krinkle
Copy link
Member Author

Krinkle commented Oct 30, 2018

For the record, this has been restarted at #120.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants