Themes¶
As of the Kilo release, styling for the OpenStack Dashboard can be altered
through the use of a theme. A theme is a directory containing a
_variables.scss
file to override the color codes used throughout the SCSS
and a _styles.scss
file with additional styles to load after dashboard
styles have loaded.
As of the Mitaka release, Horizon can be configured to run with multiple themes available at run time. It uses a browser cookie to allow users to toggle between the configured themes. By default, Horizon is configured with the two standard themes available: ‘default’ and ‘material’.
To configure or alter the available themes, set AVAILABLE_THEMES
in
local_settings.py
to a list of tuples, such that
('name', 'label', 'path')
name
The key by which the theme value is stored within the cookie
label
The label shown in the theme toggle under the User Menu
path
The directory location for the theme. The path must be relative to the
openstack_dashboard
directory or an absolute path to an accessible location on the file system
To use a custom theme, set AVAILABLE_THEMES
in local_settings.py
to
a list of themes. If you wish to run in a mode similar to legacy Horizon,
set AVAILABLE_THEMES
with a single tuple, and the theme toggle will not
be available at all through the application to allow user configuration themes.
For example, a configuration with multiple themes:
AVAILABLE_THEMES = [
('default', 'Default', 'themes/default'),
('material', 'Material', 'themes/material'),
]
A configuration with a single theme:
AVAILABLE_THEMES = [
('default', 'Default', 'themes/default'),
]
Both the Dashboard custom variables and Bootstrap variables can be overridden.
For a full list of the Dashboard SCSS variables that can be changed,
see the variables file at
openstack_dashboard/static/dashboard/scss/_variables.scss
.
In order to build a custom theme, both _variables.scss
and _styles.scss
are required and _variables.scss
must provide all the default Bootstrap
variables.
Inherit from an Existing Theme¶
Custom themes must implement all of the Bootstrap variables required by
Horizon in _variables.scss
and _styles.scss
. To make this easier, you
can inherit the variables needed in the default theme and only override those
that you need to customize. To inherit from the default theme, put this in your
theme’s _variables.scss
:
@import "/themes/default/variables";
Once you have made your changes you must re-generate the static files with:
python manage.py collectstatic
By default, all of the themes configured by AVAILABLE_THEMES
setting are
collected by horizon during the collectstatic process. By default, the themes
are collected into the dynamic static/themes directory, but this location can
be customized via the local_settings.py
variable: THEME_COLLECTION_DIR
Once collected, any theme configured via AVAILABLE_THEMES
is available to
inherit from by importing its variables and styles from its collection
directory. The following is an example of inheriting from the material theme:
@import "/themes/material/variables";
@import "/themes/material/styles";
All themes will need to be configured in AVAILABLE_THEMES
to allow
inheritance. If you wish to inherit from a theme, but not show that theme
as a selectable option in the theme picker widget, then simply configure the
SELECTABLE_THEMES
to exclude the parent theme. SELECTABLE_THEMES
must
be of the same format as AVAILABLE_THEMES
. It defaults to
AVAILABLE_THEMES
if it is not set explicitly.
Bootswatch¶
Horizon packages the Bootswatch SCSS files for use with its material
theme.
Because of this, it is simple to use an existing Bootswatch theme as a base.
This is due to the fact that Bootswatch is loaded as a 3rd party static asset,
and therefore is automatically collected into the static directory in
/horizon/lib/. The following is an example of how to inherit from
Bootswatch’s darkly
theme:
@import "/horizon/lib/bootswatch/darkly/variables";
@import "/horizon/lib/bootswatch/darkly/bootswatch";
Organizing Your Theme Directory¶
A custom theme directory can be organized differently, depending on the
level of customization that is desired, as it can include static files
as well as Django templates. It can include special subdirectories that will
be used differently: static
, templates
and img
.
The static
Folder¶
If the theme folder contains a sub-folder called static
, then that sub
folder will be used as the static root of the theme. I.e., Horizon will
look in that sub-folder for the _variables.scss and _styles.scss files.
The contents of this folder will also be served up at /static/custom
.
The templates
Folder¶
If the theme folder contains a sub-folder templates
, then the path
to that sub-folder will be prepended to the TEMPLATE_DIRS
tuple to
allow for theme specific template customizations.
Using the templates
Folder¶
Any Django template that is used in Horizon can be overridden through a theme. This allows highly customized user experiences to exist within the scope of different themes. Any template that is overridden must adhere to the same directory structure that the extending template expects.
For example, if you wish to customize the sidebar, Horizon expects the template
to live at horizon/_sidebar.html
. You would need to duplicate that
directory structure under your templates directory, such that your override
would live at { theme_path }/templates/horizon/_sidebar.html
.
The img
Folder¶
If the static root of the theme folder contains an img
directory,
then all images that make use of the {% themable_asset %} templatetag
can be overridden.
These assets include logo.svg, splash-logo.svg and favicon.ico, however overriding the SVG/GIF assets used by Heat within the dashboard/img folder is not currently supported.
Customizing the Logo¶
Simple¶
If you wish to customize the logo that is used on the splash screen or in the
top navigation bar, then you need to create an img
directory under your
theme’s static root directory and place your custom logo.svg
or
logo-splash.svg
within it.
If you wish to override the logo.svg
using the previous method, and if the
image used is larger than the height of the top navigation, then the image will
be constrained to fit within the height of nav. You can customize the height
of the top navigation bar by customizing the SCSS variable: $navbar-height
.
If the image’s height is smaller than the navbar height, then the image
will retain its original resolution and size, and simply be centered
vertically in the available space.
Prior to the Kilo release the images files inside of Horizon needed to be replaced by your images files or the Horizon stylesheets needed to be altered to point to the location of your image.
Advanced¶
If you need to do more to customize the logo than simply replacing the existing
SVG, then you can also override the _brand.html through a custom theme. To use
this technique, simply add a templates/header/_brand.html
to the root of
your custom theme, and add markup directly to the file. For an example of how
to do this, see
openstack_dashboard/themes/material/templates/header/_brand.html
.
The splash / login panel can also be customized by adding
templates/auth/_splash.html
. See
openstack_dashboard/themes/material/templates/auth/_splash.html
for an
example.