Tutorial Drupal Paragraphs: warianty, odstępy i UX | Droptica

Tutorial Drupal Paragraphs, część 2: warianty, responsive design, odstępy i UX administracyjny

To druga i ostatnia część przewodnika po budowie korporacyjnej strony opartej o komponenty w Drupal Paragraphs. Na końcu serii będziesz mieć bibliotekę 10–12 uniwersalnych typów paragrafów z wariantami stylu, responsywnymi układami i kontrolą odstępów przyjazną redaktorom.

Ten tutorial Drupal Paragraphs pokazuje, jak przekształcić podstawowe komponenty z części 1 w elastyczną bibliotekę gotową do wykorzystania w rzeczywistych projektach. W poprzedniej części zaplanowałeś architekturę komponentów, przygotowałeś fundament modułu Paragraphs i stworzyłeś trzy bazowe typy paragrafów: Hero, Tekst + obraz oraz Feature Grid. To dobry początek, ale sama biblioteka komponentów nie powinna kończyć się na zestawie statycznych układów. Aby mogła sprawdzić się na większych stronach i rozwijać wraz z projektem, potrzebuje mechanizmów pozwalających dostosowywać wygląd, układ i zachowanie komponentów bez tworzenia kolejnych typów paragrafów dla każdego nowego przypadku użycia.

W tej części skupimy się właśnie na tym etapie. Dodasz warianty kolorystyczne i stylistyczne, przygotujesz komponenty zgodnie z podejściem mobile-first, wdrożysz kontrolę odstępów dostępną dla redaktorów, wykorzystasz pola warunkowe do uproszczenia formularzy oraz dopracujesz doświadczenie administracyjne w panelu CMS. Na końcu omówimy również kwestie wydajności, utrzymania i dalszego rozwoju biblioteki, aby stworzony zestaw komponentów pozostał czytelny, skalowalny i łatwy w rozbudowie wraz z rozwojem projektu.

Ten artykuł jest kontynuacją części 1 serii i pokazuje, jak rozbudować podstawową bibliotekę Paragraphs o funkcje potrzebne w rzeczywistych projektach. Jeśli jeszcze nie przygotowałeś fundamentu biblioteki i bazowych typów paragrafów, warto zacząć od pierwszej części. Natomiast jeśli obecna konfiguracja Paragraphs bardziej utrudnia pracę redaktorom, niż ją wspiera, artykuł Drupal Paragraphs: od bezużytecznej konfiguracji do CMS dla redaktorów pokazuje, jakie cechy odróżniają rozwiązanie gotowe do pracy na produkcji od wdrożenia, które szybko staje się trudne w utrzymaniu.

W tym artykule:

Co zbudowałeś w części 1?

W pierwszej części tutoriala Drupal Paragraphs zaplanowałeś architekturę biblioteki komponentów, zidentyfikowałeś wzorce wielokrotnego użytku i określiłeś zestaw podstawowych elementów potrzebnych typowej stronie korporacyjnej. Następnie przygotowałeś fundament rozwiązania: zainstalowałeś moduł Paragraphs, skonfigurowałeś pole referencyjne dla komponentów oraz ustaliłeś spójną konwencję nazewnictwa pól.

Na tej podstawie stworzyłeś trzy kluczowe komponenty — Hero, Tekst + obraz oraz Feature Grid — wraz z szablonami Twig i bazowymi stylami CSS. Dzięki temu powstała biblioteka gotowa do budowania stron z wykorzystaniem podejścia komponentowego.

Teraz pora rozwinąć ten fundament. W kolejnych krokach dodasz mechanizmy, które pozwolą wielokrotnie wykorzystywać te same komponenty w różnych wariantach wizualnych i układach, bez konieczności tworzenia nowych typów paragrafów dla każdego przypadku użycia.

Jak wdrożyć warianty kolorystyczne i stylistyczne?

Warianty stylu pozwalają jednemu komponentowi obsługiwać kilka różnych wersji wizualnych, takich jak jasna, ciemna, neutralna czy zgodna z identyfikacją marki. Redaktor wybiera odpowiedni wariant z listy rozwijanej, a komponent automatycznie dostosowuje swój wygląd. To stosunkowo proste rozwiązanie, które znacząco zwiększa elastyczność biblioteki, ponieważ ten sam paragraf może być wykorzystywany w wielu miejscach i prezentować się inaczej w zależności od kontekstu — bez tworzenia nowych typów komponentów i bez modyfikowania kodu.

Mechanizm to pole listy mapowane na klasę CSS. Dodaj pole listy field_style do każdego typu paragrafu z opcjami:

light|Light
dark|Dark
brand|Brand
neutral|Neutral

Odczytaj wartość w szablonie i zastosuj ją jako klasę modyfikatora na wrapperze:

{% set style = content.field_style['#items'].value|default('light') %}
<section{{ attributes.addClass('paragraph', 'paragraph--hero', 'paragraph--style-' ~ style) }}>
  {# ... component markup ... #}
</section>

Następnie ustrukturyzuj CSS jako style bazowe plus nadpisania wariantów, z paletą zdefiniowaną raz jako custom properties:

:root {
  --color-light-bg: #ffffff;
  --color-light-fg: #1a1a1a;
  --color-dark-bg: #11151c;
  --color-dark-fg: #ffffff;
  --color-brand-bg: #0057ff;
  --color-brand-fg: #ffffff;
  --color-neutral-bg: #f4f5f7;
  --color-neutral-fg: #1a1a1a;
}

.paragraph--style-light   { background: var(--color-light-bg);   color: var(--color-light-fg); }
.paragraph--style-dark    { background: var(--color-dark-bg);    color: var(--color-dark-fg); }
.paragraph--style-brand   { background: var(--color-brand-bg);   color: var(--color-brand-fg); }
.paragraph--style-neutral { background: var(--color-neutral-bg); color: var(--color-neutral-fg); }

Ponieważ każdy wariant korzysta z tych samych custom properties, rebrand to kilka zmian wartości zamiast przejścia przez każdy komponent.

Przy bibliotece dziesięciu i więcej typów powtarzanie field_style na każdym jest żmudne i podatne na błędy. Skalowalną alternatywą jest plugin Paragraphs behavior, który dodaje ustawienie stylu i logikę renderowania wielu typom naraz:

<?php

namespace Drupal\my_module\Plugin\paragraphs\Behavior;

use Drupal\paragraphs\Entity\Paragraph;
use Drupal\paragraphs\ParagraphsBehaviorBase;
use Drupal\Core\Form\FormStateInterface;

/**
 * @ParagraphsBehavior(
 *   id = "style_variant",
 *   label = @Translation("Style variant"),
 *   description = @Translation("Adds a color/style variant selector."),
 *   weight = 0,
 * )
 */
class StyleVariantBehavior extends ParagraphsBehaviorBase {

  public function buildBehaviorForm(Paragraph $paragraph, array &$form, FormStateInterface $form_state) {
    $form['style'] = [
      '#type' => 'select',
      '#title' => $this->t('Style'),
      '#options' => [
        'light' => $this->t('Light'),
        'dark' => $this->t('Dark'),
        'brand' => $this->t('Brand'),
        'neutral' => $this->t('Neutral'),
      ],
      '#default_value' => $paragraph->getBehaviorSetting($this->getPluginId(), 'style', 'light'),
    ];
    return $form;
  }

  public function preprocess(&$variables) {
    $paragraph = $variables['paragraph'];
    $style = $paragraph->getBehaviorSetting($this->getPluginId(), 'style', 'light');
    $variables['attributes']['class'][] = 'paragraph--style-' . $style;
  }

}

Włącz behavior na typach paragrafów, które mają oferować warianty - selektor pojawi się spójnie wszędzie. To podejście stosujemy w realnych bibliotekach komponentów, bo trzyma ustawienia przekrojowe w jednym miejscu.

Czytaj też: tworzenie treści w Drupalu - moduł Paragraphs oraz Paragraph View Mode - przegląd modułu dla Drupala.

Jak zbudować responsywne układy dla każdego paragrafu?

Responsive nie oznacza „to samo, tylko mniejsze”. Każdy typ paragrafu potrzebuje własnego układu mobilnego, w którym treść jest reorganizowana i repriorytetyzowana na mały ekran, a nie tylko pomniejszana.

Pracuj mobile-first: napisz jednokolumnowy układ mobilny jako domyślny, potem dodawaj złożoność na większych breakpointach. Na przykładzie komponentu Tekst + obraz z części 1:

/* Mobile-first: ułożone w stos, obraz pierwszy. */
.paragraph--text-image {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: 1fr;
}

/* Tablet i więcej: dwie kolumny. */
@media (min-width: 48rem) {
  .paragraph--text-image {
    grid-template-columns: 1fr 1fr;
    gap: 2rem;
    align-items: center;
  }
  .paragraph--text-image--right .paragraph--text-image__media {
    order: 2;
  }
}

W całej bibliotece warto stosować spójną strategię breakpointów, aby wszystkie komponenty reagowały na zmianę szerokości ekranu w przewidywalny sposób. Dobrym punktem wyjścia jest podejście mobile-first z breakpointem dla tabletów w okolicach 48rem i dla desktopów około 64rem. Dzięki temu kolejne komponenty korzystają z tych samych zasad projektowych i łatwiej tworzą spójne układy na różnych urządzeniach.

Szczególną uwagę zwróć na obsługę obrazów. Wykorzystuj Responsive Image Styles w Drupalu, aby użytkownicy pobierali pliki dostosowane do rozdzielczości swojego urządzenia zamiast pełnowymiarowych grafik przeznaczonych dla desktopów. W przypadku sekcji Hero lub innych dużych banerów warto również rozważyć art direction, czyli wyświetlanie różnych kadrów tej samej grafiki na urządzeniach mobilnych i desktopowych.

Jest to szczególnie istotne podczas zastępowania treści opartych na statycznych obrazach biblioteką komponentów. Dobrze zaprojektowane, responsywne paragrafy poprawiają komfort korzystania ze strony na urządzeniach mobilnych, ograniczają ilość przesyłanych danych i wspierają wydajność serwisu. Pamiętaj też o testowaniu komponentów na rzeczywistych urządzeniach oraz przy różnych szerokościach ekranu. Samo zwężanie okna przeglądarki nie zawsze pozwala wychwycić problemy widoczne podczas normalnego korzystania ze strony.

Jak dodać kontrolę odstępów dla redaktorów?

Odstępy to problem, na który wcześniej czy później natrafia każdy system oparty o paragrafy: dwie sekcje o tym samym tle układają się w ogromną przerwę, albo paragraf bez tytułu zostawia pusty pas. Rozwiązanie: dać redaktorom kontrolę margin i padding na poziomie paragrafu, bo odstępy są kontekstowe i tylko redaktor zna kontekst.

Ten rozdział daje gotową implementację do wdrożenia w tutorialu. Pełną dyskusję o tym, dlaczego układy komponentowe rodzą problemy odstępów, kompromisach między automatycznym a ręcznym spacingiem i edge case’ach znajdziesz w artykule o odstępach w Drupal Paragraphs i lukach w układach.

Dodaj dwa pola listy - albo lepiej behavior odstępów - z tą samą skalą dla każdego:

none|None
small|Small
medium|Medium
large|Large

Udostępnij dwa osobne sterowniki. Margin odsuwa paragraf od sąsiadów; padding reguluje przestrzeń wewnątrz. Oba są potrzebne, a ich rozdzielenie czyni system naprawdę elastycznym. Odczytaj je w szablonie jako klasy modyfikatorów:

{% set margin = content.field_margin['#items'].value|default('medium') %}
{% set padding = content.field_padding['#items'].value|default('medium') %}
{%
  set spacing = [
    'paragraph--margin-' ~ margin,
    'paragraph--padding-' ~ padding,
  ]
%}
<section{{ attributes.addClass('paragraph', spacing) }}>
  {# ... component markup ... #}
</section>

Zdefiniuj skalę raz za pomocą custom properties, by była spójna wszędzie:

:root {
  --space-s: 1.5rem;
  --space-m: 3rem;
  --space-l: 5rem;
}

.paragraph--margin-none   { margin-block: 0; }
.paragraph--margin-small  { margin-block: var(--space-s); }
.paragraph--margin-medium { margin-block: var(--space-m); }
.paragraph--margin-large  { margin-block: var(--space-l); }

.paragraph--padding-none   { padding-block: 0; }
.paragraph--padding-small  { padding-block: var(--space-s); }
.paragraph--padding-medium { padding-block: var(--space-m); }
.paragraph--padding-large  { padding-block: var(--space-l); }

Przed wdrożeniem systemu odstępów przetestuj kilka scenariuszy, które niemal zawsze pojawiają się podczas pracy z biblioteką komponentów. Sprawdź, jak wyglądają dwa paragrafy o tym samym tle ustawione jeden pod drugim, komponent bez tytułu czy sekcja wykorzystująca obraz na pełną szerokość. To właśnie w takich przypadkach najłatwiej zweryfikować, czy przyjęte zasady spacingu zachowują spójność i dają redaktorom wystarczającą kontrolę nad układem strony.

W praktyce lepiej sprawdzają się jawne ustawienia dostępne dla redaktorów niż złożone, automatyczne reguły CSS. Gdy odstępy zmieniają się na podstawie kontekstu lub sąsiednich komponentów, rezultat bywa trudny do przewidzenia i wyjaśnienia. Z kolei proste kontrolki marginesów i paddingów pozwalają redaktorowi świadomie zdecydować o wyglądzie sekcji oraz łatwo zrozumieć, dlaczego strona renderuje się w określony sposób.

Przewidywalność jest jedną z najważniejszych cech dobrze zaprojektowanej biblioteki komponentów. Im bardziej zachowanie komponentu odpowiada oczekiwaniom redaktora, tym większe zaufanie do systemu i mniejsza potrzeba angażowania developerów do drobnych zmian w układzie.

Jak używać pól warunkowych i inteligentnych wartości domyślnych?

Długi formularz ze wszystkimi polami widocznymi naraz przytłacza redaktorów. Pola warunkowe pokazują opcje tylko wtedy, gdy są istotne - progressive disclosure obniża obciążenie poznawcze.

Form API Drupala obsługuje warunkową widoczność przez #states. Na przykład pokaż pole „Custom background color” tylko gdy styl ma wartość custom:

function my_module_form_alter(&$form, $form_state, $form_id) {
  if (isset($form['field_custom_bg'])) {
    $form['field_custom_bg']['#states'] = [
      'visible' => [
        ':input[name="field_style"]' => ['value' => 'custom'],
      ],
    ];
  }
}

Jeśli preferujesz konfigurację realizowaną wyłącznie przez interfejs administracyjny, podobny efekt można osiągnąć za pomocą modułu Conditional Fields. Niezależnie od wybranego podejścia cel pozostaje ten sam: pokazywać redaktorowi tylko te pola, które są potrzebne w danym kontekście, i ukrywać opcje, które na danym etapie nie mają znaczenia.

Warto połączyć pola warunkowe z dobrze dobranymi wartościami domyślnymi. Ustaw najczęściej wykorzystywany wariant stylu, domyślny rozmiar odstępów czy najpopularniejszy układ komponentu, aby nowo dodany paragraf od razu wyglądał poprawnie bez dodatkowej konfiguracji.

Dobrze zaprojektowany formularz nie powinien wymagać od redaktora podejmowania decyzji przy każdym polu. W większości przypadków użytkownicy pozostawią domyślne ustawienia bez zmian, dlatego warto zadbać o to, by już domyślna konfiguracja prowadziła do oczekiwanego rezultatu. Dzięki temu tworzenie treści staje się szybsze, a biblioteka komponentów pozostaje łatwa w użyciu nawet dla osób, które nie znają jej technicznych szczegółów.

Jak zbudować pozostałe typy paragrafów?

Gdy masz już warianty, responsywność i odstępy, reszta biblioteki to powtarzalna praca z intencją. Stosuj ten sam przepis - minimalne pola, wariant stylu, kontrola odstępów, układ mobile-first - do każdego pozostałego typu: CTA Block, Cards, Testimonial, FAQ i Stats.

Dwa szybkie przykłady.

CTA Block - field_heading, field_text, field_cta, plus behavior stylu:

<section{{ attributes.addClass('paragraph', 'paragraph--cta') }}>
  <div class="paragraph--cta__inner">
    {% if content.field_heading|render|trim %}
      <h2>{{ content.field_heading }}</h2>
    {% endif %}
    {{ content.field_text }}
    {{ content.field_cta }}
  </div>
</section>

Stats / Numbers - typ stats referencjonujący powtarzalne paragrafy stat_item (field_value, field_label), renderowany jako responsywny rząd:

.paragraph--stats__items {
  display: grid;
  gap: 1rem;
  grid-template-columns: 1fr;
}
@media (min-width: 48rem) {
  .paragraph--stats__items {
    grid-template-columns: repeat(4, 1fr);
  }
}

Dokumentuj każdy typ podczas budowy: jego cel, pola i warianty. Krótki żywy dokument biblioteki komponentów zapobiega sytuacji, w której dwóch developerów tworzy nieco różne wersje tego samego typu i jest referencją, do której wracają redaktorzy i designerzy. Ten sam mindset komponentowy, który prowadził planowanie w części 1, obowiązuje tutaj: każdy typ powinien być na tyle uniwersalny, by łączyć się na wielu stronach, a nie być szyty na miarę jednego layoutu.

Jak usprawnić kontrolki redaktora i UX administracyjny?

Formularz administracyjny to CMS dla redaktorów. Jeśli jest mylący, cały system wydaje się mylący - traktuj doświadczenie edycji jako deliverable, nie jako dodatek na końcu.

Zacznij od podstaw na każdym typie paragrafu:

  • Logiczna kolejność pól. Najczęściej używane na początku: nagłówek, potem obraz, treść, na końcu opcje jak styl i odstępy. Skonfiguruj to w „Manage form display” typu.
  • Tekst pomocy przy każdym polu. Jedno zdanie usuwa zgadywanie. Powiedz redaktorom, jak wygląda styl „Brand” albo jaki proporcje obrazu sprawdzają się najlepiej.
  • Inteligentne domyślne wartości. Ustaw najczęstszy wariant stylu i liczbę kolumn, żeby redaktorzy zmieniali tylko to, co trzeba.
  • Opisowe nazwy typów. „Sekcja hero z obrazem” czytelniej brzmi w menu dodawania niż „hero_v2”.

Następnie zainstaluj nowoczesny motyw administracyjny Gin, który w kilka minut zmienia doświadczenie edycji, a to jedna ze zmian o najwyższym ROI na każdej stronie Drupal:

composer require drupal/gin
drush theme:enable gin -y
drush config:set system.theme admin gin -y

Gin poprawia samo edytowanie Paragraphs: czytelniejsze przyciski dodawania, lepszy drag-and-drop i uporządkowany formularz, co bezpośrednio wspiera podejście przyjazne redaktorom, na którym opiera się cała biblioteka. Pogłęb to kilkoma zaawansowanymi detalami:

  • Ikony typów paragrafów. Dodaj ikonę do każdego typu, żeby menu dodawania było skanowalne jednym rzutem oka.
  • Ogranicz dostępne typy per typ treści. W formularzu pola paragraphs ogranicz typy, które redaktorzy mogą dodać na danym typie treści: landing page i artykuł newsowy oferują tylko odpowiednie komponenty.
  • Czytelne dodawanie. Użyj trybu modal lub dropdown, żeby redaktorzy wiedzieli, co wstawiają. Dla power userów moduły jak Geysir umożliwiają szybszą edycję in-place.
  • Własny styling admina. Odrobina CSS na formularzach paragrafów (grupowanie pól, zacieśnienie odstępów) ułatwia skanowanie długich formularzy.

Celem jest interfejs na tyle intuicyjny, że redaktorzy są produktywni bez warsztatu szkoleniowego. Najlepsze przekazanie to wypełniona strona przykładowa na stagingu, nie instrukcja obsługi.

Jakie kwestie wydajności mają znaczenie na stronach opartych o paragrafy?

Strony oparte o komponenty mogą stać się ciężkie od mediów - wbuduj wydajność od początku, zamiast dokładać ją później.

  • Lazy-load mediów. Opóźniaj ładowanie obrazów poza viewportem, żeby pierwszy render był szybki. Nowoczesny Drupal dodaje loading="lazy" do pól obrazu - zweryfikuj to dla mediów osadzonych w paragrafach.
  • Skuteczne cache’owanie. Strony oparte o paragrafy korzystają z render cache Drupala; upewnij się, że własne szablony i behavior deklarują poprawne cache tags i contexts, żeby strony były cache’owane, a jednocześnie aktualizowały się po zmianie treści.
  • Optymalizuj obrazy per wariant. Sekcja na ciemnym tle może wymagać innego traktowania obrazu niż jasna - serwuj pliki o odpowiednim rozmiarze i kompresji przez responsive image styles.
  • Mierz. Uruchom Lighthouse przed i po, obserwując Largest Contentful Paint i Cumulative Layout Shift, i traktuj regresje jak bugi.

Zastąpienie treści opartych o obrazy strukturalnymi, responsywnymi paragrafami to samo w sobie zysk wydajnościowy: prawdziwy HTML ładuje się szybciej i reflowuje się czysto tam, gdzie ciężka grafika by nie mogła.

Jak utrzymywać i rozwijać bibliotekę komponentów?

Biblioteka komponentów to długotrwały asset - projektuj ją z myślą o rozwoju. Zdrowy system rozpoznasz po tym, że dodanie nowego typu lub wariantu nigdy nie wymaga przebudowy istniejących.

Kilka praktyk utrzymuje ją w dobrej kondycji:

  • Dodawaj typy bez psucia innych. Każdy typ paragrafu jest samodzielny, nowe wpasowują się czysto. Unikaj wspólnego CSS, który falą przechodzi między komponentami, oprzyj się na skalach custom properties.
  • Wersjonuj szablony. Trzymaj zmiany szablonów i behavior w code review i configuration management, żeby modyfikacje były świadome i odwracalne.
  • Dokumentuj bibliotekę. Prowadź żywą referencję każdego typu, jego pól i wariantów. To zatrzymuje dwóch developerów przed budową prawie zduplikowanych komponentów.
  • Wiedz, kiedy refaktorować, a kiedy dodawać. Jeśli nowe wymaganie to wariant istniejącego typu, rozszerz go. Jeśli jest naprawdę inne, dodaj nowy typ. Unikaj skrajności: cmentarza jednorazowych typów i przeładowanego mega-paragrafu, który robi wszystko.

Dodawaj nowe typy na podstawie realnego popytu, nie spekulacji. Gdy redaktorzy zaczną używać komponentów w sposób, którego nie planowałeś, na przykład sekcji produktowej do promocji wydarzenia, to sygnał, że architektura działa i wskazówka, co budować dalej.

Chcesz zbudować stronę Drupal opartą o komponenty z Paragraphs?

Ten tutorial Drupal Paragraphs opiera się na wzorcach z produkcyjnych przebudów korporacyjnych: rozszerzaniu zaplanowanej biblioteki o warianty stylu, układy responsywne, odstępy kontrolowane przez redaktorów i UX admin, którym zespoły contentowe mogą zarządzać bez szkolenia. Przez dwie części przeszedłeś od czystej instalacji Drupal do produkcyjnej, korporacyjnej strony opartej o komponenty: biblioteki uniwersalnych typów paragrafów, którym redaktorzy ufają, i codebase’u, który developerzy utrzymują przez lata.

Budujesz stronę opartą o komponenty i chcesz wsparcia ekspertów przy architekturze? Nasz zespół codziennie projektuje i wdraża systemy Paragraphs przyjazne redaktorom: od szablonów Twig i pluginów behavior po kontrolę odstępów i utrzymanie długoterminowe. Zobacz nasze usługi Drupal, aby dowiedzieć się, jak możemy pomóc.