In Drupal 8 you can create base themes and subthemes. A base theme provides some set of predefined styles and functionality that a frontend developer can base a subtheme on. Any theme can be used as a base theme, even if it is a subtheme of some other theme.
Drupal 8 comes with five preloaded themes, located in core/themes/
.
-
Stable: Default base theme for all other themes unless otherwise specified. It is a minimalist theme, that only introduces essential CSS and functionality.
-
Classy: Base theme that comes prepackaged with "sensible" default markup and css classes.
-
Bartik: Based on
Classy
. The default frontend Drupal theme. It is simple and responsive. -
Seven: Based on
Classy
. The default admin Drupal theme. -
Stark: Is not based on any other theme. It is intentionally styleless to demonstrate default Drupal HTML, CSS and Javacript from core and contrib modules.
Choosing a base theme is a big decision when creating a new Drupal theme as it lays the framework for the way you will be building your frontend. From a D8 perspective,
Stable
and Classy
are the two standard base themes provided out of the box, although you could technically use Bartik
, Seven
and Stark
as a base theme if you really wanted to.
The reason Drupal 8 provides two base themes is to appeal to two different groups of developers:
- "Sensible 2/3" developers who want sensible markup and default classes to apply CSS with minimal overrides.
- "Clean 1/3" developers who want a minimalist theme that doesn't place unnecessary markup and css upon themers.
As a compromise, Stable
was established for the minimalists, and Classy
was for those wanting sensible markup and classes.
See Results of Drupalcon Austin's Consensus Banana for more information about that decision.
But these are only two out of a theoretically infinite number of base themes you can choose from, including a custom base theme that is shared by all of your different projects.
You can also opt out of using a base theme (see Stark
theme), but just recognize
that by doing so you are no longer guaranteeing backwards compatibility when core
functionality changes.
Custom and third-party themes should be installed in /themes/{themename}
.
Inside each theme it is recommended to have css
, js
and images
directories.
Drupal automatically searches the themes directory looking for {themename}.info.yml
.
This file provides information about your theme to Drupal.
For example - substable.info.yml
:
name: Substable
type: theme
description: 'A stable subtheme'
core: 8.x
libraries:
- substable/global-styling
- substable/global-scripts
base theme: stable
regions:
header: Header
content: Content
sidebar_left: 'Sidebar - Left'
sidebar_right: 'Sidebar - Right'
footer: Footer
Here is a list of available theme keys from Defining a theme with an .info.yml file:
- name (required) - The human-readable name. This will appear on the "Appearance" page where the theme is activated.
- type (required) - Indicates the type of extension, i.e., "module", "theme", or "profile". For themes this should always be set to "theme".
- description (optional) - The description, displayed on the "Appearance" page.
- package (optional) - Specifies a "package" that allows you to group themes together.
- core (required) - Specifies the version of Drupal core that the theme is compatible with.
- php (optional) - The minimum version of PHP required. Defaults to value of
DRUPAL_MINIMUM_PHP
constant.- version (optional) - Specifies a version. For themes hosted on drupal.org, the version number will be filled in by the packaging script. Do not specify it manually, but leave out the version line entirely.
- libraries (optional) - A list of libraries (which can contain both CSS and JavaScript assets) to add to all pages where the theme is active.
- libraries-override (optional) - A collection of libraries and assets to override.
- base theme (recommended) - A theme can inherit the resources from another theme by specifying it as a base theme. It is recommended to use classy or stable (stable is the default if the key is not supplied) – this makes it easier for your theme to inherit future changes in core theming.
- hidden (optional) - Indicates whether or not to hide the theme from the "Appearance" page so that it cannot be enabled/disabled via the UI.
- engine (optional) - The theme engine. Defaults to "twig".
- screenshot (optional) - The path to screenshot relative to the theme's .info.yml file. Screenshots should be 588 pixels wide and 438 pixels high, though they are displayed at a smaller size. By default, Drupal will look for a file named "screenshot.png" in the root of your theme folder and use that as the theme image on the "Appearance" page.
- regions (optional) - A list of theme regions. (Note that region keys are not preceded by a dash.) A content region is required. Read more about adding regions to a theme.
- regions_hidden (optional) - A list of inherited regions to remove.
- features (optional) - A list of features to expose on the theme "Settings" page.
- stylesheets-remove (deprecated) - A list of stylesheets from other modules or themes to remove from all pages where the theme is active. Each value must be a full path relative to the docroot to resolve ambiguity when more than one file with the same name exists. In cases where the file is part of a library that belongs to a module or theme, a token in the form
@module_or_theme_name
can be used in place of the full path. Note that when using the token the value must be quoted because"@"
is a reserved indicator in YAML. Note: This key is deprecated and will be removed in Drupal 9. In most caseslibraries-override
should be used.- ckeditor_stylesheets (optional) - A list of stylesheets to add to the CKEditor frame.
If you wish to include Javascript and CSS in your theme, you can do so by creating
libraries in {themename}.libraries.yml
.
For example - substable.libraries.yml
:
global-styling:
version: 1.x
css:
theme:
css/style.css: {}
css/print.css: { media: print }
global-scripts:
version: 1.x
js:
js/substable.js: {}
dependencies:
- core/jquery
Libraries also need to be included in the {themename}.info.yml
file. See substable.info.yml
example above.
See the Javascript/jQuery section for more information about Javascript and attaching libraries to a subset of pages.
The breakpoints
module allows you to predefine breakpoints for use in your
responsive design. Breakpoints are defined in a {themename}.breakpoints.yml
file.
Here is an example from the bootstrap theme:
bootstrap.screen-xs-max:
label: screen-xs-max
mediaQuery: 'all and (max-width: 767px)'
weight: 1
multipliers:
- 1x
bootstrap.screen-sm-min:
label: screen-sm-min
mediaQuery: 'all and (min-width: 768px)'
weight: 1
multipliers:
- 1x
bootstrap.screen-sm-max:
label: screen-sm-max
mediaQuery: 'all and (max-width: 991px)'
weight: 1
multipliers:
- 1x
bootstrap.screen-md-min:
label: screen-md-min
mediaQuery: 'all and (min-width: 992px)'
weight: 1
multipliers:
- 1x
bootstrap.screen-md-max:
label: screen-md-max
mediaQuery: 'all and (max-width: 1199px)'
weight: 1
multipliers:
- 1x
bootstrap.screen-lg-min:
label: screen-lg-min
mediaQuery: 'all and (min-width: 1200px)'
weight: 1
multipliers:
- 1x
From Working with breakpoints in Drupal 8:
Please note that inputting your CSS breakpoints into your
breakpoints.yml
file is only necessary when Drupal needs to interact with the breakpoints as in the case of the Responsive Images module.
- label - A human readable label for the breakpoint.
- mediaQuery - Media query text proper, e.g. 'all and (min-width: 851px)'.
- weight - Positional weight (order) for the breakpoint.
- multipliers - Supported pixel resolution multipliers.
From Working with breakpoints in Drupal 8:
Breakpoints can be organized into groups. Modules and themes should use groups to separate out breakpoints that are meant to be used for different purposes, such as breakpoints for layouts or breakpoints for image sizing.
yourtheme.group1.mobile:
label: narrow
mediaQuery: ''
weight: 0
multipliers:
- 1x
group: yourtheme.group1
yourtheme.group1.narrow:
label: narrow
mediaQuery: '(min-width: 560px)'
weight: 0
multipliers:
- 1x
- 2x
group: yourtheme.group1
yourtheme.group1.wide:
label: wide
mediaQuery: '(min-width: 851px)'
weight: 1
multipliers:
- 1x
- 2x
group: yourtheme.group1
yourtheme.group2.mobile:
label: narrow
mediaQuery: ''
weight: 0
multipliers:
- 1x
group: yourtheme.group2
yourtheme.group2.narrower:
label: narrow
mediaQuery: '(min-width: 400px)'
weight: 0
multipliers:
- 1x
- 2x
group: yourtheme.group2
yourtheme.group2.wider:
label: wide
mediaQuery: '(min-width: 1001px)'
weight: 1
multipliers:
- 1x
- 2x
group: yourtheme.group2
You can also add breakpoints to breakpoint groups defined by other modules or themes, but you must use the full name.
yourmodule.yourtheme.group2.superwide
label: superwide
mediaQuery: '(min-width: 1501px)'
weight: 1
multipliers:
- 1x
- 2x
group: yourtheme.group2
All regions should be declared in the theme info file. The keys match the machine name and the values match the label for each available region.
For example:
regions:
header: Header
content: Content
sidebar_left: 'Sidebar - Left'
sidebar_right: 'Sidebar - Right'
footer: Footer
Then each region can be referenced in your page.html.twig
file:
<div class="container">
{% if page.header %}
<div class="row">
<div class="header col-xs-12">
{{ page.header }}
</div>
</div>
{% endif %}
<div class="row">
{% if page.sidebar_left %}
<div class="sidebar-left col-xs-2">
{{ page.sidebar_left }}
</div>
{% endif %}
{% if page.sidebar_left and page.sidebar_right %}
<div class="content col-xs-8">
{{ page.content }}
</div>
{% elseif page.sidebar_left or page.sidebar_right %}
<div class="content col-xs-10">
{{ page.content }}
</div>
{% else %}
<div class="content col-xs-12">
{{ page.content }}
</div>
{% endif %}
{% if page.sidebar_right %}
<div class="sidebar-right col-xs-2">
{{ page.sidebar_right }}
</div>
{% endif %}
</div>
{% if page.footer %}
<div class="row">
<div class="footer col-xs-12">
{{ page.footer }}
</div>
</div>
{% endif %}
</div>
Default regions
If you declare any regions in your theme, even just one, all the default regions will no longer be applied and you assume responsibility for declaring any and all regions you want to use.
- drupal.org - Defining a theme with an .info.yml file
- drupal.org - Adding Stylesheets (CSS) and JavaScript (JS) to a Drupal 8 theme
- drupal.org - Using Classy as a Base Theme
- drupal.org - Results of Drupalcon Austin's Consensus Banana
- drupal.org - Working with breakpoints in Drupal 8