Theming and Styling

The basic intention of the theme is to provide a minimal design with great UX.

We follow the desktop first design. That means that we design for desktop but with mobile in mind and not the opposite.

Follow the Atomic design philosophy for the css as also as for the design and html.

Here are some examples of the Atomic design in terms of Drupal. Do not confuse these with the scss file structure.

  • Atoms: basic HTML tags, browser resets, Drupal resets.
  • Molecules: logo, search form, breadcrumbs,
  • Organisms: views list, sidebar, header, content type full view mode.
  • Templates: each page styles, content type all styles, mockups.
  • Pages: the styleguide, a test page (for styling)

The above order should be also used to achieve the cascading of the styles. For more examples please see the atomic design demo.

Please read all the file and not individual sections. It was written like this for purpose.

Static content elements

Static content elements are elements that will/should not change their design attributes (eg size, color, decoration etc) across pages.

They are usually created once and they exist on all or some pages but on the same position.

Such elements are usually not user generated.

In the case of Drupal such elements are usually Blocks or hardcoded elements on the twig templates.

Some common Static content elements are:

  • Logo
  • Slogan
  • Site name
  • Breadcrumbs
  • Messages (system)
  • Search form
  • User login form
  • Main menu
  • Menus (other)
  • Social profiles
  • Copyright text
  • Credits text
  • Language switcher
  • Header region
  • Footer region
  • (~) Sidebar region(s)
  • All the basic HTML elements of HTML that will be allowed (eg <p>, <br>, <blockquote>, <strong> etc)

Dynamic content elements

Dynamic content elements are elements that are usually user generated.

This means that some of their design attributes are not always easy to predict.

For example, a blog post title may have 10, 20 or 100 characters so the design should “predict” for all the possible attributes of it (eg line-height or element width.

Some common Dynamic content elements are:

  • (Current page) Title
  • Main content
  • Lists of content (Drupal Views)
  • WYSIWYG content
  • Banners/Ads
  • Slideshows/Carousels etc
  • Blocks with custom content

(Frontend) Static pages

Static pages are the pages that do have the same design for all users and they do not depend on any parameter that could change their design.

Just like the Static content elements before these pages do not have content generated by users.

Static here does not mean that they are hardcoded and their elements will never change. Do not confuse this with the “HTML static page”.

In case of Drupal some common Static pages are:

  • User login
  • User register
  • User password
  • User account
  • User edit form
  • Contact page and form
  • 404 page (not found)
  • 403 page (access denied)
  • Maintenance page

  • node/add/*, node/*/edit pages (forms)

  • node/*/preview

(Frontend) Dynamic pages

  • Homepage
  • (Each) Content type page (node/*/view)
  • Lists of content (Drupal views)
  • Other custom pages

(Backend) Admin pages

  • Dashboard (general)
  • Workflow dashboard
  • Administer menus
  • Administer users
  • Administer content (and per Content type pages)
  • Administer Blocks
  • Administer translations (Translation management)
  • Settings pages (eg System settings)

Media queries (table)

TBD (Responsive breakpoints, Other browser options)

Form design and best practices

All the forms (user inputs) of the same type should be unified by design. For example, all Content type forms (node/add/*) should have the same design even if they have different fields.

  • WYSIWYG should inherit exactly the Frontend Theme CSS/JS.
  • WYSIWYG should not allow the user to add styles that do not have a style!
  • WYSIWYG should not allow the user to create functionality inside the Editor such as dropdown menus or effects.
  • WYSIWYG should follow the allowed text Filter.
  • For each allowed option on the Drupal text Filter WYSIWYG should provide the relative button. Eg if the user is able to add a <blockquote> she should see a button on the Editor to add a blockquote.
  • Custom Ckeditor templates should be created (using js) on a custom module.
  • WYSIWYG should provide basic information about using the Editor as also as a more analytic page for Admins.
  • Too many options on the WYSIWYG may cause problems. Protect the user from “breaking” the site design/code etc.
  • Avoid too many (html) text Filters (2 are OK).
  • WYSIWYG configuration should be packaged on a separated module.

Theme best practices

  • We support IE8 and above browsers. We are not styling with that in mind but will deal with it when finished.
  • Override only the necessary css coming from each module. Do not copy and paste all the css of a module to the project Theme.
  • Be careful when overriding css/js as also as html structure especially if it is coming from Core. This may break core built-in functionality.
  • For the Admin pages we will use the default Core admin theme (Seven) and we are just attaching js/css files to add some functionality. This will happen on a custom module or a subtheme.
  • If you want to override a twig template get only from the source module that provides that. Eg if you want to override the html.html.twig file copy that from the system module.
  • Under the Theme folder create new subfolders to group files only if there is a significant amount of them and it makes sense to separate theme. Eg split the twig files to templates/system, templates/block etc using the pattern templates/[module] if there are 3 files of the system and 2 files of the block module. There should not exist any empty folder.
  • Avoid using the path alias (eg related classes) of a webpage to style the page. Path aliases are considered unstable and could change frequently.
  • If you need to extend/alter a class or another attribute prefer to use the [theme_name].theme
  • Do not use non semantic classes. Saying that we should not use classes such as “clearfix, container, full-width” etc if these classes are used to provide some css styling. Instead use sass mixins such as @full-width {width: 100%}.
  • Avoid theming with elements except from the basic ones (p, h1 etc). Use classes instead. Example for this code <div><span class="my"></span></div>:
  // Good
  .my {}
  // Good also {}

  // Bad
  div span {}
  // Bad also
  div .my {}


  • Follow the Atomic design philosophy to show the styleguide(s).
  • Create one styleguide from existing css (autogenerated) from the Distribution.
  • Create one custom styleguide for design reference.

Theme folders and file structure

Structure generated with command tree -F -a --dirsfirst. See the structure at

├── config/
│   └── install/
│       └── MY_THEME.settings.yml
├── css/
│   └── style.css
├── images/
├── js/
│   └── scripts.js
├── scss/
│   ├── drupal_block/
│   │   ├── _breadcrumbs
│   │   ├── _logo
│   │   ├── _page_title
│   │   └── _search_form
│   ├── drupal_ctype/
│   │   ├── _blog.scss
│   │   ├── _event.scss
│   │   └── _page.scss
│   ├── drupal_form/
│   │   └── _contact.scss
│   ├── drupal_page/
│   │   └── _user.scss
│   ├── drupal_region/
│   │   ├── _footer.scss
│   │   ├── _header.scss
│   │   └── _left_sidebar.scss
│   ├── helpers/
│   │   ├── _function.scss
│   │   └── _mixin.scss
│   ├── resets/
│   │   ├── _normalize_drupal.scss
│   │   └── _normalize.scss
│   ├── _general.scss
│   ├── _layout.scss
│   ├── style.scss
│   └── _variables.scss
├── templates/
│   ├── html.html.twig
│   └── page.html.twig
├── favicon.ico
├── .gitignore
├── gulp.config.json
├── gulpfile.js
├── logo.png
├── logo.svg
├── MY_THEME.breakpoints.yml
├── MY_THEME.libraries.yml
├── MY_THEME.theme
├── package.json
├── README.txt
├── screenshot.png
└── theme-settings.php

SCSS variables, mixins and functions

  • We write css with the SCSS (Sassy CSS) syntax.
  • Leave 2 spaces for code indent. Do not use tabs!
  • One selector per line.
  • One space before the opening curly brace.
  • A line break after the opening curly brace.
  • A consistent indent.
  • No space before the colon.
  • A space after the colon.
  • No space before the semi-colon.
  • A line break after the semi-colon.
  • No space before the closing curly brace.
  • A line break and an empty line after the closing curly brace
.other-selector {
  color: black;
  font-size: 1.2em;
    .nested {
      font-size: 0.6em;
  • Always add zero ( for decimal values of a property (example: 0.3em instead of .3em).
  • User relative values (em, %) for size related properties values (width, line-height, font-size etc)
  • For the scss $variable, @mixin and @function avoid camel case and use an dash to separate words.
$variable-name: #fff
  • $Variable, @mixin and @function names should be self describing but not have too many characters.
$sidebar-bg: #ddd
  • Avoid using @extend! Use @mixin instead. There are so many reasons.
  • If you want to use a 3rd party scss library use only that specific part and do not load the whole library. It is better to copy this on local scss files with the proper comment.
  • Always comment @mixins, @function.
  • Always split large scss files if they contain too many lines. Split them by usage (eg the variables related to color, the variables related to typography etc).
  • Compile with Libsass.
  • Use Gulp as task manager (for theme assets).
  • Use modular-scale for vertical rhythm.
  • Use breakpoint-sass to create the media queries.
  • Use singularitygs for the grid system.
  • Create some generic @function for Drupal Views layouts, Content type display modes and fields.
  • Use the new CSS3 layout modules such as flexbox but always with cross bowser fallbacks.
  • Always add a css comment /** ... */ when adding styles for each design element (eg Left_sidebar).
  • Use the autoprefixer plugin to add browser prefixes from
  • Use the normalize.css for css reset.
  • Do not use an HTML5 reset library!
  • Do not import whole scss libraries but only the pieces of code you need (eg @import "compass/typography/lists" instead of @import "compass"). If it is hard to get only a specific piece just copy that piece from the source on your local scss folder.

Graphics - images best practices

Fonts and typography

  • Try using open source fonts (eg Google Fonts).
  • If you have the copyright to download the fonts locally do this instead of loading them from the online source.
  • Be careful so the selected fonts (and their fallback) do support all the languages.

External CSS and JS libraries

Please check development/Adding 3rd party libraries

Scaffold a theme

Debugging a theme

Check D.O. related documentation.

Performance and page loading


  • What are our performance targets
  • Cache tags
  • Views caching
  • CDN
  • Measure performance (tools)

Accessibility best practices


  • Accessibility standard we support (link)
  • Basic rules to follow
  • Images
  • Forms
  • How to fix accessibility issues (within Drupal)