Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-mediaqueries] Expose User Preference Media Queries as HTTP Client Hint or HTTP Header #4162

Closed
tomayac opened this issue Jul 30, 2019 · 36 comments

Comments

@tomayac
Copy link
Contributor

tomayac commented Jul 30, 2019

Problem Statement

CSS media queries, and specifically user preference media features like prefers-color-scheme, have a potentially significant impact¹ on the amount of CSS that needs to be delivered by a page.

Focusing on prefers-color-scheme—but highlighting that the reasoning in this issue applies to other user preference media features as well—it is a best practice to not load CSS for the particular non-matching color scheme in the critical rendering path, and instead to initially only load the currently relevant CSS. One way of doing so is via <link media>.

However, high-traffic sites like Google Search that wish to honor user preference media features like prefers-color-scheme and that inline CSS for performance reasons need to know about the preferred color scheme (or other user preference media features respectively) ideally at request time, so that the initial HTML payload already has the right CSS inlined.

Potential Solutions

Client Hint

HTTP Client Hints defines an Accept-CH response header that servers can use to advertise their use of request headers for proactive content negotiation, colloquially referred to as "client hints" (demo, try it in a current version of Chrome). One such potential client hint that could help with the above scenario might be a tentatively titled Media-Feature hint, which would notify the server about, for example, the currently preferred color scheme.

  • Meta note 1:
    This is somewhat of the inverse of what is being proposed in [css-mediaqueries] Proposal: "prefers-reduced-data" #2370, where the Save-Data header is suggested to be exposed through a prefers-reduced-data media query.

  • Meta note 2:
    HTTP Client Hints as of draft 07 no longer includes the concretely supported client hints as it was still the case with 06, which is why I decided to file this here in the csswg-drafts repo.

  • Meta note 3:
    The Accept-CH-Lifetime header field was likewise removed in draft 07. This header would have enabled delivery of client hints on subsequent requests to the server's origin (and not just sub-resources).

New HTTP Header

Given the changes in Meta note 3, an alternative approach could be to introduce a whole new Media-Feature header (obviously likewise only a tentative name) rather (than a client hint), similar as what has happened with Save-Data, which up until draft 06 was a client hint before being promoted to the Network Information API.

Proposed Syntax

The header in both cases (Client Hint or New HTTP Header) could look something like in the example below, with the concrete user preference media features as a comma-separated list:

Media-Feature: prefers-color-scheme=dark, prefers-reduced-motion=reduce

Privacy Considerations

The fingerprinting discussions in Client Hints likewise apply.

——
¹ "Implementing Dark Mode took over 1,000 lines of CSS"https://webkit.org/blog/8892/dark-mode-in-web-inspector/

@ithinkihaveacat
Copy link

Is there a way for this header to be controlled (activate) via a per-site user preferences? Most of the sites that support dark mode today do so via explicit user preferences (i.e. cookies) and I would expect this to continue.

(Overall the situation seems somewhat analogous to the Accept-Language, which is technically the "right" way to support multiple languages, but which is routinely ignored by various sites in favor of explicit user preferences.)

@tomayac
Copy link
Contributor Author

tomayac commented Jul 31, 2019

Persisting the user preference doesn't make sense for the subset of users who set their preferences automatically (and thus unpredictably). For example, iOS 13 allows for sunset-based automatic dark or light appearance:

636952457838115304

@tabatkins
Copy link
Member

This seems pretty reasonable to me overall. I'm not experienced in working with HTTP headers, tho: what group typically specifies them?

@ithinkihaveacat
Copy link

@tomayac Yes it can be controlled by the system but I don't think the site-based preferences will go away any time soon (if ever), and it seems like this platformy mechanism will go unused if there's no way to "merge" the two settings. (Similar to the way Accept-Language is generally ignored.)

@plinss
Copy link
Member

plinss commented Jul 31, 2019

@tomayac
Copy link
Contributor Author

tomayac commented Aug 1, 2019

Yes it can be controlled by the system but I don't think the site-based preferences will go away any time soon

@ithinkihaveacat The idea here is to allow for both, people to manually override their system settings (e.g., have their OS in dark, but their Google in light), but to also honor people who have their (potentially automatic) system setting determine everything else.

@tomayac
Copy link
Contributor Author

tomayac commented Aug 1, 2019

This seems pretty reasonable to me overall. I'm not experienced in working with HTTP headers, tho: what group typically specifies them?

https://httpwg.org/http-extensions/client-hints.html

@yoavweiss, @igrigorik Given Meta note 2 and Meta note 3 in the comment above, is https://httpwg.org/http-extensions/client-hints.html the right place to start a discussion about (or even land) the described client hint (or new header)?

@yoavweiss
Copy link

https://httpwg.org/http-extensions/client-hints.html defines the infrastructure but not the headers that use it. Those are defined elsewhere (e.g. https://wicg.github.io/netinfo/)
So you could define those headers either here (if the editors and the WG are OK with that) or as a separate spec.

@tomayac
Copy link
Contributor Author

tomayac commented Aug 1, 2019

https://httpwg.org/http-extensions/client-hints.html defines the infrastructure but not the headers that use it. Those are defined elsewhere (e.g. https://wicg.github.io/netinfo/)

@yoavweiss This was my understanding, thanks for confirming.

So you could define those headers either here (if the editors and the WG are OK with that) or as a separate spec.

@tabatkins Question to the CSS WG: are you fine with spec'ing such a header or client hint here?

(Updated per #4162 (comment)) One important remark: since Accept-CH-Lifetime was removed from draft 07 (I think this is the relevant discussion that caused its removal), currently a client hint would not suffice, as it would only be sent for subresource requests, but not the main document (which would be needed for the inline CSS use case to be covered). Quoting from the demo: "If the Accept-CH-Lifetime duration is omitted, then the opt-in only applies for subresource requests of the document advertising the Accept-CH policy".

Given the above, we are left with defining a whole new HTTP header that gets sent unconditionally (like Save-Data), or the HTTP WG needs to reconsider the Accept-CH-Lifetime decision. Please advise, @yoavweiss and/or @igrigorik.

@yoavweiss
Copy link

Accept-CH-Lifetime was removed, but its persistency features were not (it was removed as it was suggested that implicitly setting persistency for the lifetime of the session would provide the same benefits and would lower complexity).

@tomayac
Copy link
Contributor Author

tomayac commented Aug 1, 2019

Oh, great, in that case a client hint definitely is still an option (and probably the preferred option).

So question to @tabatkins and the CSS WG: are you fine with spec'ing this here?

@tabatkins
Copy link
Member

Agenda+ to see what the rest of the group thinks.

@MatsPalmgren
Copy link

Is Client Hints restricted to secure contexts? It seems bad if a client broadcast this fingerprinting material over a cleartext channel.

@tomayac
Copy link
Contributor Author

tomayac commented Aug 1, 2019

Is Client Hints restricted to secure contexts?

Yes, as of draft 05.

@Malvoz
Copy link
Contributor

Malvoz commented Aug 27, 2019

@tomayac
There may potentially be an endless list of user preferences, I think the header would need to split up into several headers - perhaps one for each user preference. See the approach for Fetch Metadata Request Headers and the references in
https://w3c.github.io/webappsec-fetch-metadata/#bloat

@tomayac
Copy link
Contributor Author

tomayac commented Aug 27, 2019

Thanks, @Malvoz, this is very valuable information! For the CSS WG consideration, here's the relevant deep link of @mnot's post linked from Fetch Metadata Request Headers.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Expose User Preference Media Queries as HTTP Client Hint or HTTP Header.

The full IRC log of that discussion <AmeliaBR> Topic: Expose User Preference Media Queries as HTTP Client Hint or HTTP Header
<AmeliaBR> github: https://github.com//issues/4162
<AmeliaBR> TabAtkins: Idea is that some of the preference media queries trigger fairly substantial changes to a page. E.g., reduced motions might trigger more than just CSS fix-ups.
<AmeliaBR> …If you want to make changes on first display, need that before the page downloads.
<dino> q+
<AmeliaBR> …Idea is to pass this info to server as a client hint & server can respond with the good stuff
<AmeliaBR> …Some debate on the invalidation logic. The settings can change over the course of a session.
<astearns> ack dino
<AmeliaBR> …But overall, idea seems reasonable. But I'm not well versed on client hints.
<AmeliaBR> dino: My pref is that this shouldn't happen. Media queries are supposed to be dynamic & can cause page changes.
<tantek> +1 dino
<AmeliaBR> …Changing which JS you download doesn't seem to conform.
<AmeliaBR> …Could also make pixel tracking techniques even easier.
<drousso> q+
<AmeliaBR> TabAtkins: I disagree that changing downloads is a minor benefit. Could help make sure that initial payload is as small as possible, good for many use cases.
<dino> q+
<florian> q+
<astearns> ack drousso
<AmeliaBR> …Already, sites can *try* to do this by setting server cookies based on previous MQ results. That's more likely to mess things up than using HTTP headers.
<tantek> CSS is a tiny fraction of what G sends down compared to the heaps of JS. Not buying the "send less CSS" argument as a practical impact here
<AmeliaBR> drousso: Using the example of dark mode, downloading only a slimmed-down dark mode CSS. If that MQ changes, then the cache invalidation must need to handle the change in state, to know what to download.
<AmeliaBR> TabAtkins: I suspect this is similar to state handling in many JS based apps, but I'm not an expert.
<tantek> LMK if there's a noJS version of G properties that has well designed CSS for normal/dark mode and what % of the page download that would impact
<astearns> ack dino
<AmeliaBR> drousso: Would probably need to add query parameters to CSS so that it can be invalidated.
<tantek> +1 dino thanks for making the right argument. sending both normal/dark CSS rules are tiny compared to all the rest of the page load size
<AmeliaBR> dino: I think the savings for cutting out a bit of CSS is probably not worth the overhead. Cookie tracking might not be that bad an alternative.
<astearns> ack florian
<AmeliaBR> TabAtkins: Sounds reasonable. Can you add these comments to the issue so we can close it with reasons?
<tantek> I'd say, the additional fingerprinting from Client Hints for this are not worth the fractional anticipated performance gain by less CSS compared to the massive JS in practice.
<astearns> ack dbaron
<AmeliaBR> florian: Another concern is privacy. If we allow this on HTTP as well as HTTPS, preferences get leaked everywhere. Also, logged on all sorts of servers
<AmeliaBR> dbaron: I am also generally skeptical. But I think some arguments given here aren't correct & what to make sure those are clarified. Client hints spec integrates with vary headers, so that caching can handle it. And tracking is not as easy as suggested.
<AmeliaBR> …I'd also want more details on proposal anyway before accepting.
<dbaron> s/tracking is not as easy/designed so fingerprinting is active rather than passive/
<AmeliaBR> astearns: OK. So let's follow-up on issue.

@grorg
Copy link
Contributor

grorg commented Sep 4, 2019

Apple/WebKit is pretty strongly against this.

  • This gives pixel-tracking and other non-JS fingerprinting techniques even more data.

  • These media queries are supposed to be dynamic, in that the page should change when the user updates their preference. The idea of only shipping a subset of your CSS and JS means that you'll have to hit the network if e.g. the user swaps from dark to light mode. And you'll have to write JS code in your page to fetch the new style.

  • For an initial page load, the amount of extra CSS to support both light and dark mode is inconsequential.

  • It will make some caching more difficult. If the user preference changes, the caching code now needs to know what things to redownload.

@frivoal
Copy link
Collaborator

frivoal commented Sep 4, 2019

@dbaron I am not convinced about the active vs passive distinction: it can very easily become a "best practice", possibly propagated by some popular framework, to always ask, and then the distinction goes away.

@astearns astearns removed the Agenda+ label Sep 5, 2019
@tomayac
Copy link
Contributor Author

tomayac commented Sep 5, 2019

Thanks for discussing this proposal. Some remarks based on the IRC logs.

Media queries are supposed to be dynamic & can cause page changes.

Google Search in a not logged in session currently contains…

…about 23kb of inlined CSS.

@-webkit-keyframes gb__a{0%{opacity:0}50%{opacity:1}}@keyframes gb__a{0%{opacity:0}50%{opacity:1}}.gb_za{display:none!important}.gb_Aa{visibility:hidden}.gb_c .gbqfi::before{left:-428px;top:0}.gb_Qb .gbqfb:focus .gbqfi{outline:1px dotted #fff}.gb_c .gb_y .gb_z::before,.gb_c.gb_A .gb_y .gb_z::before{left:-132px;top:-38px}.gb_c.gb_h .gb_y .gb_z::before{left:-463px;top:-35px}.gb_Qb .gb_F{position:relative}.gb_y .gb_z:hover,.gb_y .gb_z:focus{opacity:.85}.gb_h .gb_y .gb_z:hover,.gb_h .gb_y .gb_z:focus{opacity:1}@media (min-resolution:1.25dppx),(-webkit-min-device-pixel-ratio:1.25),(min-device-pixel-ratio:1.25){.gb_M .gb_m{background-image:url('https://ssl.gstatic.com/gb/images/p2_547d5a41.png')}}.gb_c .gb_tc .gb_vc::before{left:0;top:-35px}.gb_c.gb_h .gb_tc .gb_vc::before{left:-296px;top:0}.gb_c.gb_A .gb_tc .gb_vc::before{left:-97px;top:0}.gb_c .gb_ma{background-image:none!important}.gb_c .gb_wc{visibility:visible}.gb_Qb .gb_qe span{background:transparent}.gb_Od{color:#ffffff;font-size:13px;font-weight:bold;height:25px;line-height:19px;padding-top:5px;padding-left:12px;position:relative;background-color:#4d90fe}.gb_Od .gb_Pd{color:#ffffff;cursor:default;font-size:22px;font-weight:normal;position:absolute;right:12px;top:5px}.gb_Od .gb_td,.gb_Od .gb_qd{color:#ffffff;display:inline-block;font-size:11px;margin-left:16px;padding:0 8px;white-space:nowrap}.gb_Qd{background:none;background-image:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,0.16)),to(rgba(0,0,0,0.2)));background-image:-webkit-linear-gradient(top,rgba(0,0,0,0.16),rgba(0,0,0,0.2));background-image:linear-gradient(top,rgba(0,0,0,0.16),rgba(0,0,0,0.2));background-image:-webkit-linear-gradient(top,rgba(0,0,0,0.16),rgba(0,0,0,0.2));border-radius:2px;border:1px solid #dcdcdc;border:1px solid rgba(0,0,0,0.1);cursor:default!important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#160000ff,endColorstr=#220000ff);text-decoration:none!important;-webkit-border-radius:2px}.gb_Qd:hover{background:none;background-image:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,0.14)),to(rgba(0,0,0,0.2)));background-image:-webkit-linear-gradient(top,rgba(0,0,0,0.14),rgba(0,0,0,0.2));background-image:linear-gradient(top,rgba(0,0,0,0.14),rgba(0,0,0,0.2));background-image:-webkit-linear-gradient(top,rgba(0,0,0,0.14),rgba(0,0,0,0.2));border:1px solid rgba(0,0,0,0.2);box-shadow:0 1px 1px rgba(0,0,0,0.1);-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.1);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#14000000,endColorstr=#22000000)}.gb_Qd:active{box-shadow:inset 0 1px 2px rgba(0,0,0,0.3);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.3)}.gb_kd.gb_ld{padding:0}.gb_ld .gb_B{background:#ffffff;border:solid 1px transparent;-webkit-border-radius:8px;border-radius:8px;-webkit-box-sizing:border-box;box-sizing:border-box;padding:16px;right:0;top:72px;-webkit-box-shadow:0 1px 2px 0 rgba(65,69,73,0.3),0 3px 6px 2px rgba(65,69,73,0.15);box-shadow:0 1px 2px 0 rgba(65,69,73,0.3),0 3px 6px 2px rgba(65,69,73,0.15)}a.gb_md{color:#5f6368!important;font-size:22px;height:24px;opacity:1;padding:8px;position:absolute;right:8px;top:8px;text-decoration:none!important;width:24px}a.gb_md:focus,a.gb_md:active,a.gb_md:focus:hover{background-color:#e8eaed;-webkit-border-radius:50%;border-radius:50%;outline:none}a.gb_md:hover{background-color:#f1f3f4;-webkit-border-radius:50%;border-radius:50%;outline:none}svg.gb_nd{fill:#5f6368;opacity:1}.gb_od{padding:0;white-space:normal;display:table}.gb_pd{line-height:normal;font-family:Roboto,RobotoDraft,Helvetica,Arial,sans-serif}.gb_ld .gb_5:active{outline:none;-webkit-box-shadow:0 4px 5px rgba(0,0,0,.16);box-shadow:0 4px 5px rgba(0,0,0,.16)}.gb_1.gb_qd.gb_rd{-webkit-border-radius:4px;border-radius:4px;cursor:pointer;height:16px;color:#5f6368;font-family:Google Sans,Roboto,RobotoDraft,Helvetica,Arial,sans-serif;font-weight:500;letter-spacing:.25px;line-height:16px;padding:8px 6px;text-transform:none;-webkit-font-smoothing:antialiased}.gb_1.gb_qd:hover{background-color:#f8f9fa}.gb_1.gb_qd:focus,.gb_1.gb_qd:hover:focus{background-color:#f1f3f4;border-color:transparent}.gb_1.gb_qd:active{background-color:#f1f3f4;-webkit-box-shadow:0 1px 2px 0 rgba(60,64,67,0.3),0 1px 3px 1px rgba(60,64,67,0.15);box-shadow:0 1px 2px 0 rgba(60,64,67,0.3),0 1px 3px 1px rgba(60,64,67,0.15)}.gb_jd{color:#5f6368;font-family:Roboto,RobotoDraft,Helvetica,Arial,sans-serif;font-size:14px;letter-spacing:.25px;line-height:20px;margin:0;margin-bottom:5px}.gb_sd{text-align:right;font-size:14px;padding-bottom:0;white-space:nowrap}.gb_sd .gb_td{margin-left:12px;text-transform:none}a.gb_5.gb_td:hover{background-color:#2b7de9;border-color:transparent;-webkit-box-shadow:0 1px 2px 0 rgba(66,133,244,0.3),0 1px 3px 1px rgba(66,133,244,0.15);box-shadow:0 1px 2px 0 rgba(66,133,244,0.3),0 1px 3px 1px rgba(66,133,244,0.15)}a.gb_5.gb_td:focus,a.gb_5.gb_td:hover:focus{background-color:#5094ed;border-color:transparent;-webkit-box-shadow:0 1px 2px 0 rgba(66,133,244,0.3),0 1px 3px 1px rgba(66,133,244,0.15);box-shadow:0 1px 2px 0 rgba(66,133,244,0.3),0 1px 3px 1px rgba(66,133,244,0.15)}a.gb_5.gb_td:active{background-color:#63a0ef;-webkit-box-shadow:0 1px 2px 0 rgba(66,133,244,0.3),0 1px 3px 1px rgba(66,133,244,0.15);box-shadow:0 1px 2px 0 rgba(66,133,244,0.3),0 1px 3px 1px rgba(66,133,244,0.15)}.gb_sd .gb_td.gb_ud{padding-left:6px;padding-right:14px}.gb_sd .gb_rd.gb_td img{background-color:inherit;-webkit-border-radius:initial;border-radius:initial;height:18px;margin:0 8px 0 4px;vertical-align:text-top;width:18px}.gb_vd .gb_od .gb_wd .gb_rd{border:2px solid transparent}.gb_vd .gb_od .gb_wd .gb_rd:focus:after,.gb_vd .gb_od .gb_wd .gb_rd:hover:after{background-color:transparent}.gb_pd{background-color:#404040;color:#fff;padding:16px;position:absolute;top:36px;min-width:328px;max-width:650px;right:0;-webkit-border-radius:2px;border-radius:2px;-webkit-box-shadow:4px 4px 12px rgba(0,0,0,0.4);box-shadow:4px 4px 12px rgba(0,0,0,0.4)}.gb_pd a,.gb_pd a:visited{color:#5e97f6;text-decoration:none}.gb_xd{text-transform:uppercase}.gb_yd{padding-left:50px}.gb_zd{color:#3c4043;font-family:Google Sans,Roboto,RobotoDraft,Helvetica,Arial,sans-serif;font-size:16px;font-weight:500;letter-spacing:.1px;line-height:20px;margin:0;margin-bottom:12px}.gb_jd a.gb_Bd{text-decoration:none;color:#5e97f6}.gb_jd a.gb_Bd:visited{color:#5e97f6}.gb_jd a.gb_Bd:hover,.gb_jd a.gb_Bd:active{text-decoration:underline}.gb_Cd{position:absolute;background:transparent;top:-999px;z-index:-1;visibility:hidden;margin-top:1px;margin-left:1px}#gb .gb_ld{margin:0}.gb_ld .gb_tb{background:#4d90fe;border:2px solid transparent;-webkit-box-sizing:border-box;box-sizing:border-box;font-weight:500;margin-top:21px;min-width:70px;text-align:center;-webkit-font-smoothing:antialiased}.gb_ld a.gb_5{background:#1a73e8;-webkit-border-radius:4px;border-radius:4px;color:#ffffff;font-family:Google Sans,Roboto,RobotoDraft,Helvetica,Arial,sans-serif;font-size:14px;font-weight:500;letter-spacing:.25px;line-height:16px;padding:8px 22px;-webkit-font-smoothing:antialiased}.gb_ld a.gb_5.gb_Dd{background:#d93025}.gb_ld a.gb_5.gb_Dd:hover{background-color:#cc3127}.gb_ld a.gb_5.gb_Dd:focus,.gb_ld a.gb_5.gb_Dd:focus:hover{background-color:#b3332c}.gb_ld a.gb_5.gb_Dd:active,.gb_ld a.gb_5.gb_Dd:focus:active{background-color:#a6342e}.gb_ld:not(.gb_vd) a.gb_5{float:right}#gb .gb_ld a.gb_tb.gb_tb{color:#ffffff;cursor:pointer}.gb_ld .gb_tb:hover{background:#357ae8;border-color:#2f5bb7}.gb_Ed,.gb_wd{display:table-cell}.gb_Ed{vertical-align:middle}.gb_Ed img{height:48px;padding-left:4px;padding-right:20px;width:48px}.gb_wd{padding-left:13px;width:100%}.gb_ld .gb_wd{padding-top:4px;min-width:326px;padding-left:0;width:326px}.gb_ld.gb_Fd .gb_wd{min-width:254px;width:254px}.gb_ld:not(.gb_vd) .gb_wd{padding-top:32px}.gb_Hd{display:block;display:inline-block;padding:1em 0 0 0;position:relative;width:100%}.gb_Id{color:#ff0000;font-style:italic;margin:0;padding-left:46px}.gb_Hd .gb_Jd{float:right;margin:-20px 0;width:-webkit-calc(100% - 46px);width:calc(100% - 46px)}.gb_Kd svg{fill:grey}.gb_Kd.gb_Ld svg{fill:#4285f4}.gb_Hd .gb_Jd label:after{background-color:#4285f4}.gb_Kd{display:inline;float:right;margin-right:22px;position:relative;top:2px}.gb_Sf{margin-bottom:32px;font-size:small}.gb_Sf .gb_Tf{margin-right:5px}.gb_Sf .gb_Uf{color:red}.gb_9c{display:none}.gb_9c.gb_Ic{display:block}.gb_ad{background-color:#fff;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.08);box-shadow:0 1px 0 rgba(0,0,0,0.08);color:#000;position:relative;z-index:986}.gb_bd{height:40px;padding:16px 24px;white-space:nowrap}.gb_cd{position:fixed;bottom:16px;padding:16px;right:16px;white-space:normal;width:328px;-webkit-transition:width .2s,bottom .2s,right .2s;transition:width .2s,bottom .2s,right .2s;-webkit-border-radius:2px;border-radius:2px;-webkit-box-shadow:0 5px 5px -3px rgba(0,0,0,0.2),0 8px 10px 1px rgba(0,0,0,0.14),0 3px 14px 2px rgba(0,0,0,0.12);box-shadow:0 5px 5px -3px rgba(0,0,0,0.2),0 8px 10px 1px rgba(0,0,0,0.14),0 3px 14px 2px rgba(0,0,0,0.12)}@media (max-width:400px){.gb_ad.gb_cd{max-width:368px;width:auto;bottom:0;right:0}}.gb_ad .gb_tb{border:0;font-weight:500;font-size:14px;line-height:36px;min-width:32px;padding:0 16px;vertical-align:middle}.gb_ad .gb_tb:before{content:'';height:6px;left:0;position:absolute;top:-6px;width:100%}.gb_ad .gb_tb:after{bottom:-6px;content:'';height:6px;left:0;position:absolute;width:100%}.gb_ad .gb_tb+.gb_tb{margin-left:8px}.gb_dd{height:48px;padding:4px;margin:-8px 0 0 -8px}.gb_cd .gb_dd{float:left;margin:-4px}.gb_ed{font-family:Roboto,RobotoDraft,Helvetica,Arial,sans-serif;overflow:hidden;vertical-align:top}.gb_bd .gb_ed{display:inline-block;padding-left:8px;width:640px}.gb_cd .gb_ed{display:block;margin-left:56px;padding-bottom:16px}.gb_fd{background-color:inherit}.gb_bd .gb_fd{display:inline-block;position:absolute;top:18px;right:24px}.gb_cd .gb_fd{text-align:right;padding-right:24px;padding-top:6px}.gb_fd .gb_gd{height:1.5em;margin:-.25em 10px -.25em 0;vertical-align:text-top;width:1.5em}.gb_hd{line-height:20px;font-size:16px;font-weight:700;color:rgba(0,0,0,.87)}.gb_cd .gb_hd{color:rgba(0,0,0,.87);font-size:16px;line-height:20px;padding-top:8px}.gb_bd .gb_hd,.gb_bd .gb_id{width:640px}.gb_id .gb_jd,.gb_id{line-height:20px;font-size:13px;font-weight:400;color:rgba(0,0,0,.54)}.gb_cd .gb_id .gb_jd{font-size:14px}.gb_cd .gb_id{padding-top:12px}.gb_cd .gb_id a{color:rgba(66,133,244,1)}.gb_Qb .gb_Va{border:0;border-left:1px solid rgba(0,0,0,.2);border-top:1px solid rgba(0,0,0,.2);height:14px;width:14px;-webkit-transform:rotate(45deg);transform:rotate(45deg)}.gb_Qb .gb_Ua{border:0;border-left:1px solid rgba(0,0,0,.2);border-top:1px solid rgba(0,0,0,.2);height:14px;width:14px;-webkit-transform:rotate(45deg);transform:rotate(45deg);border-color:#fff;background:#fff}.gb_c .gb_ug::before{clip:rect(25px 235px 41px 219px);left:-197px;top:-3px}.gb_c .gb_vc.gb_vg{position:absolute}.gb_c .gb_vg::before{clip:rect(0 210px 16px 194px);left:-164px;top:22px}.gb_c .gb_La .gb_ug::before{left:-189px}@media (min-resolution:1.25dppx),(-webkit-min-device-pixel-ratio:1.25),(min-device-pixel-ratio:1.25){.gb_c .gb_ug::before{clip:rect(50px 470px 82px 438px)}.gb_c .gb_vg::before{clip:rect(0 420px 32px 388px)}}.gb_c .gb_vc,.gb_c .gbii,.gb_c .gbip{background-image:none;overflow:hidden;position:relative}.gb_c .gb_vc::before{content:url('//ssl.gstatic.com/gb/images/i1_1967ca6a.png');position:absolute}@media (min-resolution:1.25dppx),(-webkit-min-device-pixel-ratio:1.25),(min-device-pixel-ratio:1.25){.gb_c .gb_vc::before{content:url('//ssl.gstatic.com/gb/images/i2_2ec824b0.png');-webkit-transform:scale(.5);transform:scale(.5);-webkit-transform-origin:0 0;transform-origin:0 0}}.gb_Qb a:focus{outline:1px dotted #fff!important}sentinel{}

The idea of this proposal definitely is to still support dynamic switching, simply by deferring the loading of CSS for the currently not needed mode.

I disagree that changing downloads is a minor benefit. Could help make sure that initial payload is as small as possible, good for many use cases.

Keeping the initial payload small is indeed crucial for high traffic sites like Google Search.

Already, sites can try to do this by setting server cookies based on previous MQ results. That's more likely to mess things up than using HTTP headers.

Very much true, especially now that automatic color scheme switching has become a thing in both Catalina and iOS 13, and now that Android 10 toggles dark theme when battery safer is on, we expect the preference to change non-predictably, so storing the value in cookies definitely would make things worse.

LMK if there's a noJS version of G properties that has well designed CSS for normal/dark mode

You can try support.google.com, which has a manual theme mode switcher (at the very bottom). It does a full refresh, though.

Another concern is privacy. If we allow this on HTTP as well as HTTPS, preferences get leaked everywhere.

Client Hints currently makes the following requirements (emphasis mine): "The opt-in SHOULD be persisted and bound to the origin to enable delivery of Client Hints on subsequent requests to the server’s origin, and MUST NOT be persisted for an origin that isn’t HTTPS".

The idea of only shipping a subset of your CSS and JS means that you'll have to hit the network if e.g. the user swaps from dark to light mode.

As outlined above, we see this as an advantage (i.e., the argument being to keep the initial payload small).

And you'll have to write JS code in your page to fetch the new style.

This can be circumvented by leveraging the media attribute on <link>, or by leveraging an @import CSS at-rule with a media query.

Happy to try to answer more questions the group may have. Apologies if the above responses potentially were a bit off, it was hard to get the full gist regarding the caching discussion by looking at just the IRC logs ("Some debate on the invalidation logic.").

@emilio
Copy link
Collaborator

emilio commented Sep 5, 2019

This can be circumvented by leveraging the media attribute on , or by leveraging an @import CSS at-rule with a media query.

But those are fetched regardless, aren't they?

@tomayac
Copy link
Contributor Author

tomayac commented Sep 5, 2019

But those are fetched regardless, aren't they?

Very much true, but for the <link> case they download with lowest priority so they don't interfere with resources crucial to the current page.

Update 1: For the @import case, it seems like they download with highest priority (I am going to investigate if I should file a bug about this, or if this is the correct behavior).

Update 2: The @import case loading behavior from Update 1 can actually be considered a bug: https://crbug.com/1001078.

@emilio
Copy link
Collaborator

emilio commented Sep 5, 2019

It is correct / intended probably, as the load of the outer <style> element blocks rendering, since it has no media attribute.

<!doctype html>
<style>
  @import url("https://software.hixie.ch/utilities/cgi/test-tools/delayed-file?pause=2&mime=text%2Fcss&text=body{color:red}") print;
</style>
Should see me after two seconds.

It could probably be optimized to not block rendering, though it probably requires spec changes.

@tomayac
Copy link
Contributor Author

tomayac commented Sep 5, 2019

I think it's fine to not block, please see https://crbug.com/1001078.

@emilio
Copy link
Collaborator

emilio commented Sep 5, 2019

Sure, in that simple example. But if you have mixed import rules, per spec you need to process the <style> element before the rest, and it may get a bit more complicated to track it.

Anyhow I don't think as is https://html.spec.whatwg.org/multipage/semantics.html#interactions-of-styling-and-scripting allows that, though as I said it seems reasonable to change that, maybe.

@yoavweiss
Copy link

@dbaron I am not convinced about the active vs passive distinction: it can very easily become a "best practice", possibly propagated by some popular framework, to always ask, and then the distinction goes away.

@frivoal
Browsers are determined to make sure the distinction between passive and active fingerprinting is very clear for developers, and that any blurring of the distinction will have practical implications. Those practical implications should apply to both JS entropy sources as well as the Client Hints one.

@grorg

This gives pixel-tracking and other non-JS fingerprinting techniques even more data.

That is not accurate:

  • For pixel-tracking, cross-origin requests will not get hints, unless the 1P is actively delegating the hints to the pixel-tracking host.
  • The idea behind Client Hints data exposure is to treat it similarly to JS exposure, as an active fingerprinting vector. So it should not be considered a "non-JS" technique. As a result, when JS is disabled, CH are also not emitted.
  • Any use of MQ in CSS should also be considered an active fingerprinting vector, as it can e.g. trigger network requests, which don't require JS to be abused by the server.
  • It will make some caching more difficult. If the user preference changes, the caching code now needs to know what things to redownload.

Vary headers solve that problem. Variants will enable solving it with better granularity in the future, but since we're talking about exposing a single bit here, I doubt they matter for this discussion.

@tomayac
Copy link
Contributor Author

tomayac commented Nov 6, 2019

@tabatkins I think we've tried to come up with answers to the questions and concerns that were brought forward here on this thread as well as on IRC (based on the logs). The Google Search team are still eager to follow through with the overall idea described in the initial comment. Could the CSS WG maybe discuss this again based on the provided answers? Thanks in advance. Also happy to join a call if this would be helpful.

@tomayac
Copy link
Contributor Author

tomayac commented Feb 6, 2020

FWIW, the prefers-reduced-data media feature proposal was added to the spec in December 2019. I listed this in a meta note in the initial proposal as the inverse of what is being proposed in the current issue. Google Search is still eager to explore the idea.

@yoavweiss
Copy link

igrigorik/http-client-hints#73 seems relevant as a detailed request for a prefers-color-scheme Client Hint

@tomayac
Copy link
Contributor Author

tomayac commented Apr 17, 2020

@tabatkins Any chance this could be Agenda+'ed again? The Google Search team are still interested in pursuing this.

@benschwarz
Copy link

I'd just like to add my support to this proposal. Calibre is a tool to help teams test and monitor the performance of their pages.

If there were headers set by the browser, our customers would easily be able to set headers for page testing conditions — then they'd get metrics and feedback about their sites in more user conditions.

This'd be especially useful for turning off animations (so that metrics are more accurate) as well as better supporting accessibility efforts. Huge 👍 from me.

@efstajas
Copy link

efstajas commented May 20, 2020

I'd like to add my support as well. We're 100% committed to supporting specifically the prefers-color-scheme accessibility feature, but with our SSR setup it's currently practically impossible to prevent the default theme being briefly rendered on first load before the view is hydrated on the client-side, unless we sacrifice time to first contentful paint by displaying the page only after hydration. Getting this information in the request header would allow us to properly render with the expected color scheme right away.

I understand that we could use CSS variables and ship both light and dark themes with the initial rendered HTML, but we're using styled-components as a CSS-in-JS styling solution, as many others do. Systematically, this means our theme is rendered using JS so we have no way to render the page properly without knowing the user preference on the server render. Unless we invest weeks into changing our styling toolchain, that is…

@sangwoo108
Copy link

I support the proposal too. If a request can contain the color-scheme information, we can provide not only optimized stylesheets but also optimized images based on the preference. As clients can provide DPR, viewport-width and etc. for similar purpose, I believe providing color-scheme is not that far from that.

@tomayac
Copy link
Contributor Author

tomayac commented Sep 10, 2020

Together with the Critical-CH header (TAG Review), the client hint solution proposed in the initial post would work for Google Search, where we are eager to explore this.

@tomayac
Copy link
Contributor Author

tomayac commented May 12, 2021

FYI, we have started the TAG review process for a new set of User Preference Media Features Client Hints Headers, for example, Sec-CH-Prefers-Color-Scheme. See (and/or subscribe to) w3ctag/design-reviews#632 for details.

@tomayac
Copy link
Contributor Author

tomayac commented Aug 3, 2021

To close the loop on this: we have introduced the Sec-CH-Prefers-Color-Scheme header as a first specimen of other user preference media feature headers. Thanks everyone for their feedback and helpful remarks on this issue. Closing.

@tomayac tomayac closed this as completed Aug 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests