BEM für Anfänger: Warum Sie BEM brauchen
Veröffentlicht: 2022-03-10BEM macht Ihren Code skalierbar und wiederverwendbar, erhöht so die Produktivität und erleichtert die Teamarbeit. Auch wenn Sie das einzige Mitglied des Teams sind, kann BEM für Sie nützlich sein. Dennoch glauben viele Entwickler, dass ein solcher Systemansatz wie BEM ihrem Projekt zusätzliche Grenzen setzt und Ihr Projekt überladen, schwerfällig und langsam macht.
Wir sammeln alle wesentlichen Aspekte von BEM in komprimierter Form. Dieser Artikel hilft Ihnen, die Grundideen von BEM in nur 20 Minuten zu verstehen und Vorurteile zu entkräften, dass der Systemansatz Ihrem Projekt abträglich ist.
Das Big BEM besteht aus Methodologie , Technologien , Bibliotheken und Tools . In diesem Artikel werden wir mehr über die Methodik selbst sprechen, da sie die geballte Erfahrung einer großen Anzahl von Entwicklern ist und jedem Projekt einen systematischen Ansatz verleiht.
Um Ihnen einige praktische Fälle von BEM zu zeigen, gehen wir auf die BEM-Technologien ein und überspringen die Bibliotheken und Tools vollständig.
Von der Theorie zur Praxis:
- Die Hauptgründe, warum wir keine Selektoren außer Klassen verwenden
- Die Grundlagen von BEM
- Blöcke und Elemente
- Modifikatoren und Mischungen
- Blöcke in der Dateistruktur
- Nicht offensichtliche Vorteile der Methodik
- Praxisbeispiel: BEM ist nicht nur für CSS
- BEM ist ein anpassbares System
Ist BEM also ein Held oder ein Bösewicht? Es liegt an dir! Aber lesen Sie zuerst den Artikel.
Die Hauptgründe, warum wir keine Selektoren außer Klassen verwenden
Eine der Grundregeln der BEM-Methodik besteht darin, nur Klassenselektoren zu verwenden. In diesem Abschnitt erklären wir, warum.
- Warum verwenden wir keine IDs?
- Warum verwenden wir keine Tag-Selektoren?
- Warum verwenden wir keinen universellen Selektor?
- Warum verwenden wir kein CSS-Reset?
- Warum verwenden wir keine verschachtelten Selektoren?
- Warum kombinieren wir nicht ein Tag und eine Klasse in einem Selektor?
- Warum verwenden wir keine kombinierten Selektoren?
- Warum verwenden wir keine Attributselektoren?
Wir verwenden keine IDs (ID-Selektoren)
Die ID stellt einen eindeutigen Namen für ein HTML-Element bereit. Wenn der Name eindeutig ist, können Sie ihn in der Benutzeroberfläche nicht wiederverwenden. Dadurch wird verhindert, dass Sie den Code wiederverwenden.
Häufige Missverständnisse
- Für die Verwendung von JavaScript sind IDs erforderlich.
Moderne Browser können entweder mit IDs oder Klassen arbeiten. Jeder Selektortyp wird im Browser mit der gleichen Rate verarbeitet. - IDs werden mit dem
<label>
-Tag verwendet.
Wenn Sie<label>
in ein Steuerelement einfügen, benötigt es keine ID. Verwenden Sie statt<input id="ID"><label for="ID">Text</label>
einfach<label><input type="...">Text</label>
.
Wir verwenden keine Tag-Selektoren
HTML-Seiten-Markup ist instabil: Ein neues Design kann die Verschachtelung der Abschnitte, Überschriftenebenen (z. B. von <h1>
bis <h3>
) ändern oder den Absatz <p>
in das Tag <div>
umwandeln. Jede dieser Änderungen unterbricht Stile, die für Tags geschrieben wurden. Auch wenn sich das Design nicht ändert, ist die Anzahl der Tags begrenzt. Um ein vorhandenes Layout in einem anderen Projekt zu verwenden, müssen Sie Konflikte zwischen Stilen lösen, die für dieselben Tags geschrieben wurden.
Auch ein erweiterter Satz semantischer Tags kann nicht alle Layout-Anforderungen erfüllen.
Ein Beispiel ist, wenn der Seitenkopf ein Logo enthält. Ein Klick auf das Logo öffnet die Hauptseite der Site ( index
). Sie können es mit Tags auszeichnen, indem Sie das <img>
-Tag für das Bild und das <a>
-Tag für den Link verwenden.
<header> <a href="/"> <img src="img.logo.png" alt="Logo"> </a> </header>
Um zwischen dem Logo-Link und einem gewöhnlichen Link im Text zu unterscheiden, benötigen Sie zusätzliche Stile. Entfernen Sie nun die Unterstreichung und die blaue Farbe aus dem Logo-Link:
header a { ... }
Der Logo-Link muss nicht auf der Hauptseite angezeigt werden, also ändern Sie das Markup der Indexseite:
<header> <!-- the <a> tag is replaced with <span> --> <span> <img src="img.logo.png" alt="Logo"> </span> </header>
Sie müssen die Unterstreichung und die blaue Farbe für das <span>
-Tag nicht entfernen. Lassen Sie uns also allgemeine Regeln für den Logo-Link von verschiedenen Seiten aufstellen:
header a, header span { ... }
Auf den ersten Blick scheint dieser Code in Ordnung zu sein, aber stellen Sie sich vor, der Designer entfernt das Logo aus dem Layout. Die Selektornamen helfen Ihnen nicht zu verstehen, welche Stile mit dem Logo aus dem Projekt entfernt werden sollten. Der Selektor „Kopfzeile a“ zeigt nicht die Verbindung zwischen dem Link und dem Logo. Dieser Selektor könnte zum Link im Kopfmenü oder zum Beispiel zum Link zum Autorenprofil gehören. Der „Header Span“-Selektor könnte zu einem beliebigen Teil des Headers gehören.
Um Verwirrung zu vermeiden, verwenden Sie einfach die logo
, um die Logostile zu schreiben:
.logo { ... }
Wir verwenden kein CSS-Reset
CSS-Reset ist ein Satz globaler CSS-Regeln, die für die gesamte Seite erstellt wurden. Diese Stile wirken sich auf alle Layoutknoten aus, verletzen die Unabhängigkeit von Komponenten und erschweren deren Wiederverwendung.
In BEM werden „Zurücksetzen“ und „Normalisieren“ nicht einmal für einen einzelnen Block verwendet. Das Zurücksetzen und Normalisieren löscht bestehende Stile und ersetzt sie durch andere Stile, die Sie später ohnehin ändern und aktualisieren müssen. Infolgedessen muss der Entwickler Stile schreiben, die die gerade zurückgesetzten überschreiben.
Wir verwenden den Universalselektor nicht ( *
)
Der universelle Selektor gibt an, dass das Projekt einen Stil aufweist, der sich auf alle Knoten im Layout auswirkt. Dies schränkt die Wiederverwendung des Layouts in anderen Projekten ein:
- Die Styles mit einem Sternchen müssen Sie zusätzlich in das Projekt übertragen. Aber in diesem Fall könnte der universelle Selektor die Stile im neuen Projekt beeinflussen.
- Die Stile mit einem Sternchen müssen dem zu übertragenden Layout hinzugefügt werden.
Außerdem kann ein universeller Selektor den Projektcode unvorhersehbar machen. Es kann sich beispielsweise auf die Stile der universellen Bibliothekskomponenten auswirken.
Gemeinsame Stile sparen Ihnen keine Zeit. Oft beginnen Entwickler damit, alle Ränder für Komponenten zurückzusetzen ( * { margin: 0; padding: 0; }
), setzen sie dann aber immer noch so wie im Layout (z. B. margin: 12px; padding: 30px;
).
Wir verwenden keine verschachtelten Selektoren
Verschachtelte Selektoren erhöhen die Codekopplung und erschweren die Wiederverwendung des Codes.
Die BEM-Methodik verbietet verschachtelte Selektoren nicht, empfiehlt aber, sie nicht zu häufig zu verwenden. Die Verschachtelung ist beispielsweise geeignet, wenn Sie den Stil der Elemente abhängig vom Zustand des Blocks oder dem ihm zugewiesenen Thema ändern müssen.
.button_hovered .button__text { text-decoration: underline; } .button_theme_islands .button__text { line-height: 1.5; }
Wir verwenden keine kombinierten Selektoren
Kombinierte Selektoren sind spezifischer als einzelne Selektoren, was es schwieriger macht, Blöcke neu zu definieren.
Betrachten Sie den folgenden Code:
<button class="button button_theme_islands">...</button>
Angenommen, Sie legen im Selektor .button.button_theme_islands
CSS-Regeln fest, um weniger Schreibarbeit zu leisten. Dann fügst du den „aktiven“ Modifikator zum Block hinzu:
<button class="button button_theme_islands button_active">...</button>
Der Selektor .button_active
definiert die als .button.button_theme_islands
geschriebenen Blockeigenschaften nicht neu, da .button.button_theme_islands
spezifischer ist als .button_active
. Um es neu zu definieren, kombinieren Sie den Blockmodifikator-Selektor mit dem .button
Selektor und deklarieren Sie ihn unterhalb der .button.button_theme_islands
, da beide Selektoren gleichermaßen spezifisch sind:
.button.button_theme_islands {} .button.button_active {}
Wenn Sie einfache Klassenselektoren verwenden, werden Sie keine Probleme haben, die Stile neu zu definieren:
.button_theme_islands {} .button_active {} .button {}
Wir kombinieren ein Tag und eine Klasse nicht in einem Selektor
Durch die Kombination eines Tags und einer Klasse im selben Selektor (z. B. button.button
) werden die CSS-Regeln spezifischer, sodass es schwieriger ist, sie neu zu definieren.
Betrachten Sie den folgenden Code:
<button class="button">...</button>
Angenommen, Sie legen CSS-Regeln im Selektor button.button
. Dann fügen Sie den active
Modifikator zum Block hinzu:
<button class="button button_active">...</button>
Der Selektor .button_active
definiert die als button.button
geschriebenen Blockeigenschaften nicht neu, da button.button
spezifischer ist als .button_active
. Um es genauer zu machen, sollten Sie den Blockmodifikator-Selektor mit dem button.button_active
-Tag kombinieren.
Im weiteren Verlauf des Projekts erhalten Sie möglicherweise Blöcke mit input.button
, span.button
oder a.button
. In diesem Fall erfordern alle Modifikatoren des button
und alle seine verschachtelten Elemente vier verschiedene Deklarationen für jede Instanz.
Mögliche Ausnahmen
In seltenen Fällen erlaubt die Methodik das Kombinieren von Tag- und Klassenselektoren. Dies kann zum Beispiel zum Einstellen des Kommentarstils in CMS-Systemen verwendet werden, die nicht das richtige Layout generieren können.
Sie können den Kommentar verwenden, um einen Text zu schreiben, Bilder einzufügen oder Markierungen hinzuzufügen. Um sie an das Website-Design anzupassen, kann der Entwickler Stile für alle Tags vordefinieren, die dem Benutzer zur Verfügung stehen, und sie bis zu den verschachtelten Blöcken kaskadieren:
<div class="content"> ... <!-- the user's text --> </div> CSS rules: .content a { ... } .content p { font-family: Arial, sans-serif; text-align: center; }
Wir verwenden keine Attributselektoren
Attributselektoren sind weniger informativ als Klassenselektoren. Betrachten Sie als Beweis ein Beispiel mit einem Suchformular in der Kopfzeile:
<header> <form action="/"> <input name="s"> <input type="submit"> </form> </header>
Versuchen Sie, Selektorattribute zu verwenden, um die Formularstile zu schreiben:
header input[type=submit], header input[type=checkbox] { width: auto; margin-right: 20px; } header input[type=checkbox] { margin: 0; }
In diesem Beispiel können Sie anhand des Selektornamens nicht sicher erkennen, dass die Stile zum Suchformular gehören. Die Verwendung von Klassen macht es klarer. Klassen haben keine Einschränkungen, die Sie daran hindern, klar zu schreiben. Du kannst es zum Beispiel so schreiben:
.form .search { ... }
Jetzt ist der Code weniger zweideutig und es ist klar, dass die Stile zum Suchformular gehören.
Aber die verschachtelten Selektoren machen die CSS-Regeln immer noch spezifischer und verhindern, dass Sie das Layout zwischen Projekten übertragen. Verwenden Sie BEM-Prinzipien, um die Verschachtelung zu beseitigen.
Zusammenfassung : class
ist der einzige Selektor, mit dem Sie die Stile jeder Komponente im Projekt isolieren können; erhöhen die Lesbarkeit des Codes und schränken die Wiederverwendung des Layouts nicht ein.
Die Isolierung von CSS-Stilen ist der häufigste Ausgangspunkt der BEM-Reise. Aber das ist das Mindeste, was BEM Ihnen geben kann. Um zu verstehen, wie isolierte unabhängige Komponenten in BEM angeordnet sind, müssen Sie die grundlegenden Konzepte lernen, dh Block, Element, Modifier und Mix. Lassen Sie uns dies im nächsten Abschnitt tun.
Die Grundlagen von BEM
- Blöcke und Elemente
- Modifikatoren und Mischungen
- Blöcke in der Dateistruktur
Block und Elemente
Die BEM-Methodik ist ein Satz universeller Regeln, die unabhängig von den verwendeten Technologien wie CSS, Sass, HTML, JavaScript oder React angewendet werden können.
BEM hilft bei der Lösung folgender Aufgaben:
- Verwenden Sie das Layout erneut;
- Verschieben Sie Layoutfragmente sicher innerhalb eines Projekts;
- Verschieben Sie das fertige Layout zwischen Projekten;
- Erstellen Sie stabilen, vorhersehbaren und klaren Code;
- Reduzieren Sie die Debugging-Zeit des Projekts.
In einem BEM-Projekt besteht die Schnittstelle aus Blöcken, die Elemente enthalten können. Blöcke sind unabhängige Komponenten der Seite. Ein Element kann nicht außerhalb des Blocks existieren, also denken Sie daran, dass jedes Element nur zu einem Block gehören kann.
Die ersten beiden Buchstaben in BEM stehen für B -Schlösser und Elemente. Der Blockname ist immer eindeutig. Es legt den Namensraum für Elemente fest und stellt eine sichtbare Verbindung zwischen den Blockteilen her. Blocknamen sind lang, aber eindeutig, um die Verbindung zwischen Komponenten aufzuzeigen und um zu vermeiden, dass Teile dieser Komponenten beim Übertragen des Layouts verloren gehen.
Betrachten Sie dieses Beispiel mit einem Formular, um die volle Leistungsfähigkeit der BEM-Benennung zu sehen. Gemäß der BEM-Methodik wird das Formular über den form
implementiert. In HTML ist der Blockname im class
enthalten:
<form class="form" action="/">
Alle Teile des Formulars (des form
), die für sich genommen keinen Sinn ergeben, werden als seine Elemente betrachtet. Das Suchfeld ( search
) und die Schaltfläche ( submit
) sind also Elemente des form
. Klassen zeigen auch an, dass ein Element zum Block gehört:
<form class="form" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>
Beachten Sie, dass der Name des Blocks durch ein spezielles Trennzeichen vom Namen des Elements getrennt ist. Im klassischen BEM-Namensschema werden zwei Unterstriche als Trennzeichen verwendet. Alles kann als Trennzeichen funktionieren. Es gibt alternative Namenskonventionen, und jeder Entwickler wählt die für ihn passende aus. Wichtig ist, dass Sie mit Trennzeichen programmgesteuert Blöcke von Elementen und Modifikatoren unterscheiden können.
Selektornamen machen deutlich, dass Sie alle seine Komponenten kopieren müssen, um das Formular in ein anderes Projekt zu verschieben:
.form__search {} .form__submit {}
Die Verwendung von Blöcken und Elementen für Klassennamen löst ein wichtiges Problem: Es hilft uns, verschachtelte Selektoren loszuwerden. Alle Selektoren in einem BEM-Projekt haben dieselbe Gewichtung. Das bedeutet, dass es viel einfacher ist, nach BEM geschriebene Stile neu zu definieren. Um dasselbe Formular jetzt in einem anderen Projekt zu verwenden, können Sie einfach sein Layout und seine Stile kopieren.
Die Idee der Benennung von BEM-Komponenten ist, dass Sie die Verbindung zwischen dem Block und seinen Elementen explizit definieren können.
Modifikatoren und Mischungen
Offiziell steht „ M “ für Modifikator, impliziert aber auch einen weiteren wichtigen Begriff in BEM: „Mix“. Sowohl Modifikatoren als auch Mixe nehmen Änderungen an einem Block und seinen Elementen vor. Schauen wir uns das genauer an.
Modifikatoren
Ein Modifikator definiert das Aussehen, den Zustand und das Verhalten eines Blocks oder eines Elements. Das Hinzufügen von Modifikatoren ist optional. Mit Modifikatoren können Sie verschiedene Blockfunktionen kombinieren, da Sie eine beliebige Anzahl von Modifikatoren verwenden können. Aber einem Block oder einem Element können nicht unterschiedliche Werte desselben Modifikators zugewiesen werden.
Lassen Sie uns untersuchen, wie Modifikatoren funktionieren.
Stellen Sie sich vor, das Projekt benötigt das gleiche Suchformular wie im obigen Beispiel. Es sollte die gleichen Funktionen haben, aber unterschiedlich aussehen (z. B. sollten die Suchformulare im Header und im Footer der Seite unterschiedlich sein). Das erste, was Sie tun können, um das Aussehen des Formulars zu ändern, ist, zusätzliche Stile zu schreiben:
header .form {} footer .form {}
Der header .form
Selektor hat mehr Gewicht als der form
, was bedeutet, dass eine Regel die andere außer Kraft setzt. Aber wie wir bereits besprochen haben, erhöhen verschachtelte Selektoren die Codekopplung und erschweren die Wiederverwendung, sodass dieser Ansatz für uns nicht funktioniert.
In BEM können Sie einen Modifikator verwenden, um dem Block neue Stile hinzuzufügen:
<!-- Added the form_type_original modifier--> <form class="form form_type_original" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>
Die Zeile <form class="form form_type_original"></form>
gibt an, dass dem Block ein type
mit dem original
Wert zugewiesen wurde. In einem klassischen Schema wird der Modifikatorname durch einen Unterstrich vom Block- oder Elementnamen getrennt.
Das Formular kann eine einzigartige Farbe, Größe, Art oder ein Designthema haben. Alle diese Parameter können mit einem Modifikator eingestellt werden:
<form class="form form_type_original form_size_m form_theme_forest">
<form class="form form_type_original form_size_m form_theme_forest">
Dasselbe Formular kann unterschiedlich aussehen, aber dieselbe Größe behalten:
<form class="form form_type_original form_size_m form_theme_forest"></form> <form class="form form_type_original form_size_m form_theme_sun"></form>
Aber die Selektoren für jeden Modifikator haben immer noch das gleiche Gewicht:
.form_type_original {} .form_size_m {} .form_theme_forest {}
Wichtig : Ein Modifikator enthält nur zusätzliche Stile, die die ursprüngliche Blockimplementierung in irgendeiner Weise ändern. Auf diese Weise können Sie das Erscheinungsbild eines universellen Blocks nur einmal festlegen und nur die Funktionen, die sich vom ursprünglichen Blockcode unterscheiden, in die Modifikatorstile einfügen.
.form { /* universal block styles */ } .form_type_original { /* added styles */ }
Aus diesem Grund sollte sich ein Modifikator immer auf demselben DOM-Knoten wie der Block und das ihm zugeordnete Element befinden.
<form class="form form_type_original"></form>
Sie können Modifikatoren verwenden, um universelle Komponenten in ganz bestimmten Fällen anzuwenden. Der Block- und Elementcode ändert sich nicht. Die erforderliche Kombination von Modifikatoren wird auf dem DOM-Knoten erstellt.
Mischungen
Eine Mischung ermöglicht es Ihnen, die gleiche Formatierung auf verschiedene HTML-Elemente anzuwenden und das Verhalten und die Stile mehrerer Entitäten zu kombinieren, während Codeduplizierung vermieden wird. Sie können abstrakte Wrapper-Blöcke ersetzen.
Ein Mix bedeutet, dass Sie mehrere BEM-Entitäten (Blöcke, Elemente, Modifikatoren) auf einem einzigen DOM-Knoten hosten. Ähnlich wie Modifikatoren werden Mischungen zum Ändern von Blöcken verwendet. Schauen wir uns einige Beispiele an, wann Sie eine Mischung verwenden sollten.
Blöcke können sich nicht nur optisch, sondern auch semantisch unterscheiden. Beispielsweise sind ein Suchformular, ein Registrierungsformular und ein Formular zum Bestellen von Kuchen allesamt Formulare. Im Layout sind sie mit dem Block „form“ implementiert, haben aber keine gemeinsamen Stile. Es ist unmöglich, solche Unterschiede mit einem Modifikator zu behandeln. Sie können allgemeine Stile für solche Blöcke definieren, aber Sie können den Code nicht wiederverwenden.
.form, .search, .register { ... }
Sie können eine Mischung verwenden, um semantisch unterschiedliche Blöcke für dasselbe Formular zu erstellen:
<form class="form" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>
Der .form
-Klassenselektor beschreibt alle Stile, die auf jedes Formular (Bestellung, Suche oder Registrierung) angewendet werden können:
.form {}
Jetzt können Sie aus dem universellen Formular ein Suchformular erstellen. Legen Sie dazu im Projekt eine zusätzliche search
an. Diese Klasse ist nur für die Suche zuständig. Um die Stile und das Verhalten der .form
und .search
Klassen zu kombinieren, platzieren Sie diese Klassen auf einem einzigen DOM-Knoten:
<form class="form search" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>
In diesem Fall ist die Klasse .search
ein separater Block, der das Verhalten definiert. Dieser Block kann keine Modifikatoren haben, die für Form, Themen und Größen verantwortlich sind. Diese Modifikatoren gehören bereits zur universellen Form. Ein Mix hilft, die Stile und das Verhalten dieser Blöcke zu kombinieren.
Nehmen wir ein weiteres Beispiel, bei dem die Semantik der Komponente geändert wird. Hier ist ein Navigationsmenü im Seitenkopf, in dem alle Einträge verlinkt sind:
<nav class="menu"> <a class="link" href=""></a> <a class="link" href=""></a> <a class="link" href=""></a> </nav>
Die Linkfunktionalität ist bereits im link
implementiert, allerdings müssen sich die Menülinks optisch von den Links im Text unterscheiden. Es gibt mehrere Möglichkeiten, die Menülinks zu ändern:
- Erstellen Sie einen Modifikator für Menüeinträge, der den Eintrag in einen Link umwandelt:
<nav class="menu"> <a class="menu__item menu__item_link" href=""></a> <a class="menu__item menu__item_link" href=""></a> <a class="menu__item menu__item_link" href=""></a> </nav>
In diesem Fall sollten Sie zur Implementierung des Modifikators das Verhalten und die Stile des Blocks „Link“ kopieren. Dies führt zu einer Codeduplizierung. - Verwenden Sie eine Mischung aus dem universellen `link`-Block und dem `item`-Element des `menu`-Blocks:
<nav class="menu"> <a class="link menu__item" href=""></a> <a class="link menu__item" href=""></a> <a class="link menu__item" href=""></a> </nav>
Mit der Mischung der beiden BEM-Entitäten können Sie jetzt die grundlegende Link-Funktionalität aus dem „Link“-Block und zusätzliche CSS-Regeln aus dem „Menü“-Block implementieren und Code-Duplizierung vermeiden.
Externe Geometrie und Positionierung: Verzicht auf abstrakte HTML-Wrapper
Mischungen werden verwendet, um einen Block relativ zu anderen Blöcken zu positionieren oder um Elemente innerhalb eines Blocks zu positionieren. In BEM werden Stile, die für Geometrie und Positionierung verantwortlich sind, im übergeordneten Block festgelegt. Nehmen wir einen universellen Menüblock, der in der Kopfzeile platziert werden muss. Im Layout muss der Block einen Einzug von 20 Pixel vom übergeordneten Block haben.
Diese Aufgabe hat mehrere Lösungen:
- Schreiben Sie Stile mit Einzügen für den Menüblock:
.menu { margin-left: 20px; }
In diesem Fall ist der "Menü"-Block nicht mehr universell. Wenn Sie das Menü im Seitenfuß platzieren müssen, müssen Sie Stile bearbeiten, da die Einzüge wahrscheinlich anders sein werden. - Erstellen Sie den Menüblock-Modifikator:
<div> <ul class="menu menu_type_header"> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> </ul> </div>
.menu_type_header { margin-left: 20px; } .menu_type_footer { margin-left: 30px; }
In diesem Fall enthält das Projekt zwei Arten von Menüs, obwohl dies nicht der Fall ist. Die Speisekarte bleibt gleich. - Definieren Sie die externe Positionierung des Blocks: Verschachteln Sie den `menu`-Block im abstrakten Wrapper (z. B. den `wrap`-Block) und setzen Sie alle Einzüge:
<div class="wrap"> <ul class="menu"> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> </ul> </div>
Um der Versuchung zu widerstehen, Modifikatoren zu erstellen und die Blockstile zu ändern, um den Block auf der Seite zu positionieren, müssen Sie eines verstehen:Der Einzug von einem übergeordneten Block ist kein Merkmal des verschachtelten Blocks. Es ist eine Funktion des übergeordneten Blocks. Es muss wissen, dass der verschachtelte Block um eine bestimmte Anzahl von Pixeln vom Rand eingerückt werden muss.
- Verwenden Sie eine Mischung. Die Information über die Positionierung verschachtelter Blöcke ist in den übergeordneten Blockelementen enthalten. Dann wird das übergeordnete Blockelement in den verschachtelten Block gemischt. In diesem Fall gibt der verschachtelte Block keine Einrückungen vor und kann problemlos an beliebiger Stelle wiederverwendet werden.
Machen wir weiter mit unserem Beispiel:
<div> <ul class="menu header__menu"> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> </ul> </div>
In diesem Fall werden die äußere Geometrie und die Positionierung des menu
über das Element header__menu
. Der menu
gibt keine Einzüge vor und kann einfach wiederverwendet werden.
Das übergeordnete Blockelement (in unserem Fall ist es header__menu
) übernimmt die Aufgabe der Wrapper-Blöcke, die für die externe Positionierung des Blocks verantwortlich sind.
Blöcke in der Dateistruktur
Alle BEM-Projekte haben eine ähnliche Dateistruktur. Die vertraute Dateistruktur erleichtert Entwicklern das Navigieren im Projekt, das Wechseln zwischen Projekten und das Verschieben von Blöcken von einem Projekt in ein anderes.
Die Implementierung jedes Blocks wird in einem separaten Projektordner gespeichert. Jede Technologie (CSS, JavaScript, Tests, Vorlagen, Dokumentation, Bilder) befindet sich in einer separaten Datei.
Wenn beispielsweise das Erscheinungsbild des input
mit CSS festgelegt wird, wird der Code in der Datei input.css
gespeichert.
project common.blocks/ input/ input.css # The "input" block implementation with CSS input.js # The "input" block implementation with JavaScript
Der Code für Modifikatoren und Elemente wird ebenfalls in separaten Dateien des Blocks gespeichert. Dieser Ansatz ermöglicht es Ihnen, nur die Modifikatoren und Elemente in den Build aufzunehmen, die für die Implementierung des Blocks erforderlich sind.
project common.blocks/ input/ input.css # The "input" block implementation with CSS input.js # The "input" block implementation with JavaScript input_theme_sun.css # The "input_theme_sun" modifier implementation input__clear.css # The "input__clear" element implementation with CSS input__clear.js # The "input__clear" element implementation with JavaScript
Um die Projektnavigation zu verbessern, kombinieren Sie Blockmodifikatoren mit mehreren Werten in Verzeichnissen.
Die Dateistruktur jedes BEM-Projekts besteht aus Neudefinitionsebenen (mehr darüber erfahren Sie hier). Mit Neudefinitionsebenen können Sie:
- Unterteilen Sie das Projekt in Plattformen;
- Aktualisieren Sie einfach die im Projekt enthaltenen Blockbibliotheken;
- Verwenden Sie gemeinsame Blöcke, um mehrere Projekte zu entwickeln;
- Ändern Sie die Designthemen, ohne die Projektlogik zu beeinflussen;
- Führen Sie Experimente in einem Live-Projekt durch.
Die Verwendung von Blöcken und das Speichern aller Blocktechnologien im selben Ordner erleichtert das Verschieben von Blöcken zwischen Projekten. Um alle Stile und Verhaltensweisen des Blocks zusammen mit dem Layout zu verschieben, kopieren Sie einfach den Blockordner in das neue Projekt.
Nicht offensichtliche Vorteile der Methodik
Die Bequemlichkeit der parallelen Entwicklung
In BEM wird jedes Layout in Blöcke unterteilt. Da die Blöcke unabhängig sind, können sie von mehreren Entwicklern parallel entwickelt werden.
Ein Entwickler erstellt einen Block als universelle Komponente, die in jedem anderen Projekt wiederverwendet werden kann.
Ein Beispiel ist die Bausteinbibliothek bem-components, die universelle Bausteine wie Link, Button und Eingabefeld enthält. Es ist einfacher, komplexere Blöcke aus universellen Komponenten zu erstellen. Beispielsweise eine Auswahl oder ein Kontrollkästchen.
Die Verwendung von Blöcken im Projektlayout hilft Ihnen, die Zeit für die Integration von Code zu sparen, der von mehreren Entwicklern geschrieben wurde, garantiert die Eindeutigkeit von Komponentennamen und ermöglicht Ihnen das Testen von Blöcken in der Entwicklungsphase.
Testen des Layouts
Es ist problematisch, die Funktionalität der gesamten Seite zu testen, insbesondere in einem dynamischen Projekt, das mit einer Datenbank verbunden ist.
In BEM wird jeder Block durch Tests abgedeckt. Tests sind eine Blockimplementierungstechnologie wie Javascript oder CSS. Blöcke werden in der Entwicklungsphase getestet. Es ist einfacher, die Korrektheit eines Blocks zu überprüfen und dann das Projekt aus getesteten Blöcken zusammenzusetzen. Danach müssen Sie nur noch sicherstellen, dass der Block-Wrapper korrekt funktioniert.
Anpassbarer Aufbau eines Projekts
Zur bequemen Entwicklung werden alle Blöcke und Technologien in einem BEM-Projekt in separaten Ordnern und Dateien abgelegt. Um die Quelldateien in einer einzigen Datei zusammenzufassen (um beispielsweise alle CSS-Dateien in project.css
, alle JS-Dateien in project.js
usw. abzulegen), verwenden wir den Build-Prozess.
Der Build führt die folgenden Aufgaben aus:
- Kombiniert Quelldateien, die über das Dateisystem des Projekts verteilt sind;
- Schließt nur notwendige Blöcke, Elemente und Modifikatoren (BEM-Entitäten) in das Projekt ein;
- Folgt der Reihenfolge zum Einschließen von Entitäten;
- Verarbeitet den Code der Quelldatei während des Builds (kompiliert zB LESS-Code in CSS-Code).
Um nur die erforderlichen BEM-Entitäten in den Build aufzunehmen, müssen Sie eine Liste der Blöcke, Elemente und Modifikatoren erstellen, die auf den Seiten verwendet werden. Diese Liste wird Deklaration genannt.
Da BEM-Blöcke unabhängig voneinander entwickelt und in separaten Dateien im Dateisystem platziert werden, „wissen“ sie nichts voneinander. Um Blöcke basierend auf anderen Blöcken zu erstellen, geben Sie Abhängigkeiten an. Dafür ist eine BEM-Technologie verantwortlich: die deps.js
Dateien. Abhängigkeitsdateien teilen der Build-Engine mit, welche zusätzlichen Blöcke in das Projekt aufgenommen werden müssen.
Praxisbeispiel: BEM ist nicht nur für CSS
In den vorherigen Abschnitten beziehen sich alle Codebeispiele auf CSS. Mit BEM können Sie jedoch das Verhalten des Blocks und seine Darstellung in HTML auf die gleiche deklarative Weise wie in CSS ändern.
Verwendung von Vorlagen in BEM
In HTML wird das Block-Markup jedes Mal wiederholt, wenn der Block auf der Seite erscheint. Wenn Sie das HTML-Markup manuell erstellen und dann einen Fehler beheben oder Änderungen vornehmen müssen, müssen Sie das Markup für jede Instanz des Blocks ändern. Um HTML-Code zu generieren und Korrekturen automatisch anzuwenden, verwendet BEM Vorlagen; Blöcke sind dafür verantwortlich, wie sie in HTML dargestellt werden.
Mit Vorlagen können Sie:
- Reduzieren Sie den Zeitaufwand für das Debuggen von Projekten, da die Vorlagenänderungen automatisch auf alle Projektblöcke angewendet werden.
- Ändern Sie das Blocklayout;
- Verschieben Sie Blöcke mit dem aktuellen Layout in ein anderes Projekt.
BEM verwendet die Vorlagen-Engine bem-xjst, die zwei Engines umfasst:
- BEMHTML
Wandelt die BEMJSON-Beschreibung der Seite in HTML um. Die Vorlagen werden in .bemhtml.js-Dateien beschrieben. - BEMBAUM
Wandelt Daten in BEMJSON um. Die Vorlagen werden im BEMJSON-Format in .bemtree.js- Dateien beschrieben.
Wenn für die Blöcke keine Vorlagen geschrieben werden, legt die Vorlagen-Engine standardmäßig das <div>
-Tag für die Blöcke fest.
Vergleichen Sie die Deklaration der Blöcke und die HTML-Ausgabe:
Erklärung:
{ block: 'menu', content: [ { elem: 'item', content: { block: 'link'} }, { elem: 'item', elemMods: { current: true }, // Set the modifier for the menu item content: { block: 'link' } } ] }
HTML:
<div class="menu"> <div class="menu__item"> <div class="link"></div> </div> <div class="menu__item menu__item_current"> <div class="link"></div> </div> </div>
Um das Layout des menu
zu ändern, müssen Sie Vorlagen für den Block schreiben:
- Lassen Sie uns das
menu
-Tag ändern:block('menu')( tag()('menu') // Set the "menu" tag for the menu block )
Modifizierter HTML-Code:<menu class="menu"> <!-- Replace the "div" tag with the "menu" tag for the "menu" block --> <div class="menu__item"> <div class="link"></div> </div> <div class="menu__item menu__item_current"> <div class="link"></div> </div> </menu>
Ähnlich wie bei CSS wird die Vorlage auf alle „Menü“-Blöcke auf der Seite angewendet. - Fügen Sie ein zusätzliches Element (
menu__inner
) hinzu, das als innerer Wrapper fungiert und für das Layout der Elemente immenu
verantwortlich ist. Ursprünglich war das Elementmenu__inner
nicht in der Deklaration enthalten, daher müssen wir es hinzufügen, wenn die Vorlagen erstellt werden.
BEM-Vorlagen sind in JavaScript geschrieben, Sie können also auch JavaScript verwenden, um der Vorlage ein neues Element hinzuzufügen:block('menu')( tag()('menu'), content()(function() { return { elem: 'inner', content: this.ctx.content }; }) )
<menu class="menu"> <!-- Replace the "div" tag with the "menu" tag for the "menu" block --> <div class="menu__inner"> <div class="menu__item"> <div class="link"></div> </div> <div class="menu__item menu__item_current"> <div class="link"></div> </div> </div> </menu>
- Tags für alle
inner
unditem
ersetzen:block('menu')( tag()('menu'), content()(function() { return { elem: 'inner', content: this.ctx.content } }), elem('inner')( tag()('ul') ), elem('item')( tag()('li') ) )
<menu class="menu"> <ul class="menu__inner"> <li class="menu__item"> <div class="link"></div> </li> <li class="menu__item menu__item_current"> <div class="link"></div> </li> </ul> </menu>
- Setzen Sie das
<a>
-Tag für alle Links auf der Seite:block('menu')( tag()('menu'), content()(function() { return { elem: 'inner', content: this.ctx.content } }), elem('inner')( tag()('ul') ), elem('item')( tag()('li') ) ); block('link')( tag()('a') );
<menu class="menu"> <ul class="menu__inner"> <li class="menu__item"> <a class="link"></a> </li> <li class="menu__item menu__item_current"> <a class="link"></a> </li> </ul> </menu>
- Ändern Sie die vorhandene Vorlage. Regeln in Vorlagen werden auf die gleiche Weise angewendet wie in CSS: Eine niedrigere Regel überschreibt eine höhere Regel. Fügen Sie der Vorlage neue Regeln hinzu und ändern Sie das Link-Tag von
<a>
in<span>
:block('link')( tag()('a') ); block('link')( tag()('span') );
<menu class="menu"> <ul class="menu__inner"> <li class="menu__item"> <span class="link"></span> </li> <li class="menu__item menu__item_current"> <span class="link"></span> </li> </ul> </menu>
BEM ist ein anpassbares System
Die BEM-Methodik bietet Ihnen strenge Regeln zum Erstellen eines Systems in Ihrem Projekt. Gleichzeitig können viele BEM-Regeln angepasst werden. Mit der BEM-Methodik können Sie die Namenskonvention ändern, die bequemste Dateistruktur auswählen oder beliebige Technologien zum Block hinzufügen.
Jetzt können Sie das System einschalten und Ihren eigenen Superhelden aus BEM machen!
So holen Sie mehr aus BEM heraus
Um mit dem Erlernen der BEM-Prinzipien zu beginnen, besuchen Sie unsere Website. Wenn Sie Fragen haben, die Sie dem Team stellen möchten, treten Sie unserem Telegram-Kanal bei oder eröffnen Sie eine Diskussion in unserem BEM-Forum.