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:
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.
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.
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:
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.
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:
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.