Разработка тем оформления для Drupal 8. Часть 7: Примеры и итоги

В этой статье мы детально разберем процесс разработки темы оформления на реальном примере, а также подведем итоги проделанной работы.

В предыдущей статье мы разбирались с функциями. Изложенного материала уже должно быть достаточно для полноценной разработки собственных тем.

Начиная разработку темы оформления бывает полезно спланировать последовательность действий. В некоторых случаях проще начать сразу с написания стилей, и на их основе формировать вывод. Иногда же написание стилей проще осуществлять, когда вывод и разметка и уже сделаны. В зависимости от исходных данных, ресурсов и распределение ролей в работе над проектом, подходы могут кардинально отличаться.

Тем не менее, я бы хотел рассказать о типичном для меня процессе разработки темы оформления на примере этого сайта.

Типовой процесс разработки

Определение задач и исходных данных

Изначально сайт iamdroid.net работал на Drupal 7, и вместе с миграцией на Drupal 8, я решил произвести редизайн и разработать новую тему оформления. Это довольно типичная задача. Целью редизайна было максимально упростить работу с сайтом, убрать все лишнее и сделать фокус на содержимом. Идея оформления была навеяна применением концепции Material Design в сервисах Google, в частности сервисом Inbox. Был разработан дизайн-макет главной страницы, для визуальной оценки и определения данных, которые должны присутствовать в выводе.

Как правило, все эти вводные приходят от заказчика.

Работа с контентом и формирование вывода

Часто работы по созданию структуры сайта и первоначальному наполнению контентом совмещаются с разработкой темы оформления. В данном случае, статьи и связанные ресурсы были перенесены со старого сайта на новый. Структура сайта была в значительной степени упрощена, пересмотрена навигация, в которой больше не использовалось главное меню. Также были сформированы простые представления для вывода главной страницы и страниц категорий, которые использовали вывод готовых материалов в режиме отображения "Анонс".

Таким образом, к моменту начала разработки темы оформления уже был готов практически весь вывод содержимого без разметки и стилей.

Создание и первичная настройка темы оформления

Новую тему оформления я назвал Inbox. В качестве базовой темы я использовал разработанную мной же тему Material Base. Выбор базовой темы существенно влияет на процесс разработки. В данном случае мне не пришлось разрабатывать стили для таких элементов как кнопки, формы, панель навигации, боковое меню и прочие. Конечно, надо сделать оговорку, что концепция оформления изначально подразумевала использование этих стилей.

В своей теме я переопределил основной и акцентный цвета, а также цвет фона. Это делается в файле _variables.scss:

$color-primary-base: $grey;
$color-accent-base: $cyan;

$color-primary: color($color-primary-base, 800);
$color-primary-hover: color($color-primary-base, 900);
$color-primary-active: darken(color($color-primary-base, 900), 3);

$color-accent: color($color-accent-base, a700);
$color-accent-hover: darken(color($color-accent-base, a700), 3);
$color-accent-active: darken(color($color-accent-base, a700), 6);

$color-bg: #FFF;

Файлы SCSS начинающиеся с символа подчеркивания (_) не компилируются в отдельные CSS файлы, но их можно подключать и использовать в других файлах. В данном случае тема перекомпилируется с учетом моих значений.

Для использования некоторых свойств Material Base нужно добавить классы тегу body. Я это сделал в функции препроцесса в файле inbox.theme:

use Drupal\Core\Template\Attribute;

/**
 * Implements hook_preprocess_HOOK() for HTML document templates.
 */
function inbox_preprocess_html(&$variables) {
  // Add body classes
  $variables['attributes']['class'][] = 'navbar-fixed';
  $variables['attributes']['class'][] = 'navbar-light';
  $variables['attributes']['class'][] = 'drawer-permanent-collapsible';
  $variables['attributes']['class'][] = 'drawer-below-navbar';
}

В данном случае, с помощью этих классов панель навигации закрепляется вверху страницы во время прокрутки, и ее фон меняется на белый. Также я добавил класс drawer-permanent-collapsible, который будет определять компонент, который я разработал специально для этого сайта — сворачиваемое боковое меню. В базовой теме он отсутствует.

Теперь пришло время расположить блоки в соответствующих регионах, добавить недостающие, и удалить неиспользуемые. Блокам потребуется добавить специальные классы, чтобы к ним применились стили и поведение из базовой темы. Для этого есть модуль Block Class.

В регионе Navbar расположились следующие блоки:

Navbar Menu toggle

Классы: navbar-item navbar-menu-toggle
Разметка:

<div id="navbar-menu-toggle">
  <a href="#"><i class="material-icons navbar-icon">menu</i></a>
</div>

Navbar logo

Классы: navbar-item navbar-branding
Разметка:

<div class="navbar-logo">
  <a href="/" title="Home" rel="home"><span class="logo"></span></a>
</div>

В регионе Drawer расположились следующие блоки:

Drawer Title

Классы: drawer-item divider-bottom hidden-md
Разметка:

<div id="drawer-menu-close">
  <a href="#"><i class="material-icons drawer-icon">arrow_back</i></a>
</div>
<div id="drawer-title">I amdroid</div>

Categories

Классы: drawer-item divider-bottom
Разметка: вывод блока формируется представлением.

Остальные блоки в этих регионах я добавил позже, их описание я опущу. В регионе Content все осталось по умолчанию. Все остальные блоки, кроме некоторых системных я удалил.

Блоки Navbar logo и Categories сделаны нестандартным способом, чтобы обойти побочный эффект, связанный с мультиязычностью.

Шаблоны разметки содержимого

На главной странице и в категориях содержимое отображается в режиме анонса. На страничке статьи используется полный режим отображения. Оба этих режима заданы по умолчанию, но можно создавать и собственные. Для каждого режима отображения можно определить свой набор отображаемых полей, и формат их вывода. Также для разных режимов отображения можно создать различную разметку в шаблонах.

Я сделал свои шаблоны разметки для анонса и полного отображения.

Листинг шаблона node--article--teaser.html.twig:

<a href="{{ url }}" rel="bookmark">
  {{ title_prefix }}
  <div{{ attributes.addClass('item-preview') }}>
    <div class="image">
      {{ content.field_image }}
    </div>
    <h3{{ title_attributes.addClass('title') }}>{{ label }}</h3>
    <div class="description">
      {{ content.body }}
    </div>
    <div class="info-group">
      <div class="sections">
        {{ content.field_categories }}
        {{ content.field_technologies }}
      </div>
      <div class="submitted">{{ node.getCreatedTime|date('d.m.Y') }}</div>
    </div>
  </div>
</a>

Листинг шаблона node--article--full.html.twig:

<article{{ attributes }}>
  {{ title_prefix }}
  {{ title_suffix }}
  <div class="row article-head">
    <div class="col-xs-12 col-md-6 col-left">
      <div class="image">
        {{ content.field_image }}
      </div>
    </div>
    <div class="col-xs-12 col-md-6 col-right">
      {% if node.field_categories.value %}
        <div class="categories {{ node.field_categories.entity.field_machine_name.value }}">{{ content.field_categories }}</div>
      {% endif %}
      {% if node.field_technologies.value %}
        <div class="technologies">{{ content.field_technologies }}</div>
      {% endif %}
      {% if node.field_tags.value %}
        <div class="tags">{{ content.field_tags }}</div>
      {% endif %}
      <div class="submitted">{{ node.getCreatedTime|date('d.m.Y') }}</div>
    </div>
  </div>
  <div{{ content_attributes }}>
    {{ content.body }}
    {{ content.field_comments }}
  </div>
</article>

На данном этапе мы получили готовый размеченный вывод содержимого, можно переходить к стилям.

Стили

Я опущу стили для сворачиваемого бокового меню, а также некоторые общие стили не представляющие особого интереса.

Фрагмент файла styles.scss:

/* front page */

.articles-list {
  .item > a { display: block; }
  .image {
    img { @extend .img-responsive; display: block; width: 100%; }
  }
  .info-group { display: flex; justify-content: space-between; align-items: flex-end; }
  .sections { 
    .field-item {
      display: inline-block; margin-top: 8px; margin-right: 8px;
      border-radius: 2px; background: color($color-primary-base, 500); color: $color-text-light;
    }
  }
  .submitted { flex: 0 0 80px; text-align: right; }
}

@include breakpoint($sm) {
  .articles-list {
    .item { display: flex; justify-content: center;
      .item-preview { margin: -12px; padding: 24px;
        &:hover { @include z-level-2; }
      } 
    }
  }
}

/* article page */

.article-head {
  .image img { @extend .img-responsive; max-width: none; width: 100%; }
  .categories, .technologies, .tags, .submitted { padding-left: 48px; position: relative;
    &:before { @extend .material-icons; position: absolute; left: 12px; opacity: 0.5; }
  }
  .categories.front-end:before { content: "widgets"; }
  .categories.development:before { content: "code"; }
  .categories.site-building:before { content: "build"; }
  .categories.environment:before { content: "settings"; }
  .categories.community:before { content: "group"; }
  .technologies:before { content: "extension"; }
  .tags:before { content: "label"; }
  .submitted:before { content: "today"; }
}

По сути, это все стили, которые потребовалось написать для запуска сайта. Все остальное берется из базовой темы.

В последствии я добавил несколько блоков, пару полезных функций, страницу контактов и немного подправил разметку самих статей. Итоговый файл styles.scss состоит всего из 250 строк, включая комментарии. Для темного оформления используется отдельный файл состоящий из 80 строк, весь JS код состоит из 55 строк.

На этом разработка темы оформления была завершена.

Заключение

В этом цикле статей я постарался в сжатом, но достаточном для понимания, виде изложить свой опыт разработки тем оформления. Изложенные подходы и технологии далеко не единственные, но с их помощью можно сделать первые осознанные шаги. Умение применять правильные инструменты позволяет существенно повысить эффективность и качество разработки.

В своей работе я стараюсь уделять внимание как результату, так и самому процессу. Много внимания я уделяю неприметным на первый взгляд деталям, стараюсь оптимизировать каждый стиль, каждое изображение. По возможности повторно использую реализованные ранее решения или создаю отдельные компоненты. Также я стараюсь выделять время для публикации наработок и взаимодействию с сообществом Drupal-разработчиков.

И в завершение я хотел бы рассказать о нескольких принципах, которых стараюсь придерживаться сам и рекомендую остальным:

  • Если решение сложное или не очевидное, сначала решите задачу самым простым, но работающим способом. Начав работу, вы погружаетесь в нее, лучше видите контекст, и вам будет проще дорабатывать первоначальное решение.
  • Перед тем как браться за решение новой задачи, полезно уделить час-другой на поиски актуальной информации по теме. Новые технологии в веб-разработке появляются так же стремительно, как и устаревают.
  • Английский — это основной язык разработчиков, и вся документация и сопутствующие ресурсы будут именно на английском. Чем раньше вы начнете его использовать, тем лучше.
  • Если вы замечаете, что какие-то операции делаются слишком сложно, долго или неудобно — ищите способы делать их более эффективно. Возможно, существуют инструменты для автоматизации таких операций или вы сами сможете их создать.
  • Записывайте все решения, на поиск которых вы потратили время. Это может быть личная база знаний, блог или просто комментарии в коде. Главное, чтобы вы могли быстро найти решение, когда такая задача вновь появится в будущем.
  • И последнее, но не последнее по значимости — стремитесь постоянно повышать эффективность, и выделяйте время на достижение этого. Будь это изучение новой технологии или непонятного инструмента для командной строки. Поначалу все кажется новым и непонятным, но именно так все и работает.

Разработка — это интересный и творческий процесс, в котором я нашел свое призвание, чего и вам желаю.