Making a custom theme from scratch in Drupal 8: Part 2 - Setting up the Theme Files

Submitted by Craig Clark on Sun, 04/16/2017 - 08:46
Screen shot of Drupal with no styling

These are my notes on setting up a custom theme in Drupal 8.

This is a learning project for me. With that in mind, these notes are most useful if you want to strip Drupal down to the basics and work your way up. There is a built-in theme called Classy that is a great starter theme. For this exercise though, I wanted to start even more minimal than that. I want to minimise the number of classes applied to the theme and I want to remove all css. Initially, I want my theme to look like the screenshot on this page.

Before getting started, it's really worth the time to read the Drupal 8 theming documentation and the Drupal 8 Theming guide.

Drupal 8 keeps contributed and custom themes in the root directory in a folder called themes. It is good practice to keep contributed themes (themes you download) in /themes/contrib and custom themes (the themes you make yourself) in /themes/custom.

For the purposes of these notes, we will be working with a custom theme we will call sandbox. Anywhere 'sandbox' is used, replace with the theme name

Setting up a new theme

  1. add the theme directory to /themes/custom/sandbox.  the folder /themes/ is included with Drupal, you need to add /custom and /sandbox
  2. set up the directory structure you will need inside sandbox. This will vary based on needs. 
         /images
         /css
         /js
         /templates → this folder is required if custom template files will be added
         /sass
  3. in /sandbox make a file called sandbox.info.yml  → This has to have the same name as the theme folder
  4. edit sandbox.info.yml as follows
    name: Sandbox
    type: theme
    description: 'A theme that starts with the basics'
    core: 8.x
    package: custom
    version: 1.0
    screenshot: screenshot.svg
    libraries:
      - pencilandpixel/global-styling
    base theme: stable
    regions:
      header: Header
      content: Content
      footer: Footer
    stylesheets-remove:
      - core/assets/vendor/normalize-css/normalize.css

    Here is what's going on here (see defining a theme with an .info.yml file):
    name: Set the name of your theme
    type: this is telling Drupal that this is a theme, (a module would be type:module)
    Description: This is the description that appears with your theme on the admin pages
    core: what version of Drupal is this for
    package: here we use custom, as opposed to core
    version: not required, but useful
    screenshot: the image that appears with the theme in the admin pages
    libraries: this is important, we use libraries to specify scripts and CSS. 
    base theme: if you specify no base theme, stable will be used. Generally it's a good idea to start with Classy, but for this project I want to get down to basics
    regions: header, content and footer are all default regions. They are defined here as reminders. Custom regions can also be added
    stylesheet-remove: a CSS reset will be added later, so there is no point in loading a stylesheet then overwriting the whole thing. 

  5. in /sandbox, make a file called sandbox.breakpoints.yml
  6. edit sandbox.breakpoints.yml as follows:
    sandbox.mobile:
      label: mobile
      mediaQuery: '(min-width: 0px)'
      weight: 0
      multipliers:
       - 1x
    sandbox.narrow:
      label: narrow
      mediaQuery: 'all and (min-width: 480px) and (max-width: 959px)'
      weight: 1
      multipliers:
        - 1x
    sandbox.wide:
      label: wide
      mediaQuery: 'all and (min-width: 960px)'
      weight: 2
      multipliers:
        - 1x

    These breakpoints do not have to match the media queries in CSS, but they can. They are used by Drupal for modules that need breakpoints set. Responsive images would be a good example.

  7. in /sandbox make a file called sandbox.libraries.yml
    Libraries are important. Think of them as sets of resources that can be included where needed in your theme.
  8. edit sandbox.libraries.yml
    #global css amd js
    global-styling:
    
      css:
        base:
          css/style.css: {}
          
      js:
        js/min/responsive-nav-min.js: {}
    
    
    masonry.pkgd-min:
      version: VERSION
      css:
        theme:
          css/masonry.css: {}
          
      js:
        js/min/masonry.pkgd-min.js: {}
        js/min/imagesloaded.pkgd-min.js: {}
        js/min/masonryload-min.js: {}
    in this example, there are two libraries. global-styling is used site-wide. On this site, there is a page that uses masonry.js to display blocks of content. There is no need to load all the resources for masonry on all the other pages. The resources are put in their own library and they will be loaded when needed.
  9. Add any CSS and JS to the appropriate folder. Make sure anything you put here is referenced in your libraries file

This is enough setup that the site can be themed with whatever CSS you use.

Customizing templates

Templates in Drupal 8 use Twig

In this example, I'll set up the page for my portfolio page. In part 1 of my posts on theming Drupal 8, I set up services.yml to debug, that is, it was set to show me what templates are being used and what could be used. That needs to be done for this technique to work.

  1. Navigate to the page you want to make a custom template for
  2. look at the source code. You will see where twig debug has added comments telling you what template you are using and what template you could be using
    <!-- THEME DEBUG -->
    <!-- THEME HOOK: 'page' -->
    <!-- FILE NAME SUGGESTIONS:
       * page--portfolio.html.twig
       x page.html.twig
    -->
    
    <!-- BEGIN OUTPUT from 'core/themes/stable/templates/layout/page.html.twig' -->

    The 'x' indicates that template being used, the '*' indicates a template that could be used. There is also information on where the template file is. In this case, it comes from stable, the base theme.

  3. copy the file page.html.twig from core/themes/stable/templates/layout and paste it into your theme's template folder. In this case /templates/custom/sandbox/templates/layouts
  4. rename the file to  page--portfolio.html.twig. Now it is a template page that will only be used by the portfolio page
  5. at the end of page--portfolio.html.twig, I added the following:
    {{ attach_library( 'pencilandpixel/masonry.pkgd-min' ) }}

    This is the library that was created at step 8 in the previous section. The instructions Drupal is following work something like this "Check to see if there is a template for this page, Hey! there it is! In addition to rendering the output, is there anything else? Yes! A library! Go grab whatever is part of the library and include it here".
    in this way, the additional JS and CSS will only be loaded on the portfolio page.

Things to do when you are done making your theme

  • disable settings.local.php. You can do this by
    • commenting out the request to look for settings.local.php in settings.php ( the reverse of step #1 on the page about settings and services.
    • don't upload settings.local.php to the remote server
    • delete, more or rename settings.local.php
  • if you have disabled caching in Drupal's admin pages, turn it back on
  • in services.yml, diable twig debug
        # Not recommended in production environments
        # @default false
        debug: false