Base theme libraries may be output in reverse order

Created on 25 July 2019, almost 5 years ago
Updated 17 August 2023, 11 months ago

Problem/Motivation

Libraries defined by themes and base themes may be output in an unexpected order. Assume there is the following theme hierarchy:

Theme A -> Theme B -> Theme C

Where "Theme C" is the active theme that specifies "Theme B" as its parent, and so on.

The "global" libraries defined for each theme (via their .info.yml files) are output in this order:

  1. Theme B
  2. Theme A
  3. Theme C

The expected order is

  1. Theme A
  2. Theme B
  3. Theme C

Now, assume that each of those theme libraries has CSS defined at the "theme" level. The CSS files will be output in the incorrect order instead of the expected order. So if Theme A and Theme B both have the same CSS selectors defined, Theme A will "win" which is not the expected behavior.

This "unexpected behavior" also assumes that the theme developer did not realize that they must ALSO define the base theme's libraries as a dependency of their theme's library. I think this is a common issue, especially people coming from D7 world. They may reasonably assume that if you define a "sub theme", that the styling associated with the parent theme will be output first. That is how template inheritance works, after all. Also, look at a theme like classy. It has 13 libraries defined, all of which add some CSS. It seems a lot of work to have a theme developer declare all of those as an explicit dependency.

Proposed resolution

The problem is the libraries for the base themes are added in the reverse order that we expect. Drupal will resort the libraries based on the their dependencies, but again, this problem assumes the theme developer was not aware they needed to define the dependencies for each base theme's global styling.

The code that builds the list of libraries to add is in ThemeInitialization::getActiveTheme:

...
    // Grab libraries from base theme
    foreach ($base_themes as $base) {
      if (!empty($base->libraries)) {
        foreach ($base->libraries as $library) {
          $values['libraries'][] = $library;
        }
      }
    }

    // Add libraries used by this theme.
    if (!empty($theme->libraries)) {
      foreach ($theme->libraries as $library) {
        $values['libraries'][] = $library;
      }
    }
...

So it appends libraries from the list of base themes first, then tacks on the active theme libraries. This is good. The problem is that the list of base themes is provided in an order where the most direct ancestor is listed first in the array instead of last. This is due to code in ThemeInitialization::getActiveThemeByName.

The solution is to just run $base_themes through array_reverse. Of course, if we do this, it has the potential to break many sites that are unknowingly relying on the current behavior =/.

Or, we do nothing and just hope theme developers understand they must declare the dependencies properly.

Remaining tasks

TBD

User interface changes

TBD

API changes

TBD

Original report by sacarney

I have a base theme. I have a sub-theme. I have a sub-theme of that sub-theme (sub-sub-theme).

On sites that have only the base theme and sub-theme, the css loads in the correct order: base theme > sub-theme.

On sites that have the base theme, sub-theme, and a sub-sub-theme the css loads in the wrong order: sub-theme > base theme > sub-sub-theme.

I expect the order to be: base theme > sub-theme > sub-sub-theme.

All three .libraries.yml files look like this:


global-styling:
css:
theme:
css/file1.css: {}

My sub-theme's info file sets the base theme as its base, and the sub-sub-theme sets the sub-theme as its base.

All css files are in the order they should load under the theme category.

I also noticed that in the Appearance page in the Drupal admin UI, the themes appear in the list in that unexpected order, reflecting the css load order.
* Sub-Sub-Theme
* Base Theme
* Seven (admin theme)
* Stark (blank theme)
* Sub-Theme

I have tested on my project and also a clean D8 installation with skeleton themes.

I know that I could add weights to the individual files with { weight: 200 } but this seems to be working around what should just work. It seems like CSS files should just load in the order of theme inheritance. I wonder why it works when there's a base theme and sub-theme but not when you add a sub-sub-theme.

🐛 Bug report
Status

Active

Version

11.0 🔥

Component
Theme 

Last updated about 16 hours ago

Created by

🇺🇸United States sacarney

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

Production build 0.69.0 2024