Totara LMS 9 approach to theme management

This document describes the philosophy and practical details of theme management in Totara LMS 9. You may also find the documentation on compiling LESS useful.

Purpose of each theme

Base

Fundamental, core components that no theme could do without go here, to avoid having to duplicate them in all other themes. The obvious one here is the font icon implementation. 3rd party themes must always include 'base' as a parent theme, we automatically inject it into any theme that doesn't do so.

Roots

Contains Bootstrap 3 styling, extended to apply to all Totara components. The key functionality provided here is layout and basic styling. The styling should be functional not opinionated. The theme should remain as neutral as possible but everything should make sense and work in Roots. We will recommend that 3rd party themes extend this theme as well as base as long as they are happy using Bootstrap 3 as a framework. If they don't want to use Bootstrap 3 they should not extend this.

Basis

Contains minimal changes required to put an opinionated brand on top of Roots. This means layout changes to match our in-house theme design as well as Bootstrap overrides to apply design colours, minor stylistic changes etc. We would not expect 3rd party themes to extend Basis unless they make very minor modifications (such as LESS variable overrides). Basis serves as a good example of how to extend Roots for 3rd party themers.

Bootstrapbase, Standard Totara Responsive, Custom Totara Responsive, Kiwifruit

These themes have been deprecated in Totara Learn 9 and have been removed in Learn 10. These themes should continue to work as before (in Learn 9) so any custom themes that used these themes as parent themes should work largely unchanged. Note that core template / renderer changes which affect these themes (for example 9.0 updates to the Main Menu) are mitigated by overriding back to the pre 9.0 structure in Bootstrapbase.
These have been removed in 10 as we have come across a large number of conflicts between Bootstrap 2 & 3. We do not recommend re-loading them into Learn 10 for this reason.

Inheritance

Inheritance works differently depending on the area:

LESS

We want to make use of LESS variables, so the regular Moodle approach to CSS inheritance (include CSS from all themes starting from parent working down) won't work. Instead we:
  • Disable Moodle CSS inheritance using $THEME->parents_exclude_sheets()
  • Within less/totara.less, include totara.less from the parent theme
  • Add any theme-specific LESS imports below that
  • Finally override any variables set by the parent theme that you want to change (see next section on overriding)

It is worth reading about LESS lazy-loading of variables to make sure you understand how variable inheritance works - it is not obvious.

NOTE: When developing a theme in this manor, Grunt will need to be run after all upgrades (including minor releases) as there may be changes to LESS in Roots and Basis which will not show up until after Grunt is run

Overriding Bootstrap / LMS specific styles

Bootswatches provide a portable convention for theming and extending the Bootstrap framework. In Roots and Basis these overrides can be found in their corresponding less/bootswatch/variables.less and less/bootswatch/bootswatch.less files. The Basis Bootswatch extends the Roots Bootswatch. Styles specific to LMS (e.g. using mixins to apply Bootstrap styles to core markup which cannot yet be converted to Bootstrap markup or LMS specific components) can be found under the less/totara directory. When creating overrides in child themes of Roots (e.g. Basis) we adhere to this structure. This is an internally enforced best practice and while we recommend this approach it is not a requirement for working with LESS in the new themes.

Layouts

The Base theme defines all the layouts to ensure they are available, but the layout file is not appropriate for real use. Themes are expected to set all layouts or use a parent which does so. For example Roots sets all of the layouts. Basis inherits from Roots with a few overrides.

Renderers

Ideally the default core renderers will return the appropriate output for the Roots theme and there would be no overridden renderers in roots. Legacy output will be provided by overridden renderers in bootstrapbase or standardtotararesponsive.
 

Templates

Similar to renderers, ideally the core templates would be appropriate for Roots and won't need to be overridden in Basis.

Flexible icons

The original definitions are in Base. Themes can override but we define sensible defaults so there shouldn't be any need to do so in Roots or Basis. 3rd party themes have the freedom to override icons. If they want to override every usage of a particular icon, the best way is overriding the icon's unique identifier in the $icons array via theme/themename/pix/flex_icons.php. E.g. override the backpack icon in theme/mytheme/pix/flex_icon.php by adding:


$icons = array(
    'backpack' => array(
        'template' => 'mytheme/customicon',
        'data' => array(
            'classes' => 'my-overridden-class', 
            'mycustomdata' => 'Custom string for template',
        ),
    ),
);

...and potentially including some CSS to style based on the .my-overridden-class selector. Note the above is for the purposes of illustration only.

Alternatively, if the themer wants to override a specific icon only in certain locations, or use their own font to provide new icon sets, they will need to override in CSS. The file /theme/base/less/totara/ft.less provides a good example of how to do that.

Choosing how to override a theme

As a theme designer, there are lots of ways to override a parent theme, and the method you choose will have an impact on how maintainable your theme is in the long run (e.g how robust it is to changes in the parent theme). In general the hierarchy of preference is as follows - whenever possible use an early approach in this list and only resort to a later option if the earlier ones aren't feasible:

  1. LESS variables
  2. CSS changes
  3. Template overrides
  4. Renderer overrides