Wie wird eigentlich aus einem Design eine Website?
Welche Überlegungen spielen bei der Umsetzung eine Rolle und was passiert technisch?
Anhand eines einzelnen Design-Blocks versuche ich dir unser Vorgehen näher zu bringen.
Design-Übersicht
Wir starten mit einer Design-Übersicht unseres Beispiel-Blocks. Hier ist der Block für drei Viewports (Fenstergrössen) designed.
Wir sehen einen Text in grosser Schrift, einen Link und einen Text in normaler Schriftgrösse.
Es wird klar, dass der Block auch drei verschiedene Hintergrundfarben zur Verfügung stellen soll (keine, violett und dunkelgrün).

Übrigens ☝🏻
Dieser Block stammt vom Projekt Geburtshaus St.Gallen, welches wir mit Schalter&Walter umsetzen durften.
Spezifikation
Bei einer genaueren Betrachtung auf den Block legen wir die Spezifikation fest.
In diesem Fall haben wir uns darauf geeinigt, den Block sehr flexibel zu halten. Das heisst, wir wollen auf beiden Seiten je ein Text-Feld (WYSIWYG-Editor / #1) und einen Link-Button (Link-Feld / #2) zur Verfügung stellen. Die Ausprägung der Texte überlassen wir dem Administrator, im WYSIWYG-Editor hat er alle Text-Ausprägungen der Website zur Verfügung.
Schlussendlich benötigt der Block noch ein Auswahlfeld für die Hintergrundfarbe (Radio-Buttons / #3).
Das Frontend wird dann so programmiert, dass nicht ausgefüllte Felder auch nicht ausgegeben werden und so auch keine ungewollten, optischen Lücken entstehen.

Felder
Die besprochenen Felder erzeugen wir im Backend mit Hilfe des Plugins Advanced Custom Fields – ACF.
Im Bild ist die Ansicht für den Administrator zu sehen.

Die erzeugte JSON-Datei, welche die besprochenen Felder für den Block beschreibt, sieht so aus:
add_action( 'acf/include_fields', function() {
if ( ! function_exists( 'acf_add_local_field_group' ) ) {
return;
}
acf_add_local_field_group( array(
'key' => 'group_6673f0c5294d1',
'title' => 'Block \'Infobox\'',
'fields' => array(
array(
'key' => 'field_6673f41eb7f09',
'label' => 'Hintergrundfarbe',
'name' => 'bg_color',
'aria-label' => '',
'type' => 'radio',
'instructions' => '',
'required' => 0,
'conditional_logic' => 0,
'wrapper' => array(
'width' => '',
'class' => '',
'id' => '',
),
'choices' => array(
'none' => 'keine',
'violet' => 'violett',
'dark_green' => 'dunkelgrün',
),
'default_value' => '',
'return_format' => 'value',
'allow_null' => 0,
'other_choice' => 0,
'layout' => 'horizontal',
'save_other_choice' => 0,
),
array(
'key' => 'field_6673f9402c16a',
'label' => 'Linke Seite',
'name' => 'left_side',
'aria-label' => '',
'type' => 'group',
'instructions' => '',
'required' => 0,
'conditional_logic' => 0,
'wrapper' => array(
'width' => '50',
'class' => '',
'id' => '',
),
'layout' => 'block',
'sub_fields' => array(
array(
'key' => 'field_6673f9e12c16b',
'label' => 'Text',
'name' => 'text',
'aria-label' => '',
'type' => 'wysiwyg',
'instructions' => '',
'required' => 0,
'conditional_logic' => 0,
'wrapper' => array(
'width' => '',
'class' => '',
'id' => '',
),
'default_value' => '',
'tabs' => 'all',
'toolbar' => 'custom',
'media_upload' => 0,
'delay' => 0,
),
array(
'key' => 'field_6673f9f22c16c',
'label' => 'Link',
'name' => 'link',
'aria-label' => '',
'type' => 'link',
'instructions' => '',
'required' => 0,
'conditional_logic' => 0,
'wrapper' => array(
'width' => '',
'class' => '',
'id' => '',
),
'return_format' => 'array',
),
),
),
array(
'key' => 'field_6673fa10a65e8',
'label' => 'Rechte Seite',
'name' => 'right_side',
'aria-label' => '',
'type' => 'group',
'instructions' => '',
'required' => 0,
'conditional_logic' => 0,
'wrapper' => array(
'width' => '50',
'class' => '',
'id' => '',
),
'layout' => 'block',
'sub_fields' => array(
array(
'key' => 'field_6673fa10a65e9',
'label' => 'Text',
'name' => 'text',
'aria-label' => '',
'type' => 'wysiwyg',
'instructions' => '',
'required' => 0,
'conditional_logic' => 0,
'wrapper' => array(
'width' => '',
'class' => '',
'id' => '',
),
'default_value' => '',
'tabs' => 'all',
'toolbar' => 'custom',
'media_upload' => 0,
'delay' => 0,
),
array(
'key' => 'field_6673fa10a65ea',
'label' => 'Link',
'name' => 'link',
'aria-label' => '',
'type' => 'link',
'instructions' => '',
'required' => 0,
'conditional_logic' => 0,
'wrapper' => array(
'width' => '',
'class' => '',
'id' => '',
),
'return_format' => 'array',
),
),
),
),
'location' => array(
array(
array(
'param' => 'block',
'operator' => '==',
'value' => 'acf/infobox',
),
),
),
'menu_order' => 0,
'position' => 'normal',
'style' => 'default',
'label_placement' => 'top',
'instruction_placement' => 'label',
'hide_on_screen' => '',
'active' => true,
'description' => '',
'show_in_rest' => 0,
) );
} );
Umsetzung
Nun widmen wir uns der Umsetzung. In den folgenden Bildern sehen wir die Website-Ansicht in drei verschiedenen Viewports und unten das Markup (in HTML).
Das äusserste Block-Element mit Abständen zu den weiteren Blöcken (in hellgrün).
Für eine grössere Flexibilität verfügen alle unsere Blöcke über die Möglichkeit, den oberen, bzw. unteren Aussenabstand zu entfernen.

Die eigentliche Box mit Innenabständen.

Die Spaltenaufteilung.
Wir arbeiten mit dem Framework Bootstrap, dieses arbeitet wie die meisten mit einem 12er-Raster. In unserem Beispiel beträgt das Verhältnis der einzelnen Spalten 5 zu 7.

Wir konzentrieren uns auf die linke Spalte mit ihren inneren Abständen. Beim kleinsten Viewport ist ebenfalls ein Aussenabstand (in orange) zu sehen. Da es hier nur Platz für eine Spalte gibt, sind beide Seiten untereinander angeordnet. Mit dem erwähnten Aussenabstand wird verhindert, dass die Textblöcke zu nahe aneinander platziert werden.

Der Text-Teil verfügt über keine fixen Abstände. Innerhalb des Textes können im WYSIWYG-Editor natürlich Abstände definiert werden.

Zu guter Letzt das Link-Feld: Darin können standardmässig Link-Text (Text des Buttons) und Link-Ziel (also eine URL), sowie bestimmt werden, ob beim Klick auf den Button, das Ziel in einem neuen Tab geöffnet werden soll oder in demselben.

Styling
Die Details betreffend Styling beziehe ich aus den Design-Spezifikationen (hier in Figma zur Verfügung gestellt).
Nicht alles kann direkt aus dem Tool gelesen werden, da die einzelnen Komponenten auch in unser Ökosystem von Frameworks und Techstack passen muss.

Fazit
Das war ein einfaches (und abgekürztes) Beispiel einer Block-Erstellung, wie wir sie fast täglich für unsere Kundschaft umsetzen.
Ich werde übrigens oft gefragt, in welchen Sprachen Webentwickler:innen eine Website umsetzen.
In unserem Fall benötigen wir PHP, um Abfragen auf dem Server zu machen (also Daten aus dem CMS zu beziehen). Das Markup schreiben wir in HTML und das Styling in CSS. Genauer gesagt arbeiten wir mit einem CSS-Preprocessor namens Sass, der uns das Arbeiten ein wenig erleichtert. Wenn zur Laufzeit Veränderungen oder Berechnungen passieren müssen, benötigen wir dazu Javascript, genauer jQuery, um dies umzusetzen. In unserem Beispiel war das hier aber nicht nötig.