Fünf Methoden für Fünf-Sterne-Bewertungen

Avatar of Alfred Genkin
Alfred Genkin am

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

In der Welt der Likes und sozialen Statistiken sind Bewertungen eine sehr wichtige Methode, um Feedback zu hinterlassen. Nutzer möchten oft die Meinungen anderer kennen, bevor sie sich für Produkte entscheiden, die sie selbst kaufen möchten, oder sogar für Artikel, die sie lesen, Filme, die sie sehen, oder Restaurants, in denen sie speisen.

Entwickler kämpfen oft mit Bewertungen – es ist üblich, unzugängliche und übermäßig komplizierte Implementierungen zu sehen. Hey, CSS-Tricks hat einen Snippet dafür, das inzwischen fast ein Jahrzehnt alt ist.

Lassen Sie uns neue, zugängliche *und* wartbare Ansätze für dieses klassische Designmuster durchgehen. Unser Ziel wird es sein, die Anforderungen zu definieren und dann eine Reise durch den Denkprozess und die Überlegungen zur Implementierung zu unternehmen.

Umfang der Arbeit

Wussten Sie, dass die Verwendung von Sternen als Bewertung bis ins Jahr 1844 zurückreicht, als sie erstmals zur Bewertung von Restaurants in den Murray’s Handbooks for Travellers verwendet wurden – und später 1931 von den Michelin Guides als Drei-Sterne-System popularisiert wurden? Da gibt es viel Geschichte, kein Wunder also, dass wir es gewohnt sind, das zu sehen!

Es gibt einige gute Gründe, warum sie den Test der Zeit bestanden haben

  1. Klare visuelle Darstellung (in Form von fünf leeren oder ausgefüllten Sternen in einer Reihe)
  2. Eine klare Beschriftung (die eine zugängliche Beschreibung liefert, wie z. B. aria-label)

Wenn wir es im Web implementieren, ist es wichtig, dass wir uns darauf konzentrieren, beide Ergebnisse zu erzielen.

Es ist auch wichtig, solche Funktionen so vielseitig wie möglich zu implementieren. Das bedeutet, wir sollten so viel wie möglich auf HTML und CSS zurückgreifen und versuchen, JavaScript zu vermeiden, wo immer wir können. Und das liegt daran

  1. JavaScript-Lösungen werden sich immer je nach Framework unterscheiden. Muster, die in Vanilla JavaScript typisch sind, können in Frameworks Anti-Muster sein (z. B. verbietet React die direkte Dokumentenmanipulation).
  2. Sprachen wie JavaScript entwickeln sich schnell, was großartig für die Community ist, aber nicht so gut für Artikel wie diesen. Wir wollen eine Lösung, die langfristig wartbar und relevant ist, also sollten wir unsere Entscheidungen auf konsistenten, stabilen Werkzeugen basieren.

Methoden zur Erstellung der Grafiken

Eines der vielen wunderbaren Dinge an CSS ist, dass es oft viele Wege gibt, dasselbe zu schreiben. Nun, dasselbe gilt auch für die Art und Weise, wie wir Sterne zeichnen können. Es gibt fünf Optionen, die ich sehe

  • Verwendung einer Bilddatei
  • Verwendung eines Hintergrundbilds
  • Verwendung von SVG zum Zeichnen der Form
  • Verwendung von CSS zum Zeichnen der Form
  • Verwendung von Unicode-Symbolen

Welche soll man wählen? Das hängt davon ab. Lassen Sie uns alle überprüfen.

Methode 1: Verwendung einer Bilddatei

Die Verwendung von Bildern bedeutet die Erstellung von Elementen – mindestens 5 Stück, um genau zu sein. Selbst wenn wir für jeden Stern in einer Fünf-Sterne-Bewertung dieselbe Bilddatei aufrufen, sind das fünf Anfragen insgesamt. Was sind die Konsequenzen daraus?

  1. Mehr DOM-Knoten machen die Dokumentenstruktur komplexer, was zu einem langsameren Seitenaufbau führen kann. Die Elemente selbst müssen gerendert werden, was entweder die Serverantwortzeit (bei SSR) oder die Hauptthread-Generierung (wenn wir in einer SPA) erhöhen muss. Das berücksichtigt noch nicht die Rendering-Logik, die implementiert werden muss.
  2. Es werden keine Bruchteilbewertungen unterstützt, z. B. 2,3 Sterne von 5. Dafür wäre eine zweite Gruppe von duplizierten Elementen erforderlich, die mit clip-path darüber maskiert sind. Dies erhöht die Komplexität des Dokuments um mindestens sieben weitere DOM-Knoten und potenziell Dutzende zusätzlicher CSS-Eigenschaftsdeklarationen.
  3. Optimierte Performance sollte berücksichtigen, wie Bilder geladen werden, und die Implementierung von etwas wie Lazy Loading für Bilder außerhalb des sichtbaren Bereichs wird zunehmend schwieriger, wenn wiederholte Elemente wie diese hinzugefügt werden.
  4. Es wird eine Anfrage gestellt, was bedeutet, dass die TTLs des Caching konfiguriert werden müssen, um eine sofortige zweite Bildladung zu erreichen. Aber selbst wenn dies korrekt konfiguriert ist, wird die erste Ladung immer noch leiden, da TTFB vom Server abhängt. Prefetch, Pre-Connect-Techniken oder der Service-Worker sollten berücksichtigt werden, um die erste Ladung des Bildes zu optimieren.
  5. Es werden mindestens fünf nichtssagende Elemente für einen Screenreader erstellt. Wie wir bereits besprochen haben, ist die Beschriftung wichtiger als das Bild selbst. Es gibt keinen Grund, sie im DOM zu lassen, da sie der Bewertung keinen Sinn verleihen – sie sind nur ein gängiges visuelles Element.
  6. Die Bilder können Teil eines verwaltbaren Mediens sein, was bedeutet, dass Content-Manager das Aussehen der Sterne jederzeit ändern können, auch wenn es falsch ist.
  7. Es ermöglicht ein vielseitiges Aussehen des Sterns, aber der aktive Zustand kann nur dem Anfangszustand ähneln. Es ist nicht möglich, das src-Attribut des Bildes ohne JavaScript zu ändern, und das ist etwas, das wir vermeiden wollen.

Sie fragen sich, wie die HTML-Struktur aussehen könnte? Wahrscheinlich so:

<div class="Rating" aria-label="Rating of this item is 3 out of 5">
  <img src="/static/assets/star.png" class="Rating--Star Rating--Star__active">
  <img src="/static/assets/star.png" class="Rating--Star Rating--Star__active">
  <img src="/static/assets/star.png" class="Rating--Star Rating--Star__active">
  <img src="/static/assets/star.png" class="Rating--Star">
  <img src="/static/assets/star.png" class="Rating--Star">
</div>

Um das Aussehen dieser Sterne zu ändern, können wir mehrere CSS-Eigenschaften verwenden. Zum Beispiel:

.Rating--Star {
  filter: grayscale(100%); // maybe we want stars to become grey if inactive
  opacity: .3; // maybe we want stars to become opaque
}

Ein zusätzlicher Vorteil dieser Methode ist, dass das <img>-Element standardmäßig auf inline-block gesetzt ist, sodass etwas weniger Styling erforderlich ist, um es in einer einzigen Zeile zu positionieren.

Barrierefreiheit: ★★☆☆☆
Verwaltung: ★★★★☆
Performance: ★☆☆☆☆
Wartung: ★★★★☆
Gesamt: ★★☆☆☆

Methode 2: Verwendung eines Hintergrundbilds

Dies war einst eine ziemlich gängige Implementierung. Dennoch hat sie immer noch ihre Vor- und Nachteile.

Zum Beispiel:

  1. Sicher, es ist nur eine einzige Serveranfrage, was viele Caching-Anforderungen entfällt. Gleichzeitig müssen wir jetzt auf drei zusätzliche Ereignisse warten, bevor die Sterne angezeigt werden: Das wären (1) das Downloaden des CSS, (2) das Parsen des CSSOM und (3) das Herunterladen des Bildes selbst.
  2. Es ist sehr einfach, den Zustand eines Sterns von leer zu gefüllt zu ändern, da wir im Grunde nur die Position eines Hintergrundbilds ändern. Allerdings ist es nicht ideal in Bezug auf die Wartung, jedes Mal, wenn eine Änderung am Aussehen der Sterne vorgenommen werden muss, einen Bildeditor öffnen und die Datei neu hochladen zu müssen.
  3. Wir können CSS-Eigenschaften wie die background-repeat-Eigenschaft und clip-path verwenden, um die Anzahl der DOM-Knoten zu reduzieren. Wir könnten sozusagen ein einziges Element verwenden, um dies zu bewerkstelligen. Auf der anderen Seite ist es nicht gut, dass wir technisch keine gute zugängliche Markup haben, um die Bilder für Screenreader zu identifizieren und die Sterne als Eingaben zu erkennen. Nun, nicht einfach.

Meiner Meinung nach eignen sich Hintergrundbilder am besten für komplexe Stern-Darstellungen, bei denen weder CSS noch SVG ausreichen, um das exakte Styling zu erzielen. Ansonsten birgt die Verwendung von Hintergrundbildern immer noch viele Kompromisse.

Barrierefreiheit: ★★★☆☆
Verwaltung: ★★★★☆
Performance: ★★☆☆☆
Wartung: ★★★☆☆
Gesamt: ★★★☆☆

Methode 3: Verwendung von SVG zum Zeichnen der Form

SVG ist großartig! Es hat viele der gleichen Vorteile beim benutzerdefinierten Zeichnen wie Rasterbilder, erfordert aber keinen Serveraufruf, wenn es inline ist, weil es einfach Code ist!

Wir könnten fünf Sterne in HTML einfügen, aber wir können es besser machen, oder? Chris hat uns einen schönen Ansatz gezeigt, der es uns ermöglicht, die SVG-Markup für eine einzelne Form als <symbol></symbol> bereitzustellen und sie mehrmals mit <use></use> aufzurufen.

<!-- Draw the star as a symbol and remove it from view -->
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="star" viewBox="214.7 0 182.6 792">
    <!-- <path>s and whatever other shapes in here -->  
  </symbol>
</svg>
    
<!-- Then use anywhere and as many times as we want! -->
<svg class="icon">
  <use xlink:href="#star"></use>
</svg>

<svg class="icon">
  <use xlink:href="#star"></use>
</svg>

<svg class="icon">
  <use xlink:href="#star"></use>
</svg>

<svg class="icon">
  <use xlink:href="#star"></use>
</svg>

<svg class="icon">
  <use xlink:href="#star"></use>
</svg>

Was sind die Vorteile? Nun, wir sprechen von null Anfragen, saubererem HTML, keinen Sorgen wegen Pixelbildung und sofort verfügbaren zugänglichen Attributen. Plus, wir haben die Flexibilität, die Sterne überall zu verwenden und die Skalierung, sie so oft zu verwenden, wie wir wollen, ohne zusätzliche Leistungseinbußen. Super!

Der ultimative Vorteil ist, dass dies auch keinen zusätzlichen Overhead erfordert. Zum Beispiel brauchen wir keinen Build-Prozess, um dies zu ermöglichen, und es gibt keine Abhängigkeit von zusätzlicher Bildbearbeitungssoftware, um weitere Änderungen später vorzunehmen (obwohl es, seien wir ehrlich, hilfreich ist).

Barrierefreiheit: ★★★★★
Verwaltung: ★★☆☆☆
Performance: ★★★★★
Wartung: ★★★★☆
Gesamt: ★★★★☆

Methode 4: Verwendung von CSS zum Zeichnen der Form

Diese Methode ist der Methode mit dem background-image sehr ähnlich, verbessert diese jedoch, indem die Form mit CSS-Eigenschaften gezeichnet wird, anstatt eine Bilddatei anzufordern. Wir denken vielleicht, dass CSS dazu dient, Elemente mit Rändern, Schriftarten und anderem zu gestalten, aber es kann auch ziemlich komplexe Kunstwerke hervorbringen. Schauen Sie sich nur Dianas berühmtes Porträt „Francine“ an.

Francine, eine CSS-Nachbildung eines Ölgemäldes, erstellt in CSS von Diana Smith (Quelle)

So verrückt werden wir es nicht treiben, aber Sie können sehen, worauf wir hinauswollen. Tatsächlich gibt es bereits eine nette Demo einer CSS-Sternform hier auf CSS-Tricks.

Siehe den Pen
Fünf Sterne!
von Geoff Graham (@geoffgraham)
auf CodePen.

Oder, hey, wir können ein bisschen raffinierter sein und die clip-path-Eigenschaft verwenden, um ein Fünf-Punkte-Polygon zu zeichnen. Noch weniger CSS! Aber Vorsicht, denn Ihre Cross-Browser-Unterstützung kann variieren.

Siehe den Pen
5 ausgeschnittene Sterne!
von Geoff Graham (@geoffgraham)
auf CodePen.

Barrierefreiheit: ★★★★★
Verwaltung: ★★☆☆☆
Performance: ★★★★★
Wartung: ★★☆☆☆
Gesamt: ★★★☆☆

Methode 5: Verwendung von Unicode-Symbolen

Diese Methode ist sehr gut, aber sehr begrenzt in Bezug auf das Aussehen. Warum? Weil das Aussehen des Sterns als Unicode-Zeichen fest vorgegeben ist. Aber hey, es gibt Variationen für einen gefüllten Stern (★) und einen leeren Stern (☆), was genau das ist, was wir brauchen!

Unicode-Zeichen können Sie entweder direkt in das HTML kopieren und einfügen

Siehe den Pen
Unicode Sterne!
von Geoff Graham (@geoffgraham)
auf CodePen.

Wir können Schriftart, Farbe, Breite, Höhe und andere Eigenschaften verwenden, um die Dinge ein wenig zu skalieren und zu gestalten, aber viel Flexibilität gibt es hier nicht. Aber das ist vielleicht der grundlegendste HTML-Ansatz von allen, dass er fast zu offensichtlich erscheint.

Stattdessen können wir den Inhalt als Pseudo-Element in das CSS verschieben. Das eröffnet zusätzliche Styling-Möglichkeiten, einschließlich der Verwendung von benutzerdefinierten Eigenschaften, um die Sterne bruchstückhaft zu füllen

Siehe den Pen
Minimalistische und zugängliche 5-Sterne-Bewertung
von Fred Genkin (@FredGenkin)
auf CodePen.

Lassen Sie uns das letzte Beispiel etwas genauer betrachten, da es die besten Vorteile aus anderen Methoden zieht und sie in einer einzigen Lösung mit sehr wenigen Nachteilen zusammenfügt, während alle unsere Anforderungen erfüllt werden.

Beginnen wir mit dem HTML. Es gibt ein einziges Element, das keine Serveranfragen stellt und gleichzeitig die Barrierefreiheit wahrt.

<div class="stars" style="--rating: 2.3;" aria-label="Rating of this product is 2.3 out of 5."></div>

Wie Sie sehen können, wird der Bewertungswert als inline benutzerdefinierte CSS-Eigenschaft (--rating) übergeben. Das bedeutet, dass keine zusätzliche Rendering-Logik erforderlich ist, außer die gleiche Bewertung im Label für bessere Barrierefreiheit anzuzeigen.

Schauen wir uns diese benutzerdefinierte Eigenschaft an. Sie ist eigentlich eine Umwandlung eines Rohwerts in einen Prozentsatz, die im CSS mit der calc()-Funktion erfolgt.

--percent: calc(var(--rating) / 5 * 100%);

Ich habe mich für diesen Weg entschieden, weil CSS-Eigenschaften wie width und linear-gradient keine <number></number>-Werte akzeptieren. Sie akzeptieren stattdessen <length></length> und <percentage></percentage> und haben spezifische Einheiten wie % und px, em. Anfänglich ist der Bewertungswert eine Gleitkommazahl, ein <number></number>-Typ. Die Verwendung dieser Umwandlung stellt sicher, dass wir die Werte auf verschiedene Weise verwenden können.

Das Füllen der Sterne mag schwierig klingen, aber es ist ziemlich einfach. Wir benötigen einen linear-gradient-Hintergrund, um harte Farbstopps zu erzeugen, wo die goldfarbene Füllung enden soll.

background: linear-gradient(90deg,
  var(--star-background) var(--percent), 
  var(--star-color) var(--percent)
);

Beachten Sie, dass ich benutzerdefinierte Variablen für Farben verwende, da ich die Stile leicht anpassbar gestalten möchte. Da benutzerdefinierte Eigenschaften von den Stilen der Elternelemente geerbt werden, können Sie sie einmal auf dem :root-Element definieren und dann in einem Element-Wrapper überschreiben. Hier ist, was ich in den Root eingefügt habe:

:root {
  --star-size: 60px;
  --star-color: #fff;
  --star-background: #fc0;
}

Das Letzte, was ich getan habe, war, den Hintergrund auf die Form des Textes zuzuschneiden, damit der Hintergrundverlauf die Form der Sterne annimmt. Stellen Sie sich die Unicode-Sterne als Schablonen vor, mit denen wir die Sternform aus der Hintergrundfarbe ausschneiden. Oder wie Keksausstecher in Sternform, die direkt in den Teig gedrückt werden.

-webkit-background-clip: text;
-webkit-text-fill-color: transparent;

Die Browserunterstützung für Background Clipping und Text Fills ist ziemlich gut. IE11 ist der einzige Ausreißer.

Barrierefreiheit: ★★★★★
Verwaltung: ★★☆☆☆
Performance: ★★★★★
Wartung: ★★★★★
Gesamt: ★★★★★

Abschließende Gedanken

Bilddateien Hintergrundbild SVG CSS-Formen Unicode-Symbole
Barrierefreiheit ★★☆☆☆ ★★★☆☆ ★★★★★ ★★★★★ ★★★★★
Verwaltung ★★★★☆ ★★★★☆ ★★☆☆☆ ★★☆☆☆ ★★☆☆☆
Leistung ★☆☆☆☆ ★★☆☆☆ ★★★★★ ★★★★★ ★★★★★
Wartung ★★★★☆ ★★★☆☆ ★★★★☆ ★★☆☆☆ ★★★★★
Gesamt ★★☆☆☆ ★★★☆☆ ★★★★☆ ★★★☆☆ ★★★★★

Von den fünf behandelten Methoden sind zwei meine Favoriten: die Verwendung von SVG (Methode 3) und die Verwendung von Unicode-Zeichen in Pseudo-Elementen (Methode 5). Es gibt definitiv Anwendungsfälle, in denen ein Hintergrundbild viel Sinn ergibt, aber das scheint eher eine fallweise Bewertung als eine Standardlösung zu sein.

Man muss immer alle Vorteile und Nachteile einer bestimmten Methode berücksichtigen. Das ist meiner Meinung nach die Schönheit der Frontend-Entwicklung! Es gibt mehrere Wege, und Erfahrung ist erforderlich, um Funktionen effizient zu implementieren.