Startseite / Artikel

Ein animierter Daumen-hoch-Feedback-Button ohne jegliche Animationsbibliothek

Erstellen Sie ein Feedback-Widget mit Daumen nach oben und Daumen nach unten samt Pop-Animation durch Keyframes, aktiven Zuständen sowie einer Abfrageruf, unter Verwendung ausschließlich von HTML, CSS und einigen Zeilen JavaScript.

Verlag: REACTAPP.TOP7 Min. Lesezeit1559 Wörter

Quellen: Creating an Interactive Thumbs Up Feedback Button with HTML, CSS and JavaScript

Die „Thumbs-up“- und „Thumbs-down“-Schaltflächen sind eine der günstigsten Möglichkeiten, Nutzer zu fragen, ob eine Seite, eine Antwort oder eine Funktion ihnen geholfen hat. Die übliche Umsetzung ändert beim Klicken lediglich die Hintergrundfarbe, was leicht übersehen werden kann, wenn sich sonst nichts auf der Seite ändert. In dieser Anleitung wird eine etwas anspruchsvollere Version erstellt: Beim Klicken auf „Thumbs-up“ wechselt das Icon kurz in ein funkelndes Smiley, das mit einer Skalierungs- und Drehanimation erscheint, bevor es wieder in ein hervorgehobenes „Thumbs-up“-Icon übergeht. Sie werden die Markup-Struktur, die CSS-Einstellungen, die JavaScript-Code zur Steuerung der Zustände sowie die noch zu behebenden Mängel sehen, bevor das Widget veröffentlicht wird.

Was das Widget leistet

Die Benutzeroberfläche enthält zwei runde Schaltflächen – eine für positive und eine für negative Rückmeldungen. Ein Klick auf die positive Schaltfläche löst eine kurze Abfolge aus:

  1. Das „Thumbs-up“-Icon wird durch ein Smiley ersetzt, das von funkelnden Symbolen umgeben ist.
  • Eine Keyframe-Animation zeigt es mit leichtem Wachsen und Drehen an.
  • Nach einer kurzen Pause wechselt das Smiley wieder zu einem einfachen Daumen nach oben.
  • Die Schaltfläche wechselt in einen aktiven, hervorgehobenen Zustand.
  • Mikrointeraktionen wie diese sorgen dafür, dass eine Benutzeroberfläche auch ohne Animationssystem reaktiv wirkt.

    Markup für die beiden Schaltflächen

    Jede Schaltfläche erhält eine ID für das Scripting, eine gemeinsame Klasse für das Styling sowie eine Modifikatorklasse für ihre eigene aktive Farbe. Die Icons sind Emoji-Zeichen innerhalb der Schaltflächen:

    <div class="feedback">
      <button
          id="thumbsUp"
          class="feedback-btn thumbs-up"
          aria-label="Thumbs up">
          👍🏻
      </button>
      <button
          id="thumbsDown"
          class="feedback-btn thumbs-down"
          aria-label="Thumbs down">
          👎🏻
      </button>
    </div>
    

    Die aria-label ist hier wichtig. Ohne sie würde ein Bildschirmleser den eigenen Namen des Emojis angeben (oder nichts Nützliches), weshalb die Beschriftung jeder Schaltfläche einen klaren, zugänglichen Namen gibt. Wenn Sie möchten, dass assistive Technologien auch erkennen können, welche Option ausgewählt ist, fügen Sie aria-pressed hinzu und aktualisieren Sie es zusammen mit der active-Klasse.

    Runde Schaltflächen mit Hover-Reaktion

    Der Basistil legt die Größe fest, entfernt das Standardaussehen, zentriert das Icon mit Flexbox und formt die Schaltfläche zu einem Kreis:

    .feedback-btn {
        width: 52px;
        height: 52px;
        border: 1px solid #ddd;
        background: #fff;
        border-radius: 50%;
        cursor: pointer;
        font-size: 25px;
        display: flex;
        align-items: center;
        justify-content: center;
        transition: all 0.25s ease;
    }
    

    border-radius: 50% an einem quadratischen Element erzeugt den Kreis, und transition sorgt für eine sanfte Anpassung späterer Änderungen; das Angben spezifischer Eigenschaften anstelle von all verhindert, dass Dinge animiert werden, die man nicht beabsichtigt hat.

    Eine Hover-Regel hellt den Hintergrund auf und vergrößert die Schaltfläche leicht, damit der Mauszeiger sofort eine Rückmeldung erhält:

    .feedback-btn:hover {
        background: #f5f5f5;
        transform: scale(1.08);
    }
    

    Die Keyframes hinter der Effektanimation

    Der interessante Moment ist der Wechsel vom Daumen nach oben zum funkelnden Smiley. Das wird durch eine @keyframes-Regel namens sparkle gesteuert:

    @keyframes sparkle {
        0% {
            transform: scale(0.4) rotate(-20deg);
            opacity: 0;
        }
        35% {
            transform: scale(1.4) rotate(10deg);
            opacity: 1;
        }
        65% {
            transform: scale(1) rotate(-5deg);
        }
        100% {
            transform: scale(1) rotate(0deg);
        }
    }
    

    Als Zeitlinie: Bei 0 % wird der Inhalt auf 40 % verkleinert, um 20 Grad nach hinten geneigt und unsichtbar gemacht. Bei 35 % erreicht er eine Skalierung von 140 % mit einer leichten Neigung in die entgegengesetzte Richtung und voller Transparenz. Bei 65 % kehrt er zur Normalgröße zurück, wobei es eine geringe Gegenrotation gibt, und bei 100 % befindet er sich in seiner natürlichen Größe und Neigung. Der Überschuss, gefolgt von einer Anpassung, erzeugt das Erscheinungsbild eines „Pop-Effekts“. Beachten Sie, dass diese Regel nur die Bewegung definiert; eine separate .sparkle-Klasse, die dies mit animation: sparkle 0.8s ease forwards umsetzt, findet sich im vollständigen Beispiel am Ende.

    Ablauf der Zustände in JavaScript

    Der Klick-Handler für das Daumen-hoch-Symbol koordiniert den Inhaltstausch, die Animationsklasse sowie den Endzustand:

    thumbsUp.addEventListener("click", function () {
        if (thumbsUp.classList.contains("active")) {
            return;
        }
        thumbsUp.innerHTML = "✨😊✨";
        thumbsUp.classList.add("sparkle");
        setTimeout(function () {
            thumbsUp.innerHTML = "👍";
            thumbsUp.classList.remove("sparkle");
            thumbsUp.classList.add("active");
        }, 900);
    });
    

    Es beginnt mit einer Überprüfung: Wenn der Button bereits die active-Klasse hat, kehrt der Handler zurück, sodass die Animation durch wiederholtes Klicken nicht erneut abgespielt werden kann. Anschließend wird der Inhalt durch das Smiley ersetzt:

    thumbsUp.innerHTML = "✨😊✨";
    

    und es wird die Klasse hinzugefügt, die die Keyframes auslöst:

    thumbsUp.classList.add("sparkle");
    

    Ein setTimeout von 900 Millisekunden, etwas länger als die 0,8 Sekunden dauernde Animation, stellt anschließend das Daumen-hoch-Symbol wieder her, entfernt sparkle und fügt active hinzu:

    thumbsUp.innerHTML = "👍";
    

    Der Inhalt stammt niemals von einer Benutzereingabe, daher ist innerHTML hier sicher, obwohl textContent die Absicht besser ausdrückt.

    Hervorheben der ausgewählten Option

    Die active-Klasse stellt die visuelle Bestätigung dar. Positive Rückmeldungen erhalten einen blassgrünen Hintergrund sowie einen grünen Rand:

    .thumbs-up.active {
        background: #e8f5e9;
        border-color: #4caf50;
    }
    

    Negative Rückmeldung verwendet dasselbe Muster in Rot:

    .thumbs-down.active {
        background: #ffebee;
        border-color: #f44336;
    }
    

    Unterschiedliche Farben zeigen auf einen Blick an, welche Auswahl gespeichert wurde, man sollte sich jedoch nicht allein auf die Farbe verlassen; aria-pressed hilft Benutzern, die sie nicht auseinanderhalten können.

    Aufrechterhaltung der gegenseitigen Ausschließlichkeit der Auswahlmöglichkeiten

    „Daumen nach unten“ verwendet eine einfachere Interaktion ohne Animation. Es schaltet seine eigene active-Klasse ein, löscht den positiven Zustand und setzt das „Daumen nach oben“-Icon bei aktueller Auswahl wieder in seine ursprüngliche Form zurück:

    thumbsDown.addEventListener("click", function () {
        thumbsDown.classList.toggle("active");
        thumbsUp.classList.remove("active");
        if (thumbsDown.classList.contains("active")) {
            thumbsUp.innerHTML = "👍🏻";
        }
    });
    

    Durch das Löschen des anderen Buttons wird verhindert, dass beide Optionen gleichzeitig ausgewählt erscheinen. Es bleibt noch ein Randfall: Wenn ein Benutzer innerhalb des 900-Millisekunden-Fensters zuerst auf „Daumen hoch“ und anschließend auf „Daumen runter“ klickt, tritt dennoch die ausstehende Zeitüberschreitung ein und aktiviert erneut „Daumen hoch“. Speichern Sie die Timer-ID und rufen Sie in dem Handler für „Daumen runter“ clearTimeout auf, um diese Lücke zu schließen. Beachten Sie außerdem, dass ein aktiver „Daumen hoch“ nicht durch erneutes Klicken rückgängig gemacht werden kann, während „Daumen runter“ umschaltet; machen Sie beide Funktionen konsistent.

    Warum sich eine kleine Animation lohnt

    Eine statische Farbänderung signalisiert, dass etwas geschehen ist; eine kurze Animation (Klick, Bewegung, Bestätigung) vermittelt den Eindruck, dass die Benutzeroberfläche reagiert hat. Das ist besonders wichtig für inline-Feedback, bei dem sonst nichts auf der Seite einen Erfolg anzeigt. Es eignet sich für Feedback-Formulare zu Kursen, Bewertungen in FAQs und Wissensbasen, Support-Tools, Produktbewertungen, Umfragen, Dokumentationsseiten, Antworten von KI-Chatsboten sowie interne Tools.

    Behandeln Sie prefers-reduced-motion, indem Sie die Schlüsselframes für Nutzer deaktivieren, die weniger Animation wünschen.

    Senden der Bewertung an einen Backend-Server

    In seiner aktuellen Form ist das Widget rein visuell. In einem echten Produkt muss die Wahl gespeichert werden, und der Ablauf umfasst anschließend eine Anfrage:

    User clicks 👍
           ↓
    Animation plays
           ↓
    Feedback recorded
           ↓
    Database updated
           ↓
    User sees confirmation
    

    Jeder Backend-Server eignet sich – egal ob PHP, Node.js, Python oder etwas anderes. Über den Klick-Handler wird die Bewertung an einen Endpunkt gesendet:

    fetch("/api/feedback", {
        method: "POST",
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify({
            feedback: "positive"
        })
    });
    

    Der Server kann die Seite, den Benutzer, die Antwort, das Zeitstempel und den Feedback-Typ speichern. Überprüfen Sie response.ok, da fetch nur bei Netzwerkfehlern abgelehnt wird, und entscheiden Sie, ob die Animation optimistisch abgespielt wird (schneller, erfordert aber einen Rollback bei einem Speicherfehler) oder erst nach Erfolg.

    Die vollständige Seite

    Hier befindet sich alles in einer einzigen Datei, einschließlich der .sparkle-Klasse, einer skalierten :active-State für den gedrückten Zustand sowie des Handlers für das Daumen-hoch-Symbol, der die Auswahl zum Daumen-runter-Symbol löscht:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Feedback Buttons</title>
    
    <style>
        .feedback {
            display: flex;
            gap: 12px;
            align-items: center;
        }
    
        .feedback-btn {
            width: 52px;
            height: 52px;
            border: 1px solid #ddd;
            background: #fff;
            border-radius: 50%;
            cursor: pointer;
            font-size: 25px;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.25s ease;
        }
    
        .feedback-btn:hover {
            background: #f5f5f5;
            transform: scale(1.08);
        }
    
        .feedback-btn:active {
            transform: scale(0.92);
        }
    
        /* Sparkle animation */
        .sparkle {
            animation: sparkle 0.8s ease forwards;
        }
    
        @keyframes sparkle {
            0% {
                transform: scale(0.4) rotate(-20deg);
                opacity: 0;
            }
    
            35% {
                transform: scale(1.4) rotate(10deg);
                opacity: 1;
            }
    
            65% {
                transform: scale(1) rotate(-5deg);
            }
    
            100% {
                transform: scale(1) rotate(0deg);
            }
        }
    
        /* Filled thumbs up */
        .thumbs-up.active {
            background: #e8f5e9;
            border-color: #4caf50;
        }
    
        .thumbs-down.active {
            background: #ffebee;
            border-color: #f44336;
        }
    </style>
    </head>
    
    <body>
    
    <div class="feedback">
    
        <button
            id="thumbsUp"
            class="feedback-btn thumbs-up"
            aria-label="Thumbs up">
            👍🏻
        </button>
    
        <button
            id="thumbsDown"
            class="feedback-btn thumbs-down"
            aria-label="Thumbs down">
            👎🏻
        </button>
    
    </div>
    
    <script>
    
    const thumbsUp = document.getElementById("thumbsUp");
    const thumbsDown = document.getElementById("thumbsDown");
    
    thumbsUp.addEventListener("click", function () {
    
        // Prevent repeated animation
        if (thumbsUp.classList.contains("active")) {
            return;
        }
    
        // Step 1: Sparkling smiley
        thumbsUp.innerHTML = "✨😊✨";
        thumbsUp.classList.add("sparkle");
    
        // Step 2: Change to filled thumbs up
        setTimeout(function () {
    
            thumbsUp.innerHTML = "👍";
            thumbsUp.classList.remove("sparkle");
            thumbsUp.classList.add("active");
    
        }, 900);
    
        // Remove thumbs down selection
        thumbsDown.classList.remove("active");
    });
    
    thumbsDown.addEventListener("click", function () {
    
        thumbsDown.classList.toggle("active");
    
        // Remove thumbs up selection
        thumbsUp.classList.remove("active");
    
        if (thumbsDown.classList.contains("active")) {
            thumbsUp.innerHTML = "👍🏻";
        }
    });
    
    </script>
    
    </body>
    </html>
    

    Zusammenfassung

    Eine gut durchdachte Feedback-Steuerung benötigt nur HTML, CSS und ein paar Zeilen JavaScript. Die Keyframes sorgen für die Animationseffekte, zeitgesteuerte Klassentausche steuern die Zustände, und das schließlich hervorgehobene Symbol bestätigt die Auswahl.

    • Lassen Sie die Animationlogik im CSS und überlassen Sie JavaScript nur das An- und Ausschalten von Klassen sowie den Inhalt.
  • Überwachen Sie die Zeitüberschreitung, damit schnelle Klicks auf den anderen Button nicht dazu führen, dass beide Optionen aktiv bleiben.
  • Fügen Sie aria-pressed sowie einen Fallback für reduzierte Bewegungen hinzu, damit das Widget weiterhin zugänglich bleibt.
  • Betrachten Sie den Aufruf am Backend als Teil der Interaktion: Behandeln Sie Fehler und entscheiden Sie zwischen optimistischem und bestätigtem Feedback.
  • Der gleiche Ansatz gilt für SVG-Ikonen, Lottie-Animationen, Tonhinweise sowie umfangreichere Workflows, die auf APIs basieren.