Problem/Motivation
Viewing the front page of a Drupal 10.1 install as user 1 shows the following CSS aggregates in the header.
As you can see, there are four aggregates, with the second aggregate including media="screen".
<link rel="stylesheet" media="all" href="/sites/default/files/css/css_AI3tdfWguXKwGYQh77azpIWFB75vRNg_QczKMd7wJAo.css?delta=0&language=en&theme=olivero&include=contextual/drupal.contextual-links%2Csystem/base%2Colivero/global-styling%2Ccore/drupal.active-link%2Colivero/powered-by-block%2Colivero/feed%2Cviews/views.module%2Colivero/navigation-secondary%2Colivero/search-wide%2Colivero/navigation-primary%2Colivero/search-narrow%2Ccore/modernizr%2Ccore/drupal.debounce%2Ctoolbar/toolbar%2Cuser/drupal.user.icons%2Ccore/shepherd%2Ctour/tour-styling%2Ctour/tour%2Ccore/drupal.tabbingmanager%2Ccontextual/drupal.contextual-toolbar%2Cshortcut/drupal.shortcut%2Ctoolbar/toolbar.escapeAdmin%2Cbig_pipe/big_pipe" />
<link rel="stylesheet" media="screen" href="/sites/default/files/css/css_5FA3K14RQkYOhjLi22sUkXa3rr9UmOmp2HuTM9zq2n4.css?delta=1&language=en&theme=olivero&include=contextual/drupal.contextual-links%2Csystem/base%2Colivero/global-styling%2Ccore/drupal.active-link%2Colivero/powered-by-block%2Colivero/feed%2Cviews/views.module%2Colivero/navigation-secondary%2Colivero/search-wide%2Colivero/navigation-primary%2Colivero/search-narrow%2Ccore/modernizr%2Ccore/drupal.debounce%2Ctoolbar/toolbar%2Cuser/drupal.user.icons%2Ccore/shepherd%2Ctour/tour-styling%2Ctour/tour%2Ccore/drupal.tabbingmanager%2Ccontextual/drupal.contextual-toolbar%2Cshortcut/drupal.shortcut%2Ctoolbar/toolbar.escapeAdmin%2Cbig_pipe/big_pipe" />
<link rel="stylesheet" media="all" href="/sites/default/files/css/css_kuhPJIoUEPrw6lSo2T4L7_-4v37wAeKmhT8fPFwvE1E.css?delta=2&language=en&theme=olivero&include=contextual/drupal.contextual-links%2Csystem/base%2Colivero/global-styling%2Ccore/drupal.active-link%2Colivero/powered-by-block%2Colivero/feed%2Cviews/views.module%2Colivero/navigation-secondary%2Colivero/search-wide%2Colivero/navigation-primary%2Colivero/search-narrow%2Ccore/modernizr%2Ccore/drupal.debounce%2Ctoolbar/toolbar%2Cuser/drupal.user.icons%2Ccore/shepherd%2Ctour/tour-styling%2Ctour/tour%2Ccore/drupal.tabbingmanager%2Ccontextual/drupal.contextual-toolbar%2Cshortcut/drupal.shortcut%2Ctoolbar/toolbar.escapeAdmin%2Cbig_pipe/big_pipe" />
<link rel="stylesheet" media="all" href="/sites/default/files/css/css_qKcdHo1cKu_xYxsR9LUksx-DrCUAFfMtkTdFg2jt9CM.css?delta=3&language=en&theme=olivero&include=contextual/drupal.contextual-links%2Csystem/base%2Colivero/global-styling%2Ccore/drupal.active-link%2Colivero/powered-by-block%2Colivero/feed%2Cviews/views.module%2Colivero/navigation-secondary%2Colivero/search-wide%2Colivero/navigation-primary%2Colivero/search-narrow%2Ccore/modernizr%2Ccore/drupal.debounce%2Ctoolbar/toolbar%2Cuser/drupal.user.icons%2Ccore/shepherd%2Ctour/tour-styling%2Ctour/tour%2Ccore/drupal.tabbingmanager%2Ccontextual/drupal.contextual-toolbar%2Cshortcut/drupal.shortcut%2Ctoolbar/toolbar.escapeAdmin%2Cbig_pipe/big_pipe" />
The media="screen" contains only the CSS file for tour-styling, due to this:
tour-styling:
version: VERSION
css:
component:
css/tour.module.css: { media: screen }
I think when we added media support many years ago, we thought it'd add one extra file to support media="screen" (and that it would mostly be used for media="print"), however in fact it turns one aggregate into three which is a lot of extra http requests.
This is because we also deal with weights of assets, so if some assets in an aggregate need to go before tour, and some after, for it to be in the middle there have to be three files. And we also add weights based just on the order that files are added to the page, so that's pretty much all the time unless an asset with media screen happened to be the very last or very first one. Even if we remove weight support, unless we explicitly put screen assets first or last, they could still end up in the middle and require their own aggregate.
Proposed resolution
Inline media declarations during aggregation, for anything that is not media="print", this means that the common case of media="screen" will be included in the same aggregates. Since we're concerned about front end performance on screens, and not worried about a few extra CSS bytes when someone's printing a web page, there should not be a downside to doing it like this.
All browsers that Drupal supports, support nested media queries now that we've dropped support for IE11.
Here's how the CSS aggregates for exactly the same page look after applying the patch and clearing caches:
<link rel="stylesheet" media="all" href="/sites/default/files/css/css_fp0O1ULW3vedV1lZnnaJEzM2rc-NGp8-8c7NCRZR1ng.css?delta=0&language=en&theme=olivero&include=contextual/drupal.contextual-links%2Csystem/base%2Colivero/global-styling%2Ccore/drupal.active-link%2Colivero/powered-by-block%2Colivero/feed%2Cviews/views.module%2Colivero/navigation-secondary%2Colivero/search-wide%2Colivero/navigation-primary%2Colivero/search-narrow%2Ccore/modernizr%2Ccore/drupal.debounce%2Ctoolbar/toolbar%2Cuser/drupal.user.icons%2Ccore/shepherd%2Ctour/tour-styling%2Ctour/tour%2Ccore/drupal.tabbingmanager%2Ccontextual/drupal.contextual-toolbar%2Cshortcut/drupal.shortcut%2Ctoolbar/toolbar.escapeAdmin%2Cbig_pipe/big_pipe" />
<link rel="stylesheet" media="all" href="/sites/default/files/css/css_qKcdHo1cKu_xYxsR9LUksx-DrCUAFfMtkTdFg2jt9CM.css?delta=1&language=en&theme=olivero&include=contextual/drupal.contextual-links%2Csystem/base%2Colivero/global-styling%2Ccore/drupal.active-link%2Colivero/powered-by-block%2Colivero/feed%2Cviews/views.module%2Colivero/navigation-secondary%2Colivero/search-wide%2Colivero/navigation-primary%2Colivero/search-narrow%2Ccore/modernizr%2Ccore/drupal.debounce%2Ctoolbar/toolbar%2Cuser/drupal.user.icons%2Ccore/shepherd%2Ctour/tour-styling%2Ctour/tour%2Ccore/drupal.tabbingmanager%2Ccontextual/drupal.contextual-toolbar%2Cshortcut/drupal.shortcut%2Ctoolbar/toolbar.escapeAdmin%2Cbig_pipe/big_pipe" />
As you can see, this reduces four aggregates down to two. The reason we still have two aggregates instead of one, is because core intentionally puts theme CSS into its own aggregate, that's unrelated to this change and by design.
Remaining tasks
User interface changes
API changes
Data model changes
| Comment | File | Size | Author |
|---|---|---|---|
| #32 | 2695871-32.patch | 5.79 KB | catch |
| #31 | 2695871-30.patch | 5.79 KB | catch |
| #31 | 2695871-24-30-interdiff.txt | 1.29 KB | catch |
| #24 | 2695871-24.patch | 4.76 KB | catch |
| #23 | 2695871-23.patch | 4.76 KB | catch |
Comments
Comment #2
catchComment #3
catchHere's a patch.
Keeps separate aggregates for media print, everything else gets inlined.
Comment #4
catchWrong patch.
Comment #5
catchThis might be stuck on nested media query support, or at least it gets a lot more complicated if we try to take that into account:
http://caniuse.com/#feat=css-mediaqueries
Comment #7
catchCouple of things from reading up on nested @media queries:
Every browser except IE supports them more or less, but even IE11 doesn't.
IE11 and other browsers apparently support nested media queries if the nesting happens via an @import.
- we currently pull stylesheets referenced with @import when generating aggregates, this could break if the @import is inside a media query.
- so a potentiall workaround for this might be to 1. check if the file has a @media statement 2. use @import if it does instead of actually aggregating 3. additionally don't aggregate files via @import if the imported file has a @media query.
Comment #20
catchNow that core no longer supports IE11, we're not blocked on nested media query support any more, that means the patch might be viable more-or-less as-is.
However, this needs a re-roll for 10.1.x after #1014086: Stampedes and cold cache performance issues with css/js aggregation.
Comment #21
catchActually this was unaffected by that change, but it was so old it needed a re-roll for array syntax. Nothing else appears to have changed.
Comment #22
catchComment #23
catchComment #24
catchComment #25
catchComment #26
borisson_We are special casing print here, but there is also speech according to w3, so should we special case that as well, or do it the other way around? Or should we not worry about it (because before googling this, I didn't know this existed).
https://www.w3schools.com/css/css3_mediaqueries.asp
The code here looks great, so if we don't worry about the speech type, then this is rtbc as far as I'm concerned.
Comment #27
catchThe speech media type is deprecated now (i.e. it's allowed, but treated as if it was 'all'), so I think it's fine to only special-case print here.
So there's only 'all', 'screen', and 'print' in terms of what should be included, and we're ensuring that 'screen' and 'all' are bundled together, and that 'print' is bundled separately.
https://www.w3.org/TR/mediaqueries-4/#media-types
Comment #28
spokjeAgreeing with @borisson_ in #26 and reading the explanation just above this comment: RTBC
Comment #29
catchThis should be eligible for 10.0.x since no IE11 support and no API change, so moving back a version.
Comment #30
alexpottThis looks fine and a nice saving on http requests for the 99.9% use-case.
Unfortunately we need to fix the docs for \Drupal\Core\Asset\CssCollectionGrouper::group() which currently say:
Comment #31
catchExpanded the docs a fair bit.
Comment #32
catchFixing that typo s/seperate/separate.
Comment #33
alexpottCommitted and pushed d587699e0a to 10.1.x and e91369d0b8 to 10.0.x. Thanks!
Comment #38
catchComment #39
catchMarked #1488910: Incorporate media queries in aggregated CSS files, don't create a new group for each new media query as duplicate and transferring credit.