W3docs

Interaktive Elemente und Widgets in der Webentwicklung

Barrierefreie Widgets in JavaScript erstellen – Slider, Modals, Tabs und Akkordeons – plus die Canvas API für dynamische Grafiken, mit praxistauglichen Tastaturbeispielen.

Das Erstellen benutzerdefinierter Widgets und die Nutzung von HTML-APIs können die Interaktivität und das Nutzererlebnis Ihrer Webanwendungen erheblich verbessern. Dieser Leitfaden bietet schrittweise Anleitungen zum Aufbau benutzerdefinierter interaktiver Elemente wie Slider, Modals und Tabs und stellt Ihnen HTML5-APIs wie die Canvas API zum Erstellen dynamischer Grafiken vor.

Einführung

Ein Widget ist eine in sich geschlossene interaktive UI-Komponente – ein Slider, ein Modal-Dialog, ein Tab-Bereich, ein Akkordeon –, die der Benutzer bedienen kann, um das Angezeigte zu ändern oder Daten einzugeben. Browser liefern einige Widgets nativ mit (<input type="range">, <dialog>, <details>), aber oft müssen Sie eigene erstellen, wenn Sie benutzerdefiniertes Verhalten, Styling oder Layout benötigen, das die eingebauten Elemente nicht bieten.

Dieser Leitfaden zeigt, wie Sie die drei Widgets erstellen, die Sie am häufigsten benötigen – einen Slider, ein Modal und eine Tab-Leiste –, und stellt dann die Canvas API vor, eine HTML5-Funktion zum Zeichnen dynamischer Grafiken. Jedes Beispiel verknüpft das Verhalten mit dem DOM und der Ereignisbehandlung, daher ist es hilfreich, wenn Sie bereits mit dem Auswählen von Elementen und Browser-Ereignissen vertraut sind.

Natives Widget oder benutzerdefiniertes Widget?

Greifen Sie auf ein natives Element zurück, bevor Sie JavaScript schreiben. Native Widgets sind barrierefrei, per Tastatur bedienbar und formularkompatibel – und sie funktionieren weiter, wenn Ihr Skript nicht geladen werden kann.

BedarfNatives ElementBenutzerdefiniert erstellen, wenn…
Wert aus einem Bereich wählen<input type="range">Sie einen Zwei-Daumen- / nicht-linearen Regler benötigen
Blockierenden Dialog anzeigen<dialog> + showModal()Sie ein vollständig benutzerdefiniertes Layout oder eine Animation benötigen
Einklappbarer Bereich<details> / <summary>Sie eine animierte Akkordeon-Gruppe benötigen
Tabs(kein natives Element)immer benutzerdefiniert – dem ARIA-Tabs-Muster folgen

Das folgende Slider-Beispiel umschließt tatsächlich das native <input type="range">, was der empfohlene Ansatz ist. Modal und Tabs werden von Grund auf erstellt, damit Sie die einzelnen Bestandteile sehen können, aber in der Produktion sollten Sie <dialog> für Modals bevorzugen.

Best Practices

  1. Semantisches HTML verwenden: Stellen Sie sicher, dass Ihre HTML-Struktur aussagekräftig und barrierefrei ist.
  2. Zuständigkeiten trennen: Halten Sie HTML, CSS und JavaScript getrennt, um sauberen und wartbaren Code zu erhalten.
  3. Barrierefreiheit: Stellen Sie sicher, dass interaktive Elemente für alle Benutzer zugänglich sind, einschließlich derer, die Screenreader verwenden.
  4. Performance-Optimierung: Minimieren Sie DOM-Manipulationen und optimieren Sie JavaScript, um reibungslose Interaktionen zu gewährleisten.
  5. Responsives Design: Stellen Sie sicher, dass interaktive Elemente auf verschiedenen Bildschirmgrößen und Geräten gut funktionieren.

Benutzerdefinierte Widgets erstellen

Warnung

Für Produktionsanwendungen sollten Sie zuerst native HTML-Elemente in Betracht ziehen: <dialog> für Modals und <details> / <summary> für einklappbare Inhalte. Diese bieten Ihnen Fokusverwaltung, die Escape-Taste und Tastaturunterstützung ohne Zusatzaufwand.

Benutzerdefinierter Slider

Ein benutzerdefinierter Slider ermöglicht es Benutzern, einen Wert aus einem Bereich auszuwählen. So können Sie einen mit HTML, CSS und JavaScript erstellen.

Beispiel

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Custom Slider</title>
    <style>
        .slider-container {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        #slider {
            width: 200px;
        }
    </style>
</head>
<body>
    <div class="slider-container">
        <input type="range" id="slider" min="0" max="100" value="50" aria-label="Value slider" aria-describedby="slider-value" />
        <span id="slider-value">50</span>
    </div>
    <script>
        document.getElementById('slider').addEventListener('input', function() {
            document.getElementById('slider-value').textContent = this.value;
        });
    </script>
</body>
</html>

Dieses Beispiel erstellt einen einfachen Slider mit einem Bereichs-Input und einem span-Element zur Anzeige des aktuellen Werts. JavaScript aktualisiert den Textinhalt des span, wenn der Slider bewegt wird.

Benutzerdefiniertes Modal

Modals werden verwendet, um Inhalte in einer Überlagerung anzuzeigen. So erstellen Sie ein benutzerdefiniertes Modal.

Beispiel

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Custom Modal</title>
    <style>
        .modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            justify-content: center;
            align-items: center;
        }

        .modal-content {
            background-color: #fff;
            padding: 20px;
            border-radius: 5px;
            text-align: center;
        }

        .close {
            position: absolute;
            top: 10px;
            right: 10px;
            font-size: 20px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <button id="open-modal">Open Modal</button>
    <div id="modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="modal-title" tabindex="-1">
        <div class="modal-content">
            <span id="close-modal" class="close" aria-label="Close modal">&times;</span>
            <h2 id="modal-title">Custom Modal</h2>
            <p>This is a custom modal!</p>
        </div>
    </div>
    <script>
        const modal = document.getElementById('modal');
        const openBtn = document.getElementById('open-modal');
        const closeBtn = document.getElementById('close-modal');

        openBtn.addEventListener('click', () => {
            modal.style.display = 'flex';
            closeBtn.focus();
        });

        closeBtn.addEventListener('click', () => {
            modal.style.display = 'none';
            openBtn.focus();
        });

        window.addEventListener('keydown', (e) => {
            if (modal.style.display === 'flex' && e.key === 'Escape') {
                modal.style.display = 'none';
                openBtn.focus();
            }
        });

        modal.addEventListener('click', (event) => {
            if (event.target === modal) {
                modal.style.display = 'none';
                openBtn.focus();
            }
        });
    </script>
</body>
</html>

Dieses Beispiel zeigt, wie Sie ein Modal erstellen, das per JavaScript geöffnet und geschlossen werden kann. Das Modal zeigt eine Überlagerung und ein Inhaltsfeld an, die durch Klicken einer Schaltfläche, Drücken von Escape oder Klicken auf die Überlagerung geschlossen werden können. Der Fokus wird verwaltet, damit Tastaturbenutzer den Dialog navigieren können.

Benutzerdefinierte Tabs

Tabs ermöglichen es Benutzern, zwischen verschiedenen Inhaltsbereichen zu wechseln. So erstellen Sie benutzerdefinierte Tabs.

Beispiel

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Custom Tabs</title>
    <style>
        .tabs {
            display: flex;
            gap: 10px;
        }

        .tab-button {
            padding: 10px 20px;
            cursor: pointer;
            background-color: #f0f0f0;
            border: 1px solid #ccc;
            border-radius: 5px;
        }

        .tab-button.active {
            background-color: #fff;
            border-bottom: 2px solid #000;
        }

        .tab-content {
            display: none;
            margin-top: 20px;
        }

        .tab-content.active {
            display: block;
        }
    </style>
</head>
<body>
    <div class="tabs" role="tablist">
        <button class="tab-button active" role="tab" aria-selected="true" data-tab="tab1">Tab 1</button>
        <button class="tab-button" role="tab" aria-selected="false" data-tab="tab2">Tab 2</button>
        <button class="tab-button" role="tab" aria-selected="false" data-tab="tab3">Tab 3</button>
    </div>
    <div class="tab-content active" role="tabpanel" aria-labelledby="tab1">
        <p>Content for Tab 1</p>
    </div>
    <div class="tab-content" role="tabpanel" aria-labelledby="tab2">
        <p>Content for Tab 2</p>
    </div>
    <div class="tab-content" role="tabpanel" aria-labelledby="tab3">
        <p>Content for Tab 3</p>
    </div>
    <script>
        // Array.from is important: querySelectorAll returns a NodeList,
        // which has no .indexOf method. We need a real array for the
        // arrow-key navigation below.
        const buttons = Array.from(document.querySelectorAll('.tab-button'));
        const contents = document.querySelectorAll('.tab-content');

        function activateTab(clickedBtn) {
            buttons.forEach(btn => {
                btn.classList.remove('active');
                btn.setAttribute('aria-selected', 'false');
            });
            contents.forEach(content => content.classList.remove('active'));

            clickedBtn.classList.add('active');
            clickedBtn.setAttribute('aria-selected', 'true');
            document.getElementById(clickedBtn.dataset.tab).classList.add('active');
        }

        buttons.forEach(button => {
            button.addEventListener('click', () => activateTab(button));
            button.addEventListener('keydown', (e) => {
                let nextIndex;
                if (e.key === 'ArrowRight') nextIndex = (buttons.indexOf(button) + 1) % buttons.length;
                else if (e.key === 'ArrowLeft') nextIndex = (buttons.indexOf(button) - 1 + buttons.length) % buttons.length;
                else return;
                e.preventDefault();
                buttons[nextIndex].focus();
                activateTab(buttons[nextIndex]);
            });
        });
    </script>
</body>
</html>

Dieses Beispiel erstellt eine Tab-Oberfläche. Ein Klick auf eine Tab-Schaltfläche oder die Verwendung der linken/rechten Pfeiltasten zeigt den entsprechenden Inhalt an und blendet die übrigen aus. Die Pfeiltasten-Behandlung folgt dem WAI-ARIA-Tabs-Muster, das Tastaturbenutzern das Wechseln zwischen Tabs ohne Maus ermöglicht – ein wesentlicher Bestandteil der DOM-Barrierefreiheit.

Akkordeon mit nativem <details>

Nicht jedes einklappbare Widget benötigt JavaScript. Das native <details>-Element bietet Ihnen eine Öffnen/Schließen-Umschaltung, Tastaturunterstützung und die richtigen Semantiken ohne ein einziges Skript. Verwenden Sie es für FAQs und Offenlegungs-Panels.

Beispiel

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>Accordion</title>
</head>
<body>
    <details>
        <summary>What is a widget?</summary>
        <p>A self-contained interactive UI component.</p>
    </details>
    <details>
        <summary>Do I always need JavaScript?</summary>
        <p>No — native elements like this one work without any script.</p>
    </details>
    <script>
        // Optional: react when a panel opens (e.g. lazy-load content).
        document.querySelectorAll('details').forEach((d) => {
            d.addEventListener('toggle', () => {
                console.log(d.open ? 'opened' : 'closed');
            });
        });
    </script>
</body>
</html>

Das toggle-Ereignis wird ausgelöst, wenn der Benutzer einen Bereich erweitert oder einklappt, sodass Sie Inhalte verzögert laden oder Analysen verfolgen können. Greifen Sie auf ein per Skript erstelltes Akkordeon nur zurück, wenn Sie eine Animation oder das Verhalten „immer nur ein Bereich geöffnet" benötigen.

HTML5-APIs verwenden

Einführung in HTML5-APIs

HTML5-APIs bieten leistungsstarke Funktionen, die Webanwendungen verbessern. Eine der vielseitigsten HTML5-APIs ist die Canvas API, die das Erstellen dynamischer Grafiken ermöglicht.

Die Canvas API verwenden

Die Canvas API ermöglicht es Ihnen, Grafiken direkt auf einer Webseite zu zeichnen. Hier ist ein einfaches Beispiel zur Verwendung der Canvas API.

Beispiel

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Canvas API Example</title>
</head>
<body>
    <canvas id="myCanvas" width="400" height="400" style="border:1px solid #000;"></canvas>
    <script>
        const canvas = document.getElementById('myCanvas');
        const ctx = canvas.getContext('2d');

        // Draw a rectangle
        ctx.fillStyle = '#FF0000';
        ctx.fillRect(50, 50, 150, 100);

        // Draw a circle
        ctx.beginPath();
        ctx.arc(200, 200, 40, 0, 2 * Math.PI);
        ctx.fillStyle = '#00FF00';
        ctx.fill();

        // Draw text
        ctx.font = '20px Arial';
        ctx.fillStyle = '#0000FF';
        ctx.fillText('Hello Canvas', 100, 300);
    </script>
</body>
</html>

Dieses Beispiel demonstriert grundlegende Zeichenfunktionen der Canvas API:

  • fillRect(x, y, width, height) zeichnet ein gefülltes Rechteck, dessen obere linke Ecke bei (x, y) liegt.
  • arc(x, y, radius, startAngle, endAngle) fügt einen Kreispfad mit Mittelpunkt bei (x, y) hinzu; Winkel sind in Bogenmaß angegeben, ein vollständiger Kreis entspricht also 0 bis 2 * Math.PI. Sie müssen vorher beginPath() und danach fill() (oder stroke()) aufrufen.
  • fillText(text, x, y) zeichnet Text, wobei (x, y) der Grundlinien-Startpunkt ist, nicht die obere linke Ecke.

Ein häufiger Fallstrick: Setzen Sie fillStyle vor dem Zeichenaufruf, den es beeinflussen soll – der Canvas behält die zuletzt gesetzte Farbe, daher kann es leicht passieren, dass versehentlich eine Farbe für mehrere Formen wiederverwendet wird. Für Animationen löschen Sie den vorherigen Frame mit ctx.clearRect(0, 0, canvas.width, canvas.height) und zeichnen Sie innerhalb von requestAnimationFrame neu. Die Größe des Canvas per CSS statt über die width/height-Attribute festzulegen, streckt die Zeichnung – verwenden Sie immer die Attribute für die Größenangabe.

Info

Stellen Sie stets sicher, dass Ihre interaktiven Elemente barrierefrei sind. Verwenden Sie ARIA-Rollen und -Eigenschaften, semantisches HTML und gewährleisten Sie die Tastaturnavigierbarkeit, um allen Benutzern ein inklusives Erlebnis zu bieten. Dies verbessert nicht nur die Barrierefreiheit, sondern steigert auch die allgemeine Benutzerfreundlichkeit und SEO.

Fazit

Benutzerdefinierte Widgets – Slider, Modals, Tabs, Akkordeons – und HTML5-APIs wie Canvas ermöglichen Ihnen den Aufbau der interaktiven Oberflächen, auf die moderne Web-Apps angewiesen sind. Die wiederkehrende Lektion über alle hinweg ist dieselbe: Beginnen Sie mit einem nativen Element, wenn eines vorhanden ist, fügen Sie dann JavaScript nur für das Verhalten hinzu, das der Browser Ihnen nicht bietet, und lassen Sie niemals Tastatur- und ARIA-Unterstützung außer Acht.

Weitere Informationen finden Sie unter DOM-Manipulationstechniken für die Bausteine dieser Widgets, Ereignisbehandlung im DOM für das Verdrahten von Benutzereingaben und DOM-Performance-Optimierung, um Interaktionen flüssig zu halten.

Übung

Übung
Welche der folgenden Aussagen über interaktive Elemente und Widgets sind korrekt?
Welche der folgenden Aussagen über interaktive Elemente und Widgets sind korrekt?
Was this page helpful?