Typeface

Kolibri is translated into upwards of 30 languages, and the public content library contains resources in dozens more. There is no way to know in advance what text will be displayed, or which fonts are already available on the user's device.

To work around this challenge, products in the Kolibri ecosystem use the open source typeface Noto Sans maintained by Google. Noto includes a wide range of fonts that cover an enormous number of languages, scripts, and glyphs.

Kolibri must work offline, and therefore the design system has some special logic for loading fonts as-needed from the device. Studio on the other hand is in the cloud and relies on the Google Fonts API to load Noto.

Globally-available styles

The design system provides a set of reusable style constants, snippets, and dynamic values.

Constants are made available as SCSS variables and snippets are made available as SCSS placeholder selectors. For example, we provide a constant called $radius (defined as 4px) and a placeholder selector called %dropshadow-2dp which creates a 2dp drop shadow. These can be used to style an element by importing the definitions file:

Use these by importing the design system's definitions.scss file. For example, this HTML and SCSS in a Vue template:


      <div class="box">Hello!</div>
    

      @import '~kolibri-design-system/lib/styles/definitions'

      .box {
        @extend %dropshadow-2dp;

        border-radius: $radius;
        text-align: center;
      }
    

can help easily reproduce styles like:

Hello!

In order for Kolibri to be dynamically themed colors cannot be defined as SCSS constants. Instead, colors are defined in Javascript. Every Vue component instance gets a few reactive Vue objects attached to it which can be accessed in computed styles:

  • $themeBrand contains colors related to the aesthetic color scheme
  • $themeTokens contains colors with special meanings in Kolibri
  • $themePalette contains a wide range of additional compatible colors

For more informatiom see the Colors page .

Elevation and shadow

Kolibri products use a system of elevation based roughly on Google's Material Design. Material introduces the idea that UI container elements (menus, modals, side-bars, etc) exist on a particular "elevation" on the page, which defines which one is visible when they overlap.

Drop shadows

In the real world, the shadow an object casts is often a physical manifestation of its elevation.

The design system provides a set of pre-defined SCSS placeholder selectors which allow consistent application of realistic-looking shadows: 1dp, 2dp, and 6dp:

1dp
2dp
6dp

Follow the guidance below to decide what depth to use for a drop shadow:

1dp
containers, panels, controls
2dp
cards, app bars, buttons, menu, tooltips, snackbars
6dp
modals, card hover

This can be achieved by with the dropshadow helpers:


      @import '~kolibri-design-system/lib/styles/definitions'

      .box-1dp {
        @extend %dropshadow-1dp;
      }

      .box-2dp {
        @extend %dropshadow-2dp;
      }

      .box-6dp {
        @extend %dropshadow-6dp;
      }
    

Z-indexes

CSS z-index is sometimes used to determine whether some element will show in front of or behind overlapping elements. A common challenge is that z-index values get set to arbitrary numbers, which leads to ever-increasing and bizarre values to force one element to display over another.

In Kolibri products we try to use the conventional elevation dp values shown above as default z-index values. This ensures that, for example, a custom menu should always show below a custom nav drawer even if there was no coordination between the authors of those components.

Note that it is not encouraged to set a z-index on every element. There are many reliable ways in CSS to show one item over another and z-index is often used a last resort.

The diagram below (with credit to Google) shows the conventional elevations:

Applying these conventions consistently helps build components that look and interact with each other in predictable ways.

Easing and timing

Rapid visual transitions for elements that move or change state help users understand what is happening on the page and add a level of polish that makes the app feel smooth and responsive:

Immediate hover
Easing hover

Easing functions should be applied to every visual state transition, including color changes.

We have a "standard" easing curve as well as curves for for outgoing items (accelerating) and incoming items (decelerating). Apply a transition with default duration $core-time and use one of the SCSS placeholder selectors:

  • %md-standard-func
  • %md-accelerate-func
  • %md-decelerate-func

For example:


      @import '~kolibri-design-system/lib/styles/definitions'

      .ease:hover {
        @extend %dropshadow-6dp;
        @extend %md-standard-func;

        cursor: pointer;
        transition: all $core-time;
      }
    

Focus outline

We provide a consistent, high-contrast focus highlight that is enabled only when we detect that the user is navigating using the keyboard (i.e. tabbing from item to item). Use the $coreOutline attribute attached to Vue objects for this.