Drupal 8 Theming – The Rules – Core's Base Themes



Drupal 8 Theming – The Rules – Core's Base Themes

0 0


Drupal-8-Theming

A crash course on Drupal 8 theming.

On Github laurelstreng / Drupal-8-Theming

Pro-tip: Press space bar to progress and it won't skip any slides

Drupal 8 Theming

A thorough crash course

What We'll Go Over

  • File Organization
  • Very Lean Core Markup
  • CEM Class Syntax
  • Twig
  • YML and Beefed up Config Functionality
  • and more!!!

File Organization

Core is in its own folder

  • Drupal
    • core
      • assets
      • config
      • ...
    • modules
    • profiles
    • sites
    • themes

Your stuff is easier to get to!

  • Drupal
    • core
    • modules
      • mymodule
    • profiles
    • sites
    • themes
      • mytheme

Template.php has a new name

 template.php

 mytheme.theme

The theme's name with a ".theme" extension.

drupal.org/node/2349803

The Info File has a new name

 mytheme.info

 mytheme.info.yml

The theme's name with a ".info.yml" extension.

drupal.org/node/2349803

CEM Class Syntax

aka (BEM)

drupal.org/coding-standards/css/architecture

The Rules

  • We use classes; ID's are the devil
  • Components (The C in CEM) are a chunk of markup that works together; e.g. a menu, a teaser, a who's online widget, a social share widget, an article.
  • An element (the E in CEM) is a piece of the whole. e.g. a title, some text, an image, call to action link.
  • A modifier is a suffix that can denote a slightly different version of a Component or Element
  • Names are '-' delimited (this goes for a C, E or M)
    .component-name {}
  • Element classes have the component's name, then their name with a double underscore separator
    .component-name__element-name {}
  • Modifiers are added to the end of a component or an element and are separated by a dash.
    .component-name--modifier-name {}
    .component-name__element-name--modifier-name {}

Menu Example

div.menu__wrapper {}
  nav.menu {}
    ul.menu__list {}
      li.menu__list-item {}
        a.menu__link {}
      li.menu__list-item {}
        a.menu__link.menu__link--active {}
      li.menu__list-item {}
        a.menu__link {}
          ul.menu.menu--sub-menu {}
            .menu__list {}

JS Prefix

If a class is being used by or is coming from Javascript, it gets a "js-" prefix.

.js-open {}
.js-accordion {}
.js-best-thing-you-ever-saw {}

Pro-tip*: Utility classes

.u-button {}
.u-clearfix {}
.u-text-replace {}
.u-element-invisible {}

* Just a suggestion for BEM projects, and not something core is doing.

When you're using BEM, sometimes you end up having great use cases for a few utility classes, instead of repeating styles. Prefix them with a "u-" so they're easy to spot.

Very Lean Core Markup and Styles

This is D8 with no theme CSS

Core's Base Themes

Classy

  • Base theme for Seven and Bartik.
  • Has default theming D7 had in core.

Stable

  • Has bare minimum markup/styles needed for things to function.

Both have well organized files, and all of the templates from core.

Classy
?
⊙﹏⊙
Stable

Starting your theming project, which is right for you?

Classy
!
´◕ ᴗ ◕`
Stable

Liked D7's default markup and styles?

Classy is the base theme for you.
Classy
!
´◕ ᴗ ◕`
Stable

Frustrated by D7 defaults and want more control?

Use Stable

OR

Classy
!
´◕ ³ ◕`
Stable

Want the latest and greatest from core markup? Don't mind keeping up with markup updates?

You can have no base theme...

Ride the roller coaster!

In your *.info.yml add:

base theme: false

Core markup and classes could change and could effect your site.

Twig Basics

{# block.html.twig #}
<div{{ attributes }}>
  {{ title_prefix }}
  {% if label %}
    <h2{{ title_attributes }}>{{ label }}</h2>
  {% endif %}
  {{ title_suffix }}
  {% block content %}
    {{ content }}
  {% endblock %}
</div>
  
If you've used Mustache/Handlebars, Angular, Templated in Blogger or Tumblr, this is very similar

Basic Twig Syntax

Print something

Hi {{ name }}

Run code

{% set class = 'my-cool-class' %}

Comment

{# My awesome comment #}

Drilling for Data in Templates

D7 vs. D8

Simple, Static Data

Drupal 7

$title
$content['field_body']
$myvar['has']->alot['of']['nesting']['und'][0]->safe_value

Drupal 8

Dot notation

{{ title }}
{{ content.field_body }}
{{ myvar.has.alot.of.nesting.safe_value }}

If/Else

{% if not page %}
  {# Stuff #}
{% endif %}
{% if not page %}
  {# Stuff #}
{% else if page and awesome %}
  {# Awesome Stuff #}
{% else %}
  {# Other Stuff #}
{% endif %}

twig.sensiolabs.org/doc/tags/if.html

For Loops

{# A for loop that counts to 10 #}
{% for i in 0..10 %}
  This is number {{ i }}!
{% endfor %}
{# A for loop that iterates through an array #}
{% for user in users %}
  User #{{ loop.index }} is {{ user.username }}
{% endfor %}

twig.sensiolabs.org/doc/tags/for.html

YML and Beefed up Config Functionality

Info.yml

# fluffiness.info.yml
name: Fluffiness
type: theme
description: A cuddly theme.
package: Custom
core: 8.x
libraries:
  - fluffiness/global-styling
regions:
  header: Header
  content: Content
  sidebar_first: Sidebar first
  footer: Footer

drupal.org/node/2349827

Creating a sub theme

# fluffiness.info.yml
name: Fluffiness
type: theme
description: A cuddly theme.
package: Custom
core: 8.x
base theme: classy

drupal.org/node/2165673

Libraries.yml

# fluffiness.libraries.yml
global:
  version: 1.x
  css:
    theme:
      css/layout.css: {}
      css/style.css: {}
      css/colors.css: {}
      css/print.css: { media: print }

drupal.org/theme-guide/8/assets

Define Libraries that can consist of JS and CSS

# Further down in fluffiness.libraries.yml
cuddly-slider:
  version: 1.x
  css:
    theme:
      css/cuddly-slider.css: {}
  js:
    js/cuddly-slider.js: {}

drupal.org/theme-guide/8/assets

Declare dependencies on other libraries

# We forgot our jquery dependency!
cuddly-slider:
  version: 1.x
  css:
    theme:
      css/cuddly-slider.css: {}
  js:
    js/cuddly-slider.js: {}
  dependencies:
    - core/jquery

drupal.org/theme-guide/8/assets

Adding Libraries to specific pages

Using Twig

For most use cases, you can tie a library to markup using attach_library()

{{ attach_library('fluffiness/cuddly-slider') }}
<div>Some fluffy markup {{ message }}</div>

drupal.org/node/2216195

Using PHP

In your .theme file you can use PHP to add the library using whatever logic you'd like.

<?php
function fluffiness_preprocess_maintenance_page(&$variables) {
  $variables['#attached']['library'][] = 'fluffiness/cuddly-slider';
}

function fluffiness_preprocess_page(&$variables) {
  if ($variables['fluffiness'] >= 5000) {
    $variables['#attached']['library'][] = 'fluffiness/cuddly-slider';
  }
}

drupal.org/node/2216195

Breakpoints.YML

# fluffiness.breakpoints.yml
fluffiness.mobile:
  label: mobile
  mediaQuery: ''
  weight: 2
  multipliers:
    - 1x
    - 2x
fluffiness.narrow:
  label: narrow
  mediaQuery: 'all and (min-width: 560px) and (max-width: 850px)'
  weight: 1
  multipliers:
    - 1x
    - 2x
fluffiness.wide:
  label: wide
  mediaQuery: 'all and (min-width: 851px)'
  weight: 0
  multipliers:
    - 1x

drupal.org/documentation/modules/breakpoint

Developing on your local

Setup Twig Developer Settings

Find twig.config and change these values (should be in development.services.yml)
# Will be buried in the file, search for 'twig.config'
  twig.config:
    debug: true
Add a settings.local.php file with:
<?php
  $settings['cache']['bins']['render'] = 'cache.backend.null';
  $settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.null';

drupal.org/node/1903374

Template Debug in D8

Once you've turned on twig debug, you'll get this:

<!-- THEME DEBUG -->
<!-- CALL: theme('block') -->
<!-- FILE NAME SUGGESTIONS:
   * block--system.html.twig
   * block--system-menu-block.html.twig
   * block--system-menu-block--tools.html.twig
   * block--bartik-tools.html.twig
   x block.html.twig
-->
<!-- BEGIN OUTPUT from 'core/modules/block/templates/block.html.twig' -->
<div class="block block-system contextual-region block-menu" id="block-bartik-tools" role="navigation">
  <!-- HTML stuff was here -->
</div>
<!-- END OUTPUT from 'core/modules/block/templates/block.html.twig' -->
  

Pro Tip: Template Debug was added to D7.33+

Add this to your settings.php of choice:

$conf['theme_debug'] = TRUE;

Getting into the weeds

Overriding Libraries

Using your theme's *.info.yml

Replace a library or asset

# fluffiness.info.yml cont'd
libraries-override:
  # Replace an entire library.
  core/drupal.collapse: mytheme/collapse

  # Replace an asset with another.
  subtheme/library:
    css:
      theme:
        css/layout.css: css/my-layout.css

drupal.org/node/2497313

Removing an asset or entire library

# OR in fluffiness.info.yml
libraries-override:
  # Remove an asset.
  drupal/dialog:
    css:
      theme:
        dialog.theme.css: false

  # Remove an entire library.
  core/modernizr: false

drupal.org/node/2497313

Extend a library

# fluffiness.info.yml cont'd
# Extend drupal.user: add assets from classy's user libraries.
libraries-extend:
  core/drupal.user:
    - classy/user1
    - classy/user2

drupal.org/node/2497313

ALL the theme_suggestions

They're all done in one place, no longer buried in preprocessor code!

hook_theme_suggestions_alter(array &$suggestions, array $variables, $hook)

api.drupal.org docs for theme_suggestions

I see less hook_form_alter() in your future...

Instead of using hook_form_alter() to add a bit of presentation to a form you can suggest a specific template for the form or any of it's fields!

Attributes Object, your new friend!

<div{{ attributes }}>

No extra space needed

{#  ↓ Don't need this space #}
<div {{ attributes }}>

drupal.org/node/2513632

{# Add or Remove Classes #}
<div{{ attributes.addClass('my-class') }}>
<div{{ attributes.removeClass('their-class') }}>

{# Set any attribute #}
<div{{ attributes.setAttribute('id', 'myID') }}>
<div{{ attributes.setAttribute('data-bundle', node.bundle) }}>

{# Remove any attribute #}
<div{{ attributes.removeAttribute('id') }}>

{# hasClass boolean! #}
{% if attribute.hasClass('myClass') %}
 {# do stuff #}
{% endif %}

drupal.org/node/2513632

Attributes methods can be chained

<div{{ attributes.addClass('hello').removeClass('goodbye') }}>

D8 encourages more classes to be set in Twig

{%
  set classes = [
    'node--' ~ node.bundle|clean_class,
    'node--my-custom-modifier',
  ]
%}

  <article{{ attributes.addClass(classes) }}>

In D7 this would have been done in the preprocessor.

Twig Extends

{# cool.html.twig #}
{% block foo %}
  Default content
{% endblock %}

Meanwhile...

{# cool-er.html.twig #}
{% extends "cool.html.twig" %}
{% block foo %}
  Alternate Content
{% endblock %}

twig.sensiolabs.org/doc/tags/extends.html

Sources

Pro-tip: Press space bar to progress and it won't skip any slides Drupal 8 Theming A thorough crash course