SMACSS-Press

Avatar of Scott Fennell
Scott Fennell am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Der folgende Text ist ein Gastbeitrag von Scott Fennell. Scott hat kürzlich einen Beitrag auf CSS-Tricks über Klassennamen in WordPress gelesen und hatte eigene Ideen dazu, wie man Kontrolle ausüben kann, anstatt die Dinge so zu belassen, wie sie sind. Seine Idee ist es, wo möglich eine SMACSS-ähnliche Philosophie für Klassennamen durchzusetzen.

Ich habe kürzlich einen Artikel in diesem Bereich über Understanding WordPress CSS Classes genossen. Der Autor bemerkte

WordPress ist extrem anpassbar und es ist möglich, diese Standardklassen zu ändern, aber wir werden hier nicht darauf eingehen. — @carlosinho

Ich habe einige Tricks dazu aufgeschnappt und möchte diese mit Ihnen teilen.

Die SMACSS-Erkenntnis

Ich liebe das SMACSS-Buch. Von all den brillanten Praktiken, die dort empfohlen werden, sind meine Favoriten die Regeln für Klassennamen. Auf die Gefahr hin, viele Seiten Brillanz zu überfliegen, werde ich die Dinge auf ein Beispiel reduzieren

<div class="pod">
  <h3 class="pod-header">heading</h3>
  <ul class="pod-items">
    <li class="pod-item"><a class="pod-item-link" href="#">Click me</a></li>
    <li class="pod-item"><a class="pod-item-link" href="#">Click me</a></li>
  </ul>
</div>

Das ist keine wörtliche Wiedergabe aus dem SMACSS-Buch, aber es repräsentiert, was SMACCS in meinem Workflow bedeutet hat. Bemerkenswert ist

  • Jede Komponente von .pod ist über eine CSS-Klasse zugänglich, die mit pod- präfixiert ist.
  • Komponenten, die eine Eltern-zu-viele-Kinder-Beziehung aufweisen, verwenden ein Singular/Plural-Namensschema, wie in pod-item und pod-items.

Das ist mehr oder weniger mein Idealaufbau für die Adressierung von HTML mit CSS. Es ist das Modell, das ich in diesem Artikel anstreben werde. Leider liefert WordPress das nicht mit.

WordPress SMACSS-ifizieren

Damit WordPress diesem Format folgt, sind vier breite Ansätze erforderlich

  1. Sehr schnelle und einfache Filter, um das, was WordPress ausgibt, mit wenigen Codezeilen zu ändern.
  2. WordPress anweisen, bestimmte Klassen auf Objekte anzuwenden, die wir registrieren.
  3. Gewohnheiten in unseren eigenen benutzerdefinierten Funktionen (entweder Plugin-Zeug oder functions.php) entwickeln, so dass sie leicht und überschaubar auf maßgeschneiderte Klassen übernommen werden können.
  4. Relativ große Überschreibungen von WordPress-Kernfunktionen, die sich letztendlich möglicherweise nicht lohnen.

Es sollte selbstverständlich sein (aber wir sagen es trotzdem): Das direkte Ändern von WordPress-Kerncodedateien ist keine Option.

Filter

Der einfachste Weg, viele der von WordPress gelieferten Klassen zu ändern, ist die Filterung. Nehmen wir an, wir haben einen Datenblock. Das könnten der Post-Titel (eine Zeichenkette) oder ein Array von Post-Klassen sein. Diese Daten sind auf dem Weg irgendwohin, vielleicht von der Datenbank zum Browser, um im Frontend angezeigt zu werden, oder vielleicht auf dem Weg vom Post-Editor zur Datenbank, wo sie gespeichert werden. Oft können wir, wenn Daten von einem Ort zum anderen bewegt werden, diese durch die Verwendung eines Filters ändern. Hier ist ein Beispiel, das die Klassen verwendet, die auf das Body-Tag angewendet werden

/**
 * Extends the default WordPress body class.
 *
 * @param  array $classes An array of css classes.
 * @return array The array of css classes, filtered.
 */
function sjf_body_class( $classes ) {
	
  // If the current post has a post thumbnail, append a body class.
  if ( is_singular() && has_post_thumbnail() ) {
    $classes[] = 'body-has-post-thumbnail';
  }
	
  return $classes;
}

// Apply these classes to the body tag.
add_filter( 'body_class', 'sjf_body_class' );

Beachten Sie, dass wir eine Bedingung haben, um dies nur zu tun, wenn es sich um einen einzelnen Beitrag mit einem Beitragsbild handelt. Es ist wichtig, dass wir das $classes-Array unabhängig vom Ergebnis dieser Bedingung zurückgeben, andernfalls erhalten alle unsere anderen Vorlagen keine Body-Klassen! Betrachten Sie diesen Punkt als ein "Fallen"-Symbol in den O'Reilly Tierbüchern.

Wir können der Klassen-Array jede beliebige Zeichenkette hinzufügen, obwohl wir, wenn wir etwas greifen, das nicht hartcodiert ist, es zuerst bereinigen sollten, mit sanitize_html_class(). Zum Beispiel möchten wir vielleicht einen post_meta-Wert hinzufügen, vielleicht wenn dieser Beitrag in einem speziellen Farbschema künstlerisch gestaltet wurde

/**
 * Extends the default WordPress body class to include the accent color for this post.
 *
 * @param  array $classes An array of css classes.
 * @return array The array of css classes, plus a new class for accent-color.
 */
function sjf_body_class( $classes ) {
	
  // If the current post has an accent color, append a body class.
  if ( is_singular() ) {
    $accent_color = get_post_meta( get_the_ID(), 'sjf_accent_color', TRUE );
    $accent_color = sanitize_html_class( $accent_color );
    if( ! empty( $accent_color ) ) {
      $classes[] = "body-$accent_color";
    }
  }
	
  return $classes;
}

// Apply these classes to the body tag.
add_filter( 'body_class', 'sjf_body_class' );

Wir können das Array von Klassen, das auf Beiträge in der Schleife angewendet wird, auf fast die gleiche Weise modifizieren. Der einzige Unterschied besteht darin, dass wir anstatt unsere Funktion zum body_class-Filter hinzuzufügen, sie zu post_class hinzufügen würden

/**
 * Extends the default WordPress post class to include the accent color for this post.
 *
 * @param  array $classes An array of css classes.
 * @return array The array of css classes, plus a new class for accent-color.
 */
function sjf_post_class( $classes ) {
	
  // If the current post has an accent color, append a post class.
  if ( is_singular() ) {
    $accent_color = get_post_meta( get_the_ID(), 'sjf_accent_color', TRUE );
    $accent_color = sanitize_html_class( $accent_color );
    if( ! empty( $accent_color ) ) {
      $classes[] = "sjf-body-$accent_color-post";
    }
  }
	
  return $classes;
}

// Apply these classes to the post tag.
add_filter( 'post_class', 'sjf_post_class' );

Es gibt viele weitere Hooks wie diesen. Sehen Sie sich Adam Browns Liste an und suchen Sie nach "class", um weitere Ideen zu erhalten. Einige der besten Kandidaten für zusätzliche Klassen sind

DRY es aus

Beachten Sie, dass meine Interpretation von SMACSS vorgibt, dass meine Post-Klassen die gleichen wie meine Body-Klassen sind, nur mit dem Suffix -post angehängt. Dank der Funktion current_filter() können wir tatsächlich dieselbe Funktion verwenden, um unsere Body-Klassen und unsere Post-Klassen auszuführen, was unseren Code DRY hält

function sjf_body_post_class( $classes ) {
	
  // If the current post has an accent color, add a class.
  if ( is_singular() ) {
    $accent_color = get_post_meta( get_the_ID(), 'sjf_accent_color', TRUE );
    $accent_color = sanitize_html_class( $accent_color );
    if( ! empty( $accent_color ) ) {	
      // If we are on the post_class filter, tack on a '-post'.
      $suffix = '';
      if( current_filter() == 'post_class' ) { $suffix = '-post'; }
      $classes[] = "sjf-body-$accent_color$suffix";
    }
  }
	
  return $classes;
}

// Apply these classes to the body tag.
add_filter( 'body_class', 'sjf_body_post_class' );

// Apply these classes to the post tag.
add_filter( 'post_class', 'sjf_body_post_class' );

Filter sind ein mächtiges, aber einfaches Werkzeug, um WordPress-generierten Elementen neue Klassen hinzuzufügen. Aber was ist mit Elementen, die WordPress als Reaktion auf die Registrierung dieses Elements durch ein Theme oder Plugin generiert?

Registrierung

Betrachten Sie diesen Code, der verwendet wird, um eine Sidebar zu registrieren

function sjf_widgets_init() {
  register_sidebar( array(
    'name' => __( 'Main Sidebar', 'sjf' ),
    'id' => 'sjf-main-widgets',
    'description' => __( 'Widgets in this area will be shown on all posts and pages.', 'sjf' ),
    'before_title' => '<h1>',
    'after_title' => '</h1>',
  ) );
}
add_action( 'widgets_init', 'sjf_widgets_init' );

Schön und einfach. Aber wenn unser Ziel ist, SMACSS-ähnliche Klassen auf so viele Elemente wie möglich anzuwenden, was für eine verpasste Gelegenheit! Es gibt viele Stellen, an denen hier Klassen eingefügt werden können, aber im Gegensatz zu den Filtern von früher, wo wir mit einem Array von Klassen umgingen, erfordert diese Situation eine einfache Zeichenkette von Klassennamen. Für dieses Beispiel nehmen wir an, das Design erfordert unterschiedliche Widget-Stile basierend auf dem Anmeldestatus. Hier ist, was wir tun können

function sjf_widgets_init() {

  $slug = 'sjf-main';

  if( is_user_logged_in() ) {
    $logged = 'logged-in';
  } else {
    $logged = 'logged-out';
  }
  
  register_sidebar( array(
    'name'          => __( 'Main Sidebar', 'theme-slug' ),
    'id'            => "$slug-widgets",
    'description'   => __( 'Widgets in this area will be shown on all posts and pages.', 'sjf' ),
    'before_widget' => "<div id='%s' class='widget $slug-widget $slug-widget-$logged_in $slug-widget-%s'>",
    'after_widget'  => '</div>',
    'before_title'  => "<h1 class='widget-title $slug-widget-title $slug-widget-title-$logged_in'>",
    'after_title'   => '</h1>',
  ) );
}
add_action( 'widgets_init', 'sjf_widgets_init' );

Ein paar Dinge, die dort passieren

  • Benutzerdaten. Mit $logged führen wir unseren alten Trick von früher aus und prüfen, ob dieser Beitrag in einem speziellen Farbschema künstlerisch gestaltet wurde.
  • sprintf(). Mit %s fordern wir WordPress auf, diesen kleinen Teil durch den Slug-Namen für diese Art von Widget zu ersetzen. Dinge wie widget_search oder widget_text.
  • Permutationen. Um SMACSS-bereit zu sein, fügen wir nicht nur die Klasse $color_class oder die Klasse $id hinzu und sind damit zufrieden. Wir berücksichtigen verschiedene Kombinationen, die wir wahrscheinlich benötigen werden. Zum Beispiel, wenn wir Suchformulare auf Seiten mit rotem Akzent in der Haupt-Sidebar ansprechen müssen, können wir das mit einer einzigen CSS-Klasse sjf-main-widget-red-widget_search tun.

Um es klarzustellen, ein Grund, warum ich von meinem früheren post_meta-Beispiel abweiche, ist, dass Post-Daten noch nicht verfügbar sind, wenn Widgets registriert werden.

Einige Designs mögen nuanciert genug sein, um noch detailliertere Klassen für Widgets zu rechtfertigen. Es gibt Plugins im .org-Repository, die ein schnelles Klassifizieren pro Widget anbieten: pro Widget Klassifizierung.

Nachdem wir einige Möglichkeiten zur Klassifizierung von WordPress-generierten Elementen behandelt haben, werfen wir nun einen Blick auf unsere eigenen benutzerdefinierten Elemente.

Benutzerdefinierte Funktionen

Entweder in unserer `functions.php` oder in unseren Plugin-Dateien werden wir zweifellos viele unserer eigenen Funktionen registrieren. Ich habe eine Routine entwickelt, um die Dinge SMACSS-bereit zu halten. Betrachten Sie diese Funktion, die einfach hello world zurückgibt

function sjf_hello() {
  return '<span class="sjf-hello">hello world</span>';
}

Überhaupt nicht SMACSS-bereit. Wir brauchen viel mehr, wenn wir dieses Element auf SMACSS-konforme Weise ansprechen wollen. Zum Beispiel, wenn dieses Element innerhalb unseres .pod-Beispiels vom Anfang des Artikels verwendet wird, möchten wir, dass es eine Klasse wie .pod-sjf-hello trägt. Was auch immer die Situation ist, wir wollen bequem so viele Klassen wie nötig injizieren können. Hier ist, was ich tue

/**
 * Get the string "hello world", wrapped and classed.
 *
 * @param  array $classes An array of CSS classes.
 * @return string The "hello world" string, wrapped and classed.
 */
function sjf_hello( $classes = array() ) {
  
  // The namespace for this element.
  $slug = 'sjf-hello';
  
  // Prepend the slug to each class name, convert to a string.
  $classes_str = sjf_prepend_slug( $classes, $slug );
  
  return "<span class='$slug $classes_str'>hello world</span>";
  
}

Beachten Sie, dass meine Funktion jetzt ein Argument für $classes nimmt, das ein Array von CSS-Klassennamen erwartet. Wenn ich ihm viele Klassen übergebe, möchte ich mich nicht darum kümmern, sie alle im Voraus zu präfixieren, also werden sie innerhalb dieser Funktion mit einer zweiten Funktion, sjf_prepend_slug(), präfixiert

/**
 * Prepend a string to each member of an array.
 *
 * @param  array  $classes An array of CSS classes.
 * @param  string $slug    A namespace to prepend to each class.
 * @return string The $classes array, cleaned, slugged, and imploded.
 */
function sjf_prepend_slug( $classes, $slug ) {
  
  $cleaned = array();
  foreach( $classes as $class ) {
    $cleaned []= sanitize_html_class( $slug . '-' . $class );
  }
  
  // Convert the array to a string, with a space between each class name.
  $classes_str = implode( ' ', $cleaned );
  
  return $classes_str;
}

Diese Funktion kümmert sich auch um die Bereinigung aller Klassen. Wir können sie für alle Template-Tags in unserem Theme oder Plugin verwenden.

Diese einfache Routine kann uns helfen, alle unsere benutzerdefinierten Funktionen SMACSS-bereit zu halten, mit minimalem zusätzlichem Code.

Überschreibungen

Alle bisher besprochenen Techniken waren in Bezug auf das Verhältnis von Code zu Ertrag sehr effizient. Das heißt, wir bekommen viel SMACSS-Güte mit relativ wenig Code, und das hat mich inspiriert, diesen Artikel zu schreiben. Es gibt jedoch einen weiteren Weg, den wir einschlagen könnten, und das ist die Überschreibung von Kernfunktionen mit unseren eigenen, um auf dem Weg unsere SMACSS-Klassen hinzuzufügen.

Ich würde dies wahrscheinlich nicht nur zum Zweck des Hinzufügens von SMACSS-Klassen empfehlen, da es viel Code sein kann und mehr Code mehr Fehler bedeutet. Vielmehr sollten wir, wenn es ein Element der Standard-WordPress-Ausgabe gibt, das für unser Projekt ohnehin überarbeitet werden muss (vielleicht aus Design- oder Funktionsgründen), diese Gelegenheit nutzen, es aufzuwerten.

searchform.php

Eine der ersten Überschreibungen, in die sich Theme-Entwickler stürzen, ist das Suchformular. Der Weg dorthin ist, ein neues Suchformular in unserem Theme in einer Datei mit dem reservierten Namen `searchform.php` hinzuzufügen. Ich möchte jedoch mein benutzerdefiniertes Suchformular woanders wiederverwenden können und definiere keine Funktionen außerhalb von `functions.php`, daher sieht mein `searchform.php` so aus

/**
 * sjf search form.
 *
 * @package WordPress
 * @subpackage sjf
 * @since  sjf 1.0
 */

echo sjf_get_search_form();

Meine sjf_get_search_form() lebt in `functions.php` und sieht so aus

/**
 * Returns a WordPress search form.
 *
 * Accepts arguments to inject CSS classes into the form, which this theme uses 
 * in order to comply with SMACSS.  Passing dynamic class values for each 
 * instance would not be possible with the normal use of searchform.php.
 * 
 * @param  array $classes CSS classes for the form.
 * @return string A search form.
 *
 * @since  anchorage 1.0
 */
if( ! function_exists( 'sjf_get_search_form' ) ) {
  function sjf_get_search_form( $classes = array() ) {
    
    $slug = 'sjf-searchform';
    
    // An array of CSS classes for the search form.
    $classes = sjf_prepend_slug( $classes, $slug );
    
    // Grab the search term to use as a watermark.
    $placeholder = esc_attr__( 'Search', 'sjf' );
    if( get_query_var( 's' ) ) {
      $placeholder = esc_attr( get_query_var( 's' ) );
    }

    $action = esc_url( home_url( '/' ) );
    
    $search_for      = esc_html__( 'Search for:', 'sjf' );
    $search_for_attr = esc_attr__( 'Search for:', 'sjf' );
    
    $submit = esc_html__( 'Submit', 'sjf' );

    $out ="
      <form action='$action' class='$classes $slug sjf-form' method='get' role='search'>
        <label class='$classes-label $slug-label sjf-label' for='s'><span class='screen-reader-text'>$search_for</span></label>
        <input id='s' type='search' title='$search_for_attr' name='s' value='$placeholder' class='$classes-input $slug-input sjf-input'>
        <input type='submit' value='$submit' class='$classes-submit $slug-submit sjf-submit'>
      </form>
    ";

    return $out;

  }
}

Das ist ein schickes Formular! Das Formular selbst und jedes darin enthaltene Element ist auf die SMACSS-ähnliche Weise zugänglich, die ich bevorzugee. Ich denke, die meisten Entwickler sind es gewohnt, das Standardformular zu ersetzen, daher ist es wahrscheinlich keine große Mühe, ihm unterwegs einige Klassen zu verpassen.

Dasselbe kann man nicht unbedingt von anderen Komponenten sagen. Ich habe eine ähnliche Anstrengung für die gesamte Kommentartemplate unternommen und bin 500 Zeilen später herausgekommen. Machbar, aber nicht unbedingt lohnenswert.

Navigationsmenü-Walker-Klassen: PHP-Klassen

Wie ich bereits erwähnte, werden die Klassen, die auf Navigationsmenü-Elemente angewendet werden, durch Filter zugänglich gemacht, aber wenn wir eine noch feinere Kontrolle wünschen, um vielleicht Klassen auf die Links selbst, die Untermenüs oder vielleicht einige Glyphen unserer gewählten Icon-Lösung anzuwenden, bietet WordPress eine Möglichkeit, tief einzudringen. Die Walker-Klasse ist fortgeschrittener Stoff und verdient wahrscheinlich ein eigenes Tutorial. Es gibt einige gute Beispiele online und wissen Sie einfach, dass dies ein Weg ist, um CSS-Klassen auf Menüs auf der feinsten Ebene vorstellbar anzuwenden.

Klasse abgewiesen

Ich habe festgestellt, dass im Laufe der Zeit der schwierigste Teil eines Projekts, sauber zu halten, das Stylesheet ist. Funktionen, Seitenvorlagen und Sidebars können kommen und gehen, aber Stylesheets scheinen ewig zu bestehen, mit allen ihren Makeln! Ich denke, eine anfängliche Investition in einige Klassifizierungen kann auf dem weiteren Weg erheblich dazu beitragen, die Dinge überschaubar zu halten.