The "themer" role is a Drupalism
Drupal's "theme" concept introduces unhealthy dependencies and hinders modularity. Use theme-agnostic front-end components instead, and let them live outside the theme.
(Disclaimer: Yes, Drupal is not the only system with "themes". Forgive the clickbait headline.)
There is this general idea in Drupal of a developer and/or site builder who builds the site and the business logic, and a themer who does the visual appearance. In many cases I have seen this leading to a situation where structure and functionality is nicely modularized, but the theme becomes a big unorganized heap of everything presentation-related. This is a problem.
Composition over Inheritance
An important lesson in a programmer's life is that inheritance is not really as good an idea as one might think. Trying to figure out what is going on in a deep and broad inheritance hierarchy can be quite the challenge. The entire point of encapsulation is to constrain the scope of variables. It is hard to individually track down and follow 99 people randomly straying around in an airport terminal. It is a lot easier to track down and follow one person in your living room. Or 99 people in 99 living rooms. The trick is to turn the airport terminal into 99 living rooms. And don't forget to close the doors.
This is what we can achieve with separation of logic into small, loosely coupled classes, and (on a more macroscopic level) into libraries or Drupal modules.
Composition does scale. Inheritance does not.
Unfortunately, themes somehow did not get the memo. Their main architecture is based on inheritance, not composition. Yes, inheritance is kinda an OOP concept, even if there are no classes and objects involved. But inheritance is not really the aspect of OOP that we are looking for.
Unhealthy layer dependencies
Besides a horizontal separation into different site features, content types, pages etc, we also identify vertical separation into layers. I refuse to use the term MVC here, because everyone seems to have a different idea what that means. Instead, I am going to distinguish a modules/libraries layer, a configuration layer, and a theme layer, that are characteric for a typical Drupal site.
The modules/libraries layer contains reusable components that are programmed in a site-agnostic way. They can be installed or uninstalled, and they can be configured for a specific behavior on the site we build.
The configuration layer defines content types, fields, views (lists of content), blocks, etc. These can be exported to code with features, but I still would consider this part of the configuration layer.
The theme layer contains templates, theme functions, preprocessors, and css. The goal is to make existing things look different than they would without the theme.
Theming is a very aspect-oriented thing to do. Instead of providing new components, or recombining existing ones, they are being altered. Instead of buying new slippers to use instead of your boots while at home, you cut holes into the boots.
The result is that now the theme may potentially touch and alter everything that is coming from either the modules/libraries, or from configuration. It can target specific content types, fields, etc, to give this specific artifact a distinct appearance. This happens both with theme functions / templates, and with targeted CSS rules.
A theme created this way will potentially depend on everything on the site, and will break if you change anything in the configuration. I have seen CSS target specific auto-increment IDs. Hardcoded content types, view names and field names are not as bad, but still far from desirable.
One consequence of this is also that you cannot start theming before the site builder has done his job for the particular feature.
The situation is worse in Drupal than it would be in Wordpress or other systems, because the artifacts you theme are such a moving target.
The CSS specifity arms race.
Not really the main topic of this article, but we need to talk a bit about CSS specifity wars.
(Also see further below, where I talk about JohnAlbin's DrupalCon presentation.)
Drupal introduces a lot of quite generic-sounding class names: ".item-list", ".title", ".content", ".menu". it also introduces a lot of classes that are very specific, but tell us more about Drupal than about appearance: ".field-item", ".views-view", ".node", etc.
These classes then need to be targeted in CSS to give e.g. all block titles in the left sidebar a specific appearance, but then having to override it again for a very specific block.
It gets even more complex with nesting: Blocks rendered within nodes, views rendered within blocks, etc.
We end up with rules like ".title", ".node .title", ".page-node-123 .sidebar .block-content .node .title". There are elements which are affected by all of them, but with a different specifity.
In the end we have a long unmanageable CSS files, where conflicting CSS rules try to compete with each other. Not a pleasant situation to be in.
Bootstrap to the rescue?
Things get miles better, if we work with a CSS framework. At least the CSS becomes a lot more manageable, because we are forced to do more in HTML and less in CSS. But if the theme is still "the place" for everything front-end, then we now get a lot of theme functions and preprocessors with hard dependencies on everything in the site. Not ideal either.
Design Components / SMACSS
The next step I want to mention here is something I learned in John Albin's DrupalCon presentation.
Styleguide-Driven Development: The New Web Development
The same thing still had a different name in Austin 4 months earlier:
MANAGING COMPLEX PROJECTS WITH DESIGN COMPONENTS
The session introduces a lot of great ideas. I'll try to summarize those that are most relevant for this blog post.
The session was with SASS dynamic stylesheet generation in mind, but a lot of this still applies to regular hand-written CSS, with Drupal's aggregation to avoid too many files.
- Divide your visual design into "components", each with a distinguishable machine name.
- Use long "namespaced" CSS classes, prefixed with the component name, instead of combining short and generic classes.
- Use different suffixes to express variations or state changes.
- Arrange your CSS into files and subfolders, grouped by component.
- JohnAlbin now suggests to auto-generate a style guide from these components. This is an awesome idea. But we don't need to go that far in this blog post.
One thing I wanted to know is where this modular CSS or SASS should live.
The answer was: It will be the theme.
But it seemed more an organizational choice, than an architectural one. The theme is home and workplace of the themer, and it is the themer who will create these design components.
Now we have reusable CSS, but we still need to theme the individual site features to the specific HTML required by the CSS components. This still means a lot of stuff happening in the theme, which I would rather see in small independent components.
Formatters, Views plugins, Display suite layouts
Fortunately, there is a world of front-end APIs outside the theming layer. We can write plugins for Views we can write formatters, etc. All of these are reusable ways to get a specific HTML and CSS. All of them are overridable on theme level, but we often get away without that. This allows our theme to remain lean and clean.
Unfortunately, writing formatters and views plugins is not a typical "themer" skill - or I think so. I don't know if it is really that much harder, or if it is simply not as sufficiently advertised.
I also think these APIs still expose too much unneeded Drupal details. Instead of a views plugin to display items in a slider, I would much rather create a "serial display plugin", which can then be used both by views and by other systems that want to render a "list of stuff", e.g. field items. I did that once, it was nice.
These display plugins are a great fit with Bootstrap, or with the design components mentioned above. A nice example is the Views Bootstrap module. I made similar modules for client sites, and it works great.
But these modules have one flaw: They depend on CSS provided by the theme. Be it the Bootstrap framework, or some bootstrap extensions, or custom design components that are part of the custom site-specific sub-theme. And these dependencies will be mostly implicit.
One difficulty with a dependency on the theme is also that module-provided functionality is available everywhere, while a theme might only be enabled on a section of the site. One obvious place where you notice this is the Views preview area, that is themed with the admin theme instead of the site theme.
Another technique mentioned in this session (or another session, I don't even remember) is tagging. Instead of having to target specific views, content types and fields, the site builder would tag those artifacts, so that a preprocessor can change the template suggestion based on the tags.
Not all systems provide allow this kind of tagging, but for those that do, it can be a nice thing.
A related technique would be modules like block_class, which allow to inject custom classes into existing templates.
But we are still left with too much stuff in the theme. And usually everything in the theme is considered site-specific and not that easy to reuse.
A refugee home for layout components
The solution, as I see it, is to have a place / an API outside the theme, where we can define CSS design components, and display plugins that can depend on these CSS components.
These APIs need to be at least as accessible as the theming layer is nowadays.
The nice thing is, we can get quite far with the current APIs (in D7) already, with a little shift of mind. And we can build new APIs on top of that.
The place for these layout components could be modules, which can provide design components and display plugins. There could be a new type of dependency, not of a module depending on a module, but of a display plugin depending on a design component, or one design component depending on another.
To clarify, with "Drupalism" I do not imply that others are doing it better, but that the solution is to be found outside the typical Drupal habits.
What do you think?
I am curious what my readers think (if anyone had the patience to make it down here). I am personally quite happy with formatters and views plugins, but this could be because I don't really fit the "themer" profile.