The landscape of Drupal theme development has drastically changed in recent years. Cutting-edge front-end development tools are now considered standard within Drupal enterprise builds.
Developers now can leverage engineering recipes into rapid development with powerful front-end automation tools like Gulp and Sass. But with these tools comes the responsibility to address performance and extensible methods within large teams. So a consistent and scalable method of development is needed. By following the techniques recommended in this blog, you will see an increase in theming velocity throughout the lifecycle of your project.
What is Component-driven Theme Development in Drupal?
When you step back and look holistically at your Drupal homepage, you'll see that it is essentially nothing more than a collection of several modular pieces. So the primary focus of this method in Sass – which is an extension of CSS that adds power and elegance to the basic language – revolves around developing your site as these modular pieces.
The construction of the varied isolated pieces are intended to exist as stand-alone components, but they are also designed to be combined and extended upon. This means steering away from the tendency to couple your styles to Drupal-rendered HTML markup. If you follow this same train of thought, this means that these elements should be coded in a manner so they maintain their stylistic integrity regardless of location on the page. Teams following this pattern are accelerating their development efforts by treating theming tasks as building blocks to be extended upon.
What Are the Benefits of Using Components in Drupal?
One of the primary driving factors behind component-driven development is the DRY (Don’t Repeat Yourself) principle. Reducing the compiled CSS will result in improved performance and less code to maintain. Your theme will also become more predictable by removing layout code that's specific to containers. Following the component methodology builds consistency by moving common styles to base HTML elements so they can be reused throughout components. This leads to a more consistent rate of development with each sprint life cycle since momentum will be accruing as your component count increases.
Why Are These Methods Now More Important Than Ever?
To appreciate the timing of this workflow consider these concepts in a linear timeline:
- Progression of Drupal’s Theming Layer: CMS has drastically improved to offer developers substantial flexibility in rendering structural markup, classes, and IDs. Alongside these features is a wide range of preprocessing options to adjust granular components according to contextual scenarios. It is now easier than ever to proactively assign classes while dynamically adjusting context to match a component pattern by dictating structural rules.
- Evolution of Front-end Development: The accelerated evolution of front-end development has yielded tools that previously didn’t exist. In addition to CSS compilation with Sass, common tasks or testing can now be automated with tools like Gulp or Grunt. These tools and languages are instrumental in rapid development, but can also adversely result in things like bloated CSS or overly-specific selectors.
In the following example, something as simple as nesting the second class “views-row” results in twice as much rendered CSS:
.block-custom, .views-row {
width: 98.5%;
display: block;
border-radius: 5px;
span {
font-weight: bold;
font-weight: 500;
}
}
While we have extensive power with available front-end tools, it’s important to remember that our front-end methods still need to catch up with our front-end tools. Using advanced nested selectors in Sass is great, but the flip side may result in not allowing your code to be extensible or even easily maintainable.
Methods of Implementing Component-driven Engineering
A basis for thinking through scenarios with Drupal components requires a proactive approach to Drupal markup and its classes when writing Sass. This means dictating to both the classes and markup, not just reacting to it. So let’s extend this thinking a bit further by considering two opposing methods: reacting to classes versus defining classes.
If we look at this example of reacting to classes, you will see why this methods quickly fails. By essentially chasing down the markup, you're creating coupled code that is both un-extendable and counterintuitive.
aside form.login-form input.edit-name,
div.view-views-articles.view-display-id-block .views-row,
div.panel-example-pane > .inside-content h2,
div.view-taxonomy-term .header .icon {
color: $greenish;
}
By proactively defining classes with a combination of preprocessing and Sass, you will establish a repeatable baseline to extend upon. This same technique can just as easily be applied with things like view modes, custom theme functions and other Drupal standards.
// hook_form_alter
function MODULENAME_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'user_login') {
$form['name']['#attributes']['class'][] = 'green';
}
}
// theme_preprocess_views_view_unformatted
function THEMENAME_preprocess_views_view_unformatted(&$vars) {
$rows = $vars['rows'];
if ($vars['view']->name == 'articles') {
foreach ($rows as $id => $row) {
$vars['classes'][$id][] = 'green';
$vars['classes_array'][$id] = implode(' ', $vars['classes'][$id]);
};
}
}
// sass file
.green {
color: $greenish;
}
Architecting Your Sass as Object Oriented CSS
Nicole Sullivan introduced the guiding principles of Object-Oriented CSS (OOCSS) in 2008. The OOCSS methodology was introduced before Sass had even hit its full stride, so with all the modern-day tools it is even more relevant. Since its introduction, it has stood out as one of the most solid modular systems for building enterprise-grade sites.
The value of OOCSS can be nicely summed up by Sullivan herself: “The purpose of OOCSS is to encourage code reuse and, ultimately, faster and more efficient stylesheets that are easier to add to and maintain.”
The two primary principles of OOCSS are:
- Separate Structure & Skin
- Separate Container & Content
In this example, you would separate this code out into two different blocks. The first three lines would go in a class designated for structure, and the last three lines would be moved to a class for skin.
// Separate Structure & Skin
.sideblock {
padding: 10px;
min-height: 300px;
width: 100%;
border: solid 1px gold;
box-shadow: rgba(0, 0, 0, .5) 2px 2px 5px;
background: linear-gradient(#ccc, blue);
}
In the following code, the requirement is that a h2 needs to reside within the footer and not offering flexibility. A better way would be to use a .header-tag
class that could live on any type of element regardless of DOM structure.
// Separate Container & Content
footer h2 {
font-family: Helvetica, sans-serif;
font-size: .8em;
color: purple;
text-shadow: rgba(0, 0, 0, .3) 3px 3px 6px;
line-height: 1;
}
Progressive Enhancement Using Re-Usable Patterns in OOCSS
When scoping out the theming of a large Drupal project, step back and look at the sequential steps of development. Whether you're dealing with individual components or entire pages, you can still break out things in re-usable patterns. The intent then is to build a collection on individual pieces to be combined as needed. This means scaling down your Sass into smaller segments to be used in multiple scenarios based on the purpose of the @extend
or @include
.
Welcome Folks
Muffin ice cream sweet macaroon jelly-o bear claw donut bonbon. Dessert caramels cupcake pie oat cake. Jelly-o cupcake caramels.
.text-white {
text-shadow: 0 0px 5px black;
color: $whiteish;
}
.tree-background {
@extend %tree-image-full;
}
.golden-block {
border: 2px solid gold;
}
Component-based Drupal takes a theoretical and practical look at advanced Drupal engineering techniques to speed up development time for enterprise projects. Hopefully these recommended steps will increase velocity and cut development time after each sprint life cycle.