5 minute video introducing DXPR Theme features

 

Introduction

DXPR theme is our premium Drupal theme. It is a subtheme of Bootstrap base theme and uses the Bootstrap 3 framework. Something that might not be clear to new prospective clients is that DXPR theme does not include DXPR Builder. DXPR Builder is a separate module. DXPR theme and DXPR Builder can be used independently.

We call DXPR theme a "Framework theme" because thanks to it's 200+ settings for layout, menu, typography, blocks, and more it can be used as a platform to design a custom look and feel for your website without needing to code.

 

1. Bootstrap base theme and DXPR Theme

We decided to use Bootstrap base theme because it's a very popular and familiar Drupal project. One of the nice things about this base theme is that it handles making all Drupal's forms, messages, tabs, and other core components into Bootstrap HTML. This helps create a holistic, consistent design even if you add new modules to your site that are not made to work with Bootstrap 3. There are also some disadvantages to using this base theme, it's overengineerd and even comes with it's own theme settings API. The developer has worked very hard to create this beast of a base theme but now development is staggered and no-one is stepping up to migrate this beast to Bootstrap 4: https://www.drupal.org/project/bootstrap/issues/2554199

Templates

Since DXPR theme is sub-theming Bootstrap base theme, every time you create a new template you should copy it from bootstrap base theme and then modify it.

 

2. Javascript development in DXPR Theme

In DXPR theme we use a lot of jQuery, but it certain places where performance is critical we replace jQuery with plain javascript code. 

DXPR theme uses Grunt.js as task runner. Grunt will run the following tasks:

  1. Watch Grunt will watch for changes and run tasks
  2. Compile Sass files into compressed CSS
  3. Postcss to add vendor prefixes, supporting older browsers (last 2 versions of each browser and ie 9)
  4. Uglify (compress) all javascript files

 

Javascript performance

jQuery is slower than pure javascript. Examples of where we remove jQuery and use additional functions for performance reasons this window resize callback and this window scroll callback. In both these cases performance is extremely important because the scroll and resize events will fire up to thousands of times per second. More importantly, on weaker systems and browser they will fire less frequently because of performance restraints. This means you will max out the user's system and the website can become sluggish or crash.

  • The _.debounce function in the resize callback example above will run the code only once, after the user is done resizing the viewport.
  • The _.throttle function in the scroll callback with a 100ms parameter will run our code a maximum of 10 times per second, while the user is scrolling.

The above 2 functions are part of the underscore library. Underscore is included in DXPR Builder but not in DXPR theme. Therefore, in DXPR theme we detect if these functions exist and create them when needed. Undercsore is also included in Drupal 8 core but not in Drupal 7 core.

For more guiding about Javascript performance please see our Javascript Development Guide

 

3. CSS & SASS in DXPR Theme

In DXPR theme we make use of SASS in order to code more efficiently. Rather than writing very long selectors, we can have nested selectors that create a visually intuitive hierarchy in our sass code. We split up our sass codein into 4 folders:

  1. base (sitewide layout and design code)
  2. components (elements that do not show on every page)
  3. helpers (utility classes, shortcuts to brand colors etc.)
  4. vendor-extensions (overrides or extensions of CSS files included in 3rd party software components, like Bootstrap framework, jQuery UI, and any Drupal modules and themes that need overrides) 

We split our css up into many files so that the files are easy to scan, read, and understand. Another advantage of this architecture is that developers who are working on different css components can submit pull requests without merge conflicts. We aim to keep all .scss files smaller than 300 lines

Classnames

Unfortunately the bootstrap 3 basetheme does not use highly structured classnames. In DXPR theme we try to use more structured classnames. We don't follow any naming convention completely, such as SMACSS or BEM but we take inspiration from these frameworks and apply structure where we see fit. Example classes:

.body--glazed-nav-desktop
.glazed-header
.glazed-header--fixed
.glazed-header--overlay
.glazed-main-menu 
.glazed-megamenu__heading
.dxpr-theme-util-float-left

As you can see from the classes above we namespace our classnames with the theme name, then we have element names with - characters separating words. We use double dashes to indicate the state of an element.

Very sparingly we use double underscores to add more context to a classname, in the form of glazed-parent-element__child-element but we don't want to apply this everywhere to avoid bloating our code too much. 

 

4. Color module integration

The color modules is a complex module with many capabilities, for example it can generate images with a transparent overlay, and replace the background of the image with a solid color or even gradients, thereby recoloring the images. It also has the capability to scan your CSS file for color codes, and it will not just replace colors but also try to find colors that are not in the palette, but are close to colors in the palette. It will then try to shift these colors in HSL color space and translate them back to RGB color space. The idea behind this feature is that you can create a palette with 5 colors, and then you CSS can create dozens of colors that are lighter, darker, or otherwise close shades of these 5 colors. The color module will then intelligently shift these colors along with your palette.

Color shifting

Unfortunately this color shifting system is flawed. Sometimes it will match colors that you don't want to shift. But more annoyingly the algorithm has rounding errors that will cause gray colors to shift to pink, green, or blue. To circumvent this problem all HEX color values in our CSS our accounted for in our palette:

https://github.com/jjroelofs/glazed/blob/8.x-1.1.3/color/color.inc#L39

This ensures that all colors are exactly matched and color module will not try to shift colors in HSL color space.  It is possible to add colors that you don't want to include in the palette, for example the color module won't pick up on rgba() color values.

Important: Color module will cache your CSS files

If you're editing DXPR theme CSS files and you're wondering why the changes are not showing up, it's probably because color module keeps a copy of recolored CSS files in the files folder. In order to regenerate these files you have to save the theme settings form. Clearing caches doest now affect these files.

You will find that all theme demos will load the DXPR css files from the files folder except the Main demo. This is because the main demo uses the default color palette, and thus color module will not rewrite and cache the css files. This makes the Main demo most attractive for CSS development.

 

5. Theme settings and the theme settings form

The theme settings form in DXPR theme let's you control over 200 theme settings. We ask users to also install the DXPR Helper module. This module will enable DXPR theme at the theme setting form page, instead of the administration theme. That way we can use our theme to totally contorl the design and experience of our theme settings form. We also make extensive use of graphical switches and sliders to create a more intuitive, designed, experience here. 

The theme settings are complicated, this is not a place for non-technical users. It's a place where site builders and webmasters can have great control over their website's look and feel without coding, or with minimal coding.

Theme settings architecture

Because we have so many theme settings in DXPR theme, we split our code into files, and split those files into "feature" folders. The following feature folders are found in glazed/features:

  • sooper-block-design
  • sooper-custom-css
  • sooper-fonts
  • sooper-header
  • sooper-layout
  • sooper-page-title
  • sooper-portfolio
  • sooper-prevnext
  • sooper-typography

Each of these folders can contain one or more of the following 3 files:

  • feature-theme-settings.inc (code generating form elements in the theme settings form)
  • feature-theme-settings-controller.inc (these files are called in a loop in template.php (D7) and in DXPR.theme (D8)
  • feature-theme-settings-css.inc (code that builds CSS code based on theme settings)

 

How the theme settings take effect

There are different mechanisms through which theme settings can take effect:

  1. Generated CSS code
  2. Logic in theme preprocess functions or twig files
  3. Logic in Javascript code

 

Generated CSS code

When the theme settings form is saved, a loop goes over all the *-theme-settings-css.inc files and collects all CSS output. This output is saved into a file in the files folder. This mechanism is used where merely class-switching cannot cover all options, for example with theme settings taking numeric values (layout width, font size, etc.).

This function is stored in a separate file, because we also need to call it during Drupal's site installation process, when installing a distribution that includes custom DXPR theme settings:

example

 

Logic in theme preprocess functions or twig files

We make a lot of theme changes by simply switching out classes. In Drupal 7 as a rule, the logic controlling HTML classes must exist in preprocess functions and the template files will be free of logic. In Drupal 8 this changed and logic will go in twig files.

Drupal 7 example | Drupal 8 example

 

Logic in Javascript code

This is used very sparingly because generally it's more performant to handle things in backend code. 

Drupal 7 example in admin js | Drupal 8 example

In Drupal 7 we store glazed settings in drupal.settings.glazed and in Drupal 8 in Drupalsettings.glazed. In Drupal 8 we attach settings to elements using the #attached property. In Drupal 7 we use the drupal_add_js function.

Drupal 7 example:

drupal_add_js(array('glazed' => array('palette' => theme_get_setting('palette', 'glazed'))), 'setting');

Drupal 8 example:

$form['#attached']['drupalSettings']['glazedSettings'] = ['palette' => $palette];

 

7. Browser Support

I think it's about 4 years ago that I last had a complaint about some serious browser issue. Luckily the days of supporting internet explorer are gone. There is of course a new challenge in supporting mobile devices, tablets, televisions, and who knows what else in the future, but so far browser support has not been a big concern for DXPR Theme. In our PostCSS connfiguration in GruntJS we support IE9 but we never test it.

 

8. The Menu System

@todo

 

9. Updating glazed_starterkit

Every time you make an update in dxpr.css, our main css file, a copy of dxpr.css needs to be cloned into the glazed_starterkit folder. This is required due to a bug in the color module, that will copy the file from there instead of from the glazed theme folder.