Problem/Motivation
All component libraries are registered with the “core” extension and the “components.[component-id]” library name. This causes problems because such libraries are treated by the LibraryDiscoveryParser as the “default group” (CSS_AGGREGATE_DEFAULT) even if the component is defined and only exists in the theme. However, libraries defined by the theme are forced into the “theme group” (CSS_AGGREGATE_THEME). This results in a broken sorting in \Drupal\Core\Asset\AssetResolver::sort. Since CSS_AGGREGATE_DEFAULT has priority over CSS_AGGREGATE_THEME, and everything else is ignored, even properly made dependencies are not considered.
This heavily breaks the CSS flow, because styles from components are always loaded before those from the theme. And if your styles rely on this (implying that components should override them, not define), it is broken. A simple example is CSS layers, which simply don't work in this workflow, because layer definitions should come first, and only then can they be used. However, since theme CSS with layer definitions is loaded after components, you cannot use them there.
Altering component libraries and adding the theme library as a dependency, which should come first, also won’t work because of library groups.
Steps to reproduce
Try to load CSS files from the theme before the component libraries are loaded on the page in any way. Something like this:
<link rel="stylesheet" media="all" href="/themes/custom/themename/css/layer.css">
<link rel="stylesheet" media="all" href="/core/../themes/custom/themename/components/foo/foo.css">
Proposed resolution
- The component libraries should be forced into the
CSS_AGGREGATE_THEMEgroup. - Allow CSS libraries from the theme override group. This can be done in
\Drupal\Core\Asset\LibraryDiscoveryParser::buildByExtension. - Improve components documentation with a mention that “not a bug, but a feature” and how to workaround it.
Workaround
This workaround will change the group for the theme CSS file [theme]/css/layers.css to CSS_AGGREGATE_DEFAULT group, which, with a proper weight, will load it before component styles.
/**
* Implements hook_css_alter().
*/
function MYTHEME_css_alter(array &$css, AttachedAssetsInterface $assets, LanguageInterface $language): void {
$active_theme = \Drupal::service(ThemeManagerInterface::class)->getActiveTheme();
$layers_path = $active_theme->getPath() . '/css/layer.css';
if (array_key_exists($layers_path, $css)) {
$css[$layers_path]['group'] = CSS_AGGREGATE_DEFAULT;
}
}
Remaining tasks
Decide which way to go.
Comments
Comment #2
quietone commentedChanges are made on on 11.x (our main development branch) first, and are then back ported as needed according to our policies.