Hi, my name is Marc, and I am a markup nerd.
My skin crawls when I see HTML filled with divs tucked inside each other over and over again like a Russian nesting doll. My shoulders tense up when I see class names spilling out of a class attribute like clowns in a circus car. Conversely, my heart sings at the sight of cleanly crafted HTML that uses just the right elements to describe its contents, with sensible BEM-style classes that simplify styling and clarify how the markup has been structured.
Because I prefer being very particular about markup, I’ve been known to develop an eye twitch from time to time while theming Drupal sites.
In 2013 I started contributing fairly regularly to the development of Drupal 8. Working at Lullabot since September 2014 has made it possible to devote even more of my time to working on Drupal 8 front-end improvements. There’s a great team of developers around the world focused on improving the theming experience in Drupal 8, and it’s been a joy collaborating with them. I’m very excited about how we’ve worked together to make Drupal 8 better for front-end developers and themers.
Thanks to those efforts, I’m looking forward to having much better tools for carefully crafting markup in Drupal 8.
Making markup shine in Drupal 8
The new templating engine in Drupal 8, Twig, makes it easier to change markup without knowing the ins and outs of PHP. Most of the classes in Drupal are now added in the Twig templates themselves, rather than being buried deep in preprocessor and theme functions. Better yet, by turning on Twig Debug in the services.yml file in your sites/default folder, you can see which templates are generating each bit of markup when you view source. You’ll find which template file is currently in use along with suggestions for filenames you can use in your theme to override that template.
The markup itself has been greatly improved as well. Contributors worked to improve template logic so that only necessary divs or other elements are generated: yes, there are fewer wrapper divs in Drupal 8! In previous versions of Drupal, field markup introduced wrapper after wrapper, often unnecessarily. Now if you have only one value and no label for a field...there’s only one div.
Two base themes in Drupal 8: Classy and Stable
In general, your theme has the final say on Drupal’s markup, CSS, and JS. Themes can override templates, CSS, and JS that come from core modules, contributed modules and base theme. Themes can have parent-child relationships, with the parent theme serving as the base theme for a sub-theme. A sub-theme inherits templates, CSS, and JS from its base theme. Themes can also have grandparent themes or even great-grandparent themes: we’ll talk about chaining together contrib themes with core themes in just a bit.
Drupal’s markup comes in two flavors, depending on what you choose as your base theme.
- If you want to start with markup with sensible classes you can use as styling hooks, then you can use Classy as your base theme. This is similar to the approach used with Drupal 7’s default markup, but with classes and markup significantly improved.
- However, if you want markup that is even more lean, you can use Stable as your base theme; in fact that’s the default. Stable still has some classes needed for front-end UI components like the toolbar and contextual links, but in general has far fewer classes than Classy, and even fewer wrapper elements.
By providing two flavors of markup with the Stable and Classy base themes, Drupal 8 allows you to choose how you want to approach markup changes:
- Tweak the classes Drupal provides as a starting point (Classy),
- Only add classes where you think they are essential (Stable).
If you prefer to start from scratch in order to use highly customized markup patterns, Stable may be the right base theme for you. This approach can be useful when implementing a framework like Bootstrap or Foundation that relies upon very particular markup patterns.
Field markup: Stable vs Classy
Let’s look at one example of how markup can differ between Stable and Classy.
Here’s Classy field markup when you have a label and multiple field values:
<div class="field field--name-field-favorite-horses field--type-string field--label-above">
<div class="field__label">Favorite horses</div>
<div class='field__items'>
<div class="field__item">Black Stallion</div>
<div class="field__item">Shadowfax</div>
<div class="field__item">Hidalgo</div>
</div>
</div>
In contrast, here’s the same markup when using Stable:
<div>
<div>Favorite horses</div>
<div>
<div>Black Stallion</div>
<div>Shadowfax</div>
<div>Hidalgo</div>
</div>
</div>
Just for fun, look how much slimmer Classy’s markup is when only one value is allowed on a field, and the label is hidden:
<div class="field field--name-field-best-horse field--type-string field--label-hidden field__item">Mister Ed</div>
That markup gets even leaner with Stable:
<div>Mister Ed</div>
To see how far we've come, here's how that markup would look by default in Drupal 7:
<div class="field field-name-field-best-horse field-type-text field-label-hidden">
<div class="field-items">
<div class="field-item even">Mister Ed</div>
</div>
</div>
That’s a lot more markup than you really need when you know there will only ever be one value for a field.
From this example, you can see that Stable is a starting point. You would want to customize Stable’s markup in your theme to add sensible classes. Writing CSS using only HTML elements in your selectors is painful. However, with Stable you can build up only the classes you need, rather than spending time evaluating which classes in Classy should be retained.
Keeping Core markup reliable
One of the primary purposes of the Stable theme, which is new to core, is to provide a backwards compatibility layer for Drupal’s core markup, CSS, and JS. Those will all be locked within the Stable theme as of Drupal 8 RC1. You can rely upon Stable as your default base theme without worry that the markup will change on you during the Drupal 8 cycle.
The Classy theme will also provide reliable markup, CSS and JS, most likely by using Stable as its base theme.
So whether you choose Stable or Classy as your base theme, you can also rely on its markup whether you have Drupal 8.0.5 or Drupal 8.3.4 installed. Both Stable and Classy will still receive bug fixes—for example, if the wrong variable is being printed by a template. The goal is to make these fixes in a way that ensures backwards compatibility.
Drupal 8 also ships with two other themes, Bartik and Seven.
- Bartik is the default theme when you install Drupal 8 and demonstrates one possible front-end implementation.
- Seven serves as the default admin theme.
Both have been improved in Drupal 8 and use Classy as their base theme. Bartik and Seven can also continue to change throughout Drupal 8, so you wouldn’t want to use Bartik or Seven as a base theme. Bartik or Seven’s markup could be tweaked in 8.1 or 8.2, which could break your site’s appearance if you use Bartik or Seven as a base for your theme.
In the meantime, during the Drupal 8 cycle, core markup can continue to evolve. Contributors can continue to clean things up so that we don’t need to spend nearly as much time working on tidying our markup when work on Drupal 9 begins.
How to define the base theme in .info.yml
Many of a theme’s basic settings are defined in a file called MYTHEME.info.yml within your theme folder, where MYTHEME is replaced with the name of your theme. This is similar to the .info file in Drupal 8.
If you want to use Classy as your theme, add the following in your theme’s .info.yml file:
base theme: classy
If you want Stable as your base theme, you do not need to add a base theme setting to your theme’s .info.yml. If no base theme is declared, by default your base theme will be set to Stable.
If you don’t want a base theme at all, add this to your theme’s .info.yml file:
base theme: false
That would mean your theme would use Drupal 8’s core templates, CSS, and JS directly, rather than passing through Stable or Classy first. That’s a risky strategy. If something changes in core, you might need to update your theme accordingly.
Using Classy or Stable as your base theme is a more reliable way to ensure the stability of your theme.
Chaining base themes together
Contrib themes can also choose to use Classy or Stable as their base theme, or no base theme at all. That’s right, a base theme like Zen can have Stable or Classy as its base theme. A sub-theme of Zen would have Zen as its base theme, but would also inherit from Zen’s base theme, whether that’s Classy or Stable. So while you might end up using a contrib theme as a base for your theme, ultimately that contrib theme will likely trace back to one of the two base themes in core, Classy or Stable.
When you evaluate base themes like Zen or Omega or Adaptive Theme, make sure to check their info.yml file for the base theme setting. If you see base theme: false
, you may want to be wary as core markup will surely change. If you see Classy or no base theme setting at all, you’ll have an idea what kind of markup (and stability) to expect from that contrib theme.
To pull together what we've learned so far, this graphic created by Morten DK shows how Drupal's core themes interact with contrib themes or themes you might develop:
This is a good look at how things stand in October 2015, with Drupal 8 RC1 recently released. As more and more people try out Drupal 8 and build themes, we'll continue to develop a better understanding of how best to set up contrib and custom themes.
Learning more
You can learn more about theming in Drupal 8 by checking out John Hannah’s great articles on the subject, Drupal 8 Theming Fundamentals Part I and Part II
I’m definitely looking forward to working with markup in Drupal 8, more so than I ever have before. Hopefully you will too!