Blog Kontakt

Eine der größten Herausforderungen bei der Erstellung von Templates ist die Vermeidung von Redundanzen. Der Fokus auf „Global Blocks first“ bringt mit klaren Namenskonventionen und modularer Arbeitsweise wieder Struktur in das gesamte Projekt.

Besonders in langfristig gewachsenen Webprojekten kommen Entwickler:innen oft mit ähnlichen Fehlerquellen in Kontakt: Redundante Codeabschnitte die sich über mehrere Templates, Stylesheets und Page Templates ziehen, eine inkonsistente UI-Sprache, und unübersichtliche Vererbungsstrukturen. 

Um scheinbar unkalkulierbare Risiken in bestehenden Funktionalitäten zu vermeiden, entwickelt sich eine „Copy & Paste“-Kultur: Ähnliche Content-Elemente werden lieber kopiert und modifiziert als bestehenden Code neu zu strukturieren. Spätere Änderungen im gesamten Projekt werden auf diese Weise noch langsamer und kostspieliger. 

Eine Lösung bietet der konsequente Fokus auf eine blockbasierte Content- und Projektarchitektur. Gepaart mit dem BEM- Namensprinzip in CSS bietet dieser Ansatz eine ideale Basis für strukturierte Daten- und Templating-Flows über das CMS hinaus.

Neu in Sulu 2.6: Global Blocks

Blöcke sind neben Smart Content einer der mächtigsten Inhaltstypen in Sulu. In unserem Beitrag zu „Progressive Entwicklung von Komponenten mit Nested Blocks“ haben wir bereits Beispiele für verschachtelte Blöcke zur besseren Wiederverwendbarkeit von Inhaltsstrukturen gezeigt. Mit dem Release 2.6 von Sulu ist die Arbeit mit Blöcken in Seiten-Templates nun noch komfortabler geworden: Blöcke, die fortan im Verzeichnis „config/templates/blocks“ abgelegt werden, können als sogenannte „Global Blocks“ anhand ihres Keys in Templates referenziert werden. Dazu wird das ref-Attribut am Type-node verwendet:

<block name="blocks" default-type="block--headline">
   <types>
       <!-- 1. Referenzierung eines Global Blocks (blocks/block—headline.xml) -->
       <type ref="block--headline" />

       <!-- 2. Referenzierung eines Blocks über XInclude -->
       <xi:include href=“./block—hero.xml“ xpointer=“...“ /> 

       <!-- 3. Reguläre Inline Block Definition -->
       <type name="block--video">
           <meta>
               <title lang="de">Video</title>
           </meta>
           <properties>
               <property name="video_url" type="text_line">
                   <meta>
                       <title lang="de">Video URL</title>
                   </meta>
               </property>
           </properties>
       </type>
   </types>
</block>

Während jede dieser Syntax zu einem ähnlichen Ergebnis führt, bleibt durch eine einfache Referenzierung des globalen Blocks „block--headline“ der Umweg über Xinclude erspart. Das Ergebnis sind nicht nur schlankere XML-Templates, sondern auch reduziertere Metadaten an den Blöcken.

Um Blöcke möglichst modular und damit wiederverwendbar zu halten, steht immer eine möglichst generische Benennung an erster Stelle. Statt bei der Benennung zu fragen „An welcher Stelle auf der Seite oder UI-Templates möchte ich diesen Block darstellen?“, wird die Funktion des Blocks möglichst isoliert betrachtet, etwa durch die Frage: „Was macht dieser Block und wie unspezifisch darf er dabei sein?“ So lassen sich mit einem „Accordion“-Block wesentlich mehr Szenarien realisieren als in einem mehr oder weniger statischen „Company FAQ“-Block. 

Dem Gedanken „Global Blocks first“ folgend erstreckt sich die gewählte Benennung nicht nur auf den Einsatz in Sulu Page- und Twig-Templates, sondern wird auch konsequent in Javascript und CSS adaptiert. Durch die BEM-Namenskonvention können Varianten, Zustände und Abhängigkeiten innerhalb eines Blocks (z.B. ein spezielles Farbschema, Layout oder variabel eingeblendete Buttons) über Twig signalisiert und im restlichen Frontend-Code einheitlich behandelt werden. Das hat weitere Vorteile: Entwickler:innen sprechen im Projekt von Anfang an dieselbe Sprache, vermeiden Namenskonflikte und abweichende Implementierungsweisen, und finden sich auch nach Jahren noch gut zurecht.

Global Blocks Suche im Projekt
Ein logisches Wording von Blöcken schafft Struktur und erleichtert die Wiederaufffindbarkeit von zusammengehörigem Code.

Mit BEM Struktur in den Frontend-Stack bringen

Aber warum ist eine einheitliche Implementierungsweise gerade für Stylesheets überhaupt wichtig? Ist nicht einer der Vorzüge von CSS, möglichst kompatibel zu verschiedenen Arten des Stylings zu sein, wie z.B. Utility-Klassen basierte Ansätze oder tief verschachtelte Selektoren? Die Antwort liegt in der Spezifität von Selektoren und damit der Wahrscheinlichkeit, dass die Eigenschaften eines bestimmten Selektors – z.B. #login-username – unabhängig von ihrer Position im CSS der Webseite bereits existierende Style-Eigenschaften an einem Element – z.B .input[type="text"] – überschreiben werden. Wie die Berechnung der Spezifität im Einzelnen abläuft, kann bei MDN nachgelesen und in den DevTools der meisten Browser eingesehen werden; wichtig ist, dass möglichst eine einheitliche Implementierung gewählt wird, idealerweise generische Klassen. 

Dies ist auch der Ansatz vom BEM-Namensprinzips – kurz für Block, Element, Modifier. Mit BEM definieren wir alle möglichen Zustände eines Blocks (oder allgemein jeder isolierbaren Entität wie Header- oder Input-Element) und seiner Child-Elemente in Isolation vom Rest der Seite. Werden später Erweiterungen an einem Block vorgenommen, ergibt sich daraus ein klarer Workflow für die Implementierung im Front- und Backend:

  1. Property im Sulu Page Template definieren
  2. Logik und neue mögliche Zustände oder Elemente im Twig Template verankern
  3. Styling im Stylesheet erweitern
  4. ggf. Interaktivität über Javascript hinzufügen. 

Ein Beispiel könnte so aussehen:

<section class="block--hero block--hero--bg-{{ content.color_scheme|default("blue") }}{{ content.reverse_content|default(false) ? " block--hero--reverse" : "" }}">
    <div class="block--hero__wrapper">
        <h1 class="block--hero__title">{{ content.headline }}</h1>
    </div>
    <!-- .... -->
</section>

Die Eigenschaften des Hero-Blocks, z.B. sein Farbschema oder ein vertikales Flip des Inhalts, werden im äußersten Scope definiert. Über CSS definieren wir dann die einzelnen Zustände nach innen. Dabei ist es Geschmackssache, ob die Werte für Eigenschaften explizit, implizit (etwa über CSS-Variablen) oder über eine Mischung aus beiden notiert werden:

.block—hero {
    // Block Scope
    --text-color: #000000;
    --bg-color: #FFFFFF;
    --wrapper-direction: row;
    background-color: var(--bg-color);

    // Elements
    &__wrapper {
        display: flex;
        flex-direction: var(--wrapper-direction);
    }

    &__title {
        color: var(--text-color);
    }

    // Modifiers
    &--bg {
        &--blue {
            --bg-color: #005CA0;
        }
    }

    &--reverse {
        --wrapper-direction: row-reverse;
    }
}

Zur besseren Veranschaulichung wird in diesem Beispiel die SASS-Syntax verwendet. Wir konnten beobachten, dass in Projekten, die konsequent BEM adaptieren, nur sehr selten die dritte oder vierte Verschachtelungsebene in SASS angesteuert werden muss - ein weiterer Indikator für die saubere Strukturierung und Nachvollziehbarkeit unseres Codes. Wer es vorzieht, auf CSS-Variablen zu verzichten oder den Namen eines Blocks nur einmalig verwenden mag, kann dies im Beispiel auch so verwenden:

.block—hero {
    $self: &;
    // s.o.

    &--reverse {
        #{$self}__wrapper {
            flex-direction: row-reverse;
        }
    }
}

Sollte die Eigenschaft (konkret: der Modifier) „Reverse“ tatsächlich nur den Wrapper und keine weiteren Child-Elemente im Block betreffen, wäre es denkbar, diese Eigenschaft eine Ebene tiefer zu notieren, etwa als .block—hero__wrapper--reverse.

Global Blocks und BEM: Eine großartige Kombination

Für ein modulares und strukturiertes Arbeiten über die gesamte Codebasis eines Sulu CMS-Projektes bleibt die Fokussierung auf Blöcke unverzichtbar. Namenskonventionen wie BEM ermöglichen es, dynamische Eigenschaften von Blöcken und Komponenten in Templates, Stylesheets und Javascript einheitlich zu behandeln. Dass durch BEM die Lesbarkeit von Code durch zu lange Klassennamen beeinträchtigen kann, ist angesichts der Natur von CSS – der Vererbung von Eigenschaften und der Spezifität von CSS-Selektoren – durchaus verzeihlich. BEM und „Global Blocks first“ können sicherlich nicht alle Probleme lösen, aber sie schaffen eine gute Grundlage für langfristige und kollaborative Projekte – und damit einen Ausweg aus dem Template-Chaos!

Diese Artikel könnten Sie auch interessieren

Interesse geweckt?

Alle Artikel anzeigen