Willkommen beim WP Wegerl.at 'Lesemodus' + Tastaturnavigation!
Entspanntes Lesen und spannende Artikel warten auf dich.
Entdecke unsere besten Beiträge und genieße den Lesemodus sowie die Tastaturbedienung.
WP Wegerl.at: Einzigartige Designs, optimiert für das Nutzererlebnis.
Keyboard, Tastaturnavigation
smilies.4-user.de

Tastaturnavigation: Fokussierung und Interaktion mit JavaScript

Illustration AnonymAT
Werbung

Der Classic-Editor: Vertraut und zuverlässig –
Ihr bewährter Begleiter.


Erleben Sie den Classic Editor neu!
(Bilder von pixelcreatures)


Viele Nutzer schätzen die vertraute Umgebung des Classic-Editors, die eine einfache und schnelle Bearbeitung ermöglicht.




Werbung

Mit dem Advanced Editor Tools auf das nächste Level –
Mehr Funktionen, mehr Möglichkeiten.


Classic Editor + Advanced Editor Tools
= Ihr Erfolgsrezept


Der Advanced Editor erweitert den Funktionsumfang des Classic-Editors und ermöglicht es, Inhalte noch effektiver zu bearbeiten.




Werbung

Einfach und intuitiv –
Der Classic-Editor für alle.


Classic Editor & Advanced Editor Tools
Erleben Sie es.


Der Classic-Editor zeichnet sich durch Stabilität und Zuverlässigkeit aus, was für professionellen Anwender von Bedeutung ist.




Werbung

Mehr schaffen in weniger Zeit –
Der Advanced Editor für kreative Köpfe.


Optimieren Sie Ihre Bearbeitung:
Advanced Editor Tools


Mit dem Advanced Editor können Designer und
Content Creatoren kreative Ideen umsetzten.





In diesem Beitrag erläutern wir, wie die Tastaturnavigation oder Keyboard Navigation (englisch, in technischen Kontexten oft direkt übernommen) auf einer Webseite durch JavaScript-Lösungen optimiert werden kann. Der Beitrag beginnt mit einem Überblick über die Grundlagen der Tastaturnavigation und deren Bedeutung für die Barrierefreiheit. Anschließend wird detailliert beschrieben, wie ein speziell entwickeltes Script die Fokussierung und Interaktion im Inhalt verbessert und gleichzeitig die Benutzerfreundlichkeit für Tastaturbenutzer gewährleistet.

Der Beitrag bietet sowohl eine theoretische Grundlage als auch praktische Anwendungsbeispiele. Die Betonung liegt auf 'Anwendungsbeispiele', denn eine so komplexe Konfiguration sollte ohnehin maßgeschneidert für jede Website erstellt werden. Sie funktioniert nicht einfach per Copy und Paste.

Einleitung: Überblick über Tastaturnavigation

In den folgenden Abschnitten werden wir die Grundlagen der Tastaturnavigation kennenlernen, ihre praktische Anwendung untersuchen und die Herausforderungen beleuchten, die dabei auftreten können.

Was ist die Tastaturnavigation?

Das Thema Tastaturnavigation und Barrierefreiheit ist in der Webentwicklung und Usability ein sehr wichtiger Aspekt, und es gibt einige Überlegungen, die berücksichtigt werden sollten:

1. Barrierefreiheit und Tastaturnavigation

Tastaturnavigation ist nicht nur für Menschen mit physischen Behinderungen wichtig, sondern auch für verschiedene andere Nutzergruppen:

  • Motorische Einschränkungen: Menschen mit eingeschränkter Handbeweglichkeit oder -koordination können Schwierigkeiten haben, eine Maus zu bedienen.
  • Sehbehinderungen: Personen, die auf Bildschirmleser angewiesen sind, navigieren oft nur mit der Tastatur.
  • Körperliche Einschränkungen: In Situationen, in denen die Verwendung einer Maus nicht möglich ist (z.B. bei bestimmten medizinischen Geräten oder bei der Nutzung von Tablets in bestimmten Positionen), ist Tastaturnavigation essentiell.

2. Maus vs. Tastatur

Es stimmt, dass viele Menschen sowohl Maus als auch Tastatur verwenden können, aber es gibt auch Nutzer, die auf Tastatur oder andere Eingabegeräte angewiesen sind. Die Idee ist nicht unbedingt, die Maus als weniger wichtig zu betrachten, sondern sicherzustellen, dass alle Nutzer eine gleichwertige Erfahrung haben können.

3. Ergonomie und Komfort

  • Ergonomie: Für einige Menschen ist die Tastatur ergonomischer als die Maus, insbesondere bei langen Nutzungszeiten.
  • Multitasking: Tastaturnavigation kann schneller sein, wenn Nutzer zwischen verschiedenen Elementen und Funktionen auf der Webseite hin und her wechseln.

4. Gesetzliche und ethische Anforderungen

  • Barrierefreiheitsgesetze: Viele Länder haben Gesetze und Richtlinien (z.B. WCAG), die besagen, dass Webseiten für alle Benutzer zugänglich sein müssen, einschließlich derjenigen, die auf Tastatur und andere assistive Technologien angewiesen sind. Ab Mitte 2025 ist dies verpflichtend für gewerbliche Websites.
  • Ethische Verantwortung: Es ist wichtig, Webseiten so zu gestalten, dass sie für alle zugänglich sind. Das umfasst auch die Tastaturnavigation, um sicherzustellen, dass keine Benutzer ausgeschlossen werden.

Es ist sowohl die Maus- als auch die Tastaturbedienung zu unterstützen, um eine möglichst breite Nutzerbasis zu erreichen. Tastaturnavigation sollte nicht nur als zusätzliche Funktion betrachtet werden, sondern als integraler Bestandteil einer barrierefreien und benutzerfreundlichen Webgestaltung. Es geht darum, eine inklusivere und zugängliche Erfahrung für alle zu schaffen, unabhängig von ihren Fähigkeiten oder Vorlieben.

Grundprinzipien der Tastaturnavigation

In diesem Abschnitt werden die grundlegenden Prinzipien der Tastaturnavigation vorgestellt. Es wird erläutert, wie Nutzer durch Tastenkombinationen und Navigationselemente effizient durch eine Webseite navigieren können. Anschließend wird ein praktisches Beispiel gegeben, um die Anwendung der Tastaturnavigation zu verdeutlichen.

  • Tabulatortaste (Tab): Mit der Tabulatortaste kann durch die interaktiven Elemente einer Seite navigiert werden, wie z.B. Links, Formulareingabefelder, Buttons und andere steuerbare Elemente. Jedes Mal, wenn die Tabulatortaste gedrückt wird, wird der Fokus auf das nächste interaktive Element verschoben.
  • Shift + Tab: Dies verschiebt den Fokus zurück zum vorherigen interaktiven Element. Diese Kombination wird verwendet, um rückwärts durch die Elemente zu navigieren.
  • Pfeiltasten: Die Pfeiltasten (nach oben und unten) können verwendet werden, um innerhalb eines längeren Textes oder eines geöffneten details– oder summary-Elements zu scrollen oder um durch eine Liste von Optionen in einem Menü oder Dropdown zu navigieren.
  • Leertaste: In der Headerleiste kann die Leertaste verwendet werden, um Buttons zu aktivieren, ähnlich wie die Enter-Taste. Im Content-Bereich dient die Leertaste hauptsächlich dem abschnittsweisen Scrollen durch das Dokument, indem sie den Fokus auf den nächsten Abschnitt verschiebt.
  • Enter-Taste: Die Enter-Taste wird verwendet, um das aktuell fokussierte Element zu aktivieren. Dies kann das Öffnen eines Links, das Betätigen eines Buttons oder das Öffnen bzw. Schließen eines Summary-Elements umfassen. Im Inhaltsbereich erfüllt die erste Betätigung der Enter-Taste die Fokussierung des Elements, während die zweite Betätigung die Aktivierung des fokussierten Elements vornimmt. Diese Funktion ist besonders wichtig für die Navigation und Interaktion auf einer Webseite.
  • Escape-Taste (Esc): Die Escape-Taste dient dazu, eine Aktion oder einen Vorgang abzubrechen. In unerem Fall ist das von Nutzen, um etwa in der Headerzeile eine Fokussierung abzubrechen.

1. Anwendung der Tastaturnavigation

  • Navigation durch die Seite: Drücke die Tabulatortaste, um durch die verschiedenen interaktiven Elemente auf einer Webseite zu wechseln. Die fokussierten Elemente können anhand von visuellem Feedback wie einem Rahmen oder einer Hervorhebung erkannt werden.
  • Interaktion mit Elementen: Wenn sich der Fokus auf einem Element wie einem Button, einem Link oder einem summary-Element befindet, kann dieses durch Drücken der Enter-Taste aktiviert werden. Bei Formularfeldern können Eingaben vorgenommen werden, indem direkt getippt wird.
  • Scrollen mit Pfeiltasten: Bei längeren Seiten oder innerhalb von geöffneten details– oder summary-Elementen können die Pfeiltasten verwendet werden, um durch den Inhalt zu scrollen.
  • Suchfeld aufrufen: Das Suchfled wird mit der Taste '7' geöffnet und mit der Escape-Taste geschlossen.
  • Fokussierungen: Mit der Esc-Taste können Fokussierungen von Links, Elementen aufgehoben und Dialoge geschlossen werden.
  • Verwendung der Leertaste: Nutze die Leertaste in der Headerleiste, um Buttons zu aktivieren. Im Content-Bereich hilft sie beim abschnittsweisen Scrollen durch das Dokument.

2. Beispiel für Tastaturnavigation

  • Webseite besuchen: Beim Öffnen einer Webseite beginnt der Fokus beim ersten fokussierbaren Element.
  • Durch die Seite navigieren: Drücke die Tabulatortaste, um zum nächsten Button oder Eingabefeld zu gelangen. Drücke Shift + Tab, um zum vorherigen Element zurückzukehren.
  • Elemente aktivieren: Wenn der Fokus auf einem Button, Link oder summary-Element liegt, drücke die Enter-Taste, um die Aktion auszuführen oder das Element zu öffnen. Im Inhaltsbereich erfüllt die erste Betätigung der Enter-Taste die Fokussierung des Elements, und die zweite Betätigung aktiviert es.
  • Scrollen innerhalb von Elementen: Verwende die Pfeiltasten, um innerhalb eines fokussierten details– oder summary-Elements zu scrollen, nachdem es mit der Leertaste oder Enter-Taste geöffnet wurde.
  • Suchfeld steuern und Aktionen abbrechen: Verwende die Escape-Taste, um das Suchfeld zu schließen oder eine nicht gewünschte Fokussierung aufzuheben.
  • Verwendung der Leertaste: In der Headerleiste aktiviert die Leertaste Buttons, während sie im Content-Bereich für das abschnittsweise Scrollen verantwortlich ist. Verwende Shift + Leertaste zum abschnittsweisen Scoll nach oben.

Erlebe die Freiheit der Tastaturnavigation –
Einfach, präzise, und so effizient wie nie zuvor.

Herausforderungen der Tastaturnavigation

Die Tastaturnavigation ist eine essentielle Komponente der Web-Benutzererfahrung, besonders für Nutzer, die auf alternative Eingabemethoden angewiesen sind. Doch selbst für viele, die die Maus als primäres Eingabegerät nutzen, bietet die Tastaturnavigation eine schnellere und oft effizientere Möglichkeit, durch Webseiten zu navigieren. Trotz dieser Bedeutung gibt es bei der Umsetzung von Tastaturnavigation einige Herausforderungen, die häufig übersehen werden:

1. Unklare Fokusreihenfolge

Eine der häufigsten Herausforderungen bei der Tastaturnavigation ist die unklare oder unlogische Reihenfolge, in der interaktive Elemente den Tastaturfokus erhalten. Standardmäßig folgt die Fokussierung der Reihenfolge, in der die Elemente im HTML-Dokument erscheinen. Dies kann jedoch zu einer Navigation führen, die für den Benutzer verwirrend oder ineffizient ist – besonders auf komplexen Seiten mit vielen interaktiven Elementen wie Formularen, Menüs und Widgets.

2. Fehlende visuelle Hinweise

Ein weiteres häufiges Problem ist das Fehlen klarer visueller Hinweise, die anzeigen, welches Element aktuell den Fokus hat. Ohne eine sichtbare Hervorhebung des fokussierten Elements können Benutzer schnell die Orientierung verlieren. Dies ist besonders problematisch, wenn Elemente wie Links oder Schaltflächen lediglich durch CSS-Stile hervorgehoben werden, die im Fokuszustand nicht angepasst wurden.

3. Schwierigkeiten bei der Navigation durch dynamische Inhalte

Moderne Webseiten enthalten oft dynamische Inhalte, wie z. B. Dropdown-Menüs, Modal-Fenster oder sich automatisch aktualisierende Inhalte. Diese können die Tastaturnavigation erheblich erschweren, wenn sie nicht sorgfältig implementiert werden. Ohne angemessene Tastatursteuerung und Fokusmanagement kann es für den Benutzer unmöglich werden, auf diese Inhalte zuzugreifen oder sie zu schließen.

4. Nicht standardisierte Tastenkombinationen

Während einige Tastenkombinationen für die Navigation auf Webseiten weit verbreitet sind (z. B. Tabulator für den Fokuswechsel, Enter zum Aktivieren), können nicht standardisierte oder schlecht dokumentierte Tastenkombinationen Benutzer verwirren und frustrieren. Zudem ist es für viele Nutzer schwierig, individuelle Tastenkombinationen zu erlernen und effektiv zu nutzen, wenn sie nicht intuitiv gestaltet sind.

5. Mangelnde Unterstützung für 'Assistive Technologien'

Nicht zuletzt gibt es oft Probleme mit der Unterstützung für assistive Technologien wie Screenreader. Diese Tools sind darauf angewiesen, dass Webseiten eine klare und zugängliche Struktur bieten, die den Fokus und die Navigation korrekt übermitteln. Wenn die Tastaturnavigation nicht ordnungsgemäß implementiert ist, kann dies dazu führen, dass wichtige Inhalte für Nutzer dieser Technologien nicht erreichbar sind.

Hier im Link Startleitfaden für WordPress kannst du die Tastaturnavigation ein wenig testen, um zu sehen, wie sie auf der Website funktioniert. Dort findest du mehrere Links, Embeds, Bilder und sogar ein Tabmenü.

🧡 Vorstellung des Scripts:
Tastaturnavigation und Fokusverwaltung

Die Entwicklung der Tastaturnavigation war nicht einfach, aber in Zusammenarbeit mit ChatGPT haben wir es erneut geschafft, die Tastatursteuerung erfolgreich zu optimieren!

Überblick über das JavaScript

Das vorgestellte Script wurde entwickelt, um die Tastaturnavigation auf Webseiten zu optimieren und die Benutzerfreundlichkeit zu erhöhen, insbesondere im "Above the Fold"-Bereich einer Webseite. Das Script überwacht die Interaktionen der Nutzer und passt die Navigation entsprechend an. Es erkennt, ob der Benutzer sich noch im sichtbaren oberen Bereich der Webseite ("Above the Fold") befindet, und ändert die Navigationslogik, sobald dieser Bereich verlassen wird. Dies stellt sicher, dass die Fokussierung und die Interaktion der Elemente effizient und intuitiv gestaltet sind.

Folgend sind drei JavaScript-Abschnitte aufgeführt, die sich mit folgenden Themen befassen:

  1. Tastaturnavigation für die Headerzeile
  2. Allgemeine Navigation und Fokusverwaltung
  3. Fokussierung und Markierung von EMBEDs

Finden und Fokussieren – Mit der Tastatur sicher ans Ziel!

1. Tastaturnavigation für die Headerzeile

Der erste Teil des Codes widmet sich der Verwaltung der Tastaturnavigation in der Headerzeile der Webseite. Dieser Abschnitt prüft, ob der Benutzer die Tab-Taste oder eine Maustaste verwendet, um den Fokus auf bestimmte Elemente zu setzen.

  • Tastaturnavigation: Ermöglicht die Navigation per Tastatur (Tab, Enter, Leertaste) und setzt den Fokus auf relevante Elemente.
  • Fokusmanagement: Setzt den Fokus bei Bedarf auf spezifische Elemente im Admin-Frontend, insbesondere beim Scrollen.
  • MutationObserver: Überwacht DOM-Änderungen, um den Fokus bei Bedarf anzupassen.

Der Code ist optimiert für Tastaturnavigation und Fokusmanagement auch für WordPress-Admin-Frontends.


Hinweis: Das Script ist möglicherweise nicht für die direkte Verwendung durch Copy und Paste geeignet.

/* === HEADERBEREICH Tastaturnavigation & Fokusverwaltung === */

document.addEventListener('DOMContentLoaded', function() {
    const body = document.body;

    // Erstmalige Tab-Taste-Überprüfung
    function handleFirstTab(event) {
        if (event.key === 'Tab') {
            body.classList.add('keyboard-focused');
            window.removeEventListener('keydown', handleFirstTab);
            window.addEventListener('mousedown', handleMouseDown);
        }
    }

    // Mausklick-Überprüfung nach der Tab-Taste
    function handleMouseDown() {
        body.classList.remove('keyboard-focused');
        window.removeEventListener('mousedown', handleMouseDown);
        window.addEventListener('keydown', handleFirstTab);
    }

    window.addEventListener('keydown', handleFirstTab);

    // Tastaturnavigation für fokussierbare Elemente
    document.querySelectorAll('.focusable').forEach(button => {
        button.addEventListener('keydown', function(event) {
            // Prüfen, ob das fokussierte Element kein Eingabefeld ist
            if (event.key === 'Enter' || event.key === ' ') {
                const tagName = event.target.tagName.toLowerCase();
                if (tagName !== 'input' && tagName !== 'textarea') {
                    event.preventDefault();
                    button.click();
                }
            }
        });
    });

    // Für Admin-Frontend: Fokus auf spezifisches Element setzen, wenn nach oben gescrollt wird
    function focusOnSpecificElement() {
        const firstFocusableElement = document.querySelector('.main-content .focusable');
        if (firstFocusableElement) {
            firstFocusableElement.focus();
        }
    }

    // Für Admin-Frontend: Fokus auf die Admin-Leiste entfernen
    function removeFocusFromAdminBar() {
        const adminBar = document.getElementById('wpadminbar');
        if (adminBar && document.activeElement.closest('#wpadminbar')) {
            document.activeElement.blur();
        }
    }

    // Für Admin-Frontend: Überwachung des Scroll-Events mit Verzögerung
    window.addEventListener('scroll', function() {
        if (window.scrollY === 0) {
            setTimeout(() => {
                removeFocusFromAdminBar();
                focusOnSpecificElement();
            }, 100); // Verzögerung anpassen, falls nötig
        }
    });

    // Für Admin-Frontend: MutationObserver zur Überwachung von DOM-Änderungen
    const observer = new MutationObserver(function() {
        if (window.scrollY === 0) {
            removeFocusFromAdminBar();
            focusOnSpecificElement();
        }
    });

    observer.observe(document.body, { childList: true, subtree: true });

    // Für Admin-Frontend: Initiales Setup
    document.addEventListener('DOMContentLoaded', function() {
        removeFocusFromAdminBar();
        focusOnSpecificElement();
    });
});

/* = Ende HEADERBEREICH Tastaturnavigation & Fokusverwaltung === */

2. Allgemeine Navigation und Fokusverwaltung

Dieser Abschnitt des Codes konzentriert sich auf die allgemeine Navigation und Fokusverwaltung auf der Webseite. Die Implementierung beinhaltet Mechanismen zur Überwachung von Scroll- und Klickereignissen, um den Fokus auf relevante Elemente zu setzen und eine reibungslose Benutzererfahrung sicherzustellen.

  1. Tastaturnavigation und Fokusverwaltung
    • Tastaturnavigation steuern: Das Script überwacht die Tastatureingaben und reagiert speziell auf die Enter-Taste, um das aktive Element im sichtbaren Bereich zu fokussieren oder zu aktivieren. Falls kein passendes Element gefunden wird, wird das erste relevante Element im Inhaltsbereich (#content) fokussiert.
    • Verhinderung von Standardaktionen: Standardaktionen, wie die des Enter-Schlüssels, werden in bestimmten Fällen unterdrückt, um eine benutzerdefinierte Navigation zu ermöglichen.
  2. Scroll-Überwachung mit "Above the Fold"-Logik
    • Erkennen des "Above the Fold"-Status: Das Script überwacht die Scrollposition der Seite, um festzustellen, ob sich der Benutzer im "Above the Fold"-Bereich befindet (der sichtbare obere Bereich der Webseite, ohne Scrollen).
    • Tabindex zurücksetzen: Sobald der Benutzer wieder in den "Above the Fold"-Bereich zurückkehrt, wird der Tabindex auf das erste relevante Element gesetzt, um die Navigation zu erleichtern.
  3. Fokusverwaltung
    • Fokusverlust bei Verlassen des Viewports: Wenn ein fokussiertes Element aus dem sichtbaren Bereich (Viewport) gescrollt wird, entfernt das Script den Fokus von diesem Element.
    • Fokus auf den Headerbereich: Falls der Benutzer auf den Header klickt oder der Fokus dorthin wechselt, wird die Tastaturnavigation pausiert, um unerwünschte Navigation zu verhindern.
  4. Tabindex-Verwaltung
    • Zurücksetzen des Tabindex: Das Script stellt sicher, dass der Tabindex auf das erste relevante Element gesetzt wird, um eine logische und zugängliche Navigation zu gewährleisten.
  5. Escape-Taste Funktionalität
    • Schließen von Suchfeldern: Bei Drücken der Escape-Taste wird das Suchfeld geschlossen, falls es aktiv ist.
    • Entfernen des Fokus: Falls ein Element fokussiert ist, wird der Fokus durch Drücken der Escape-Taste entfernt.
  6. Öffnen der Suche mit der 7-Taste
    • Suche aktivieren: Durch Drücken der 7-Taste wird die Suche geöffnet, indem ein unsichtbares Such-Toggle-Element aktiviert wird.
  7. Viewport-Prüfung
    • Überprüfung, ob ein Element im Viewport ist: Das Script enthält eine Funktion zur Prüfung, ob ein Element sich innerhalb des sichtbaren Bereichs (Viewport) des Browsers befindet, um zu entscheiden, ob es aktiviert oder fokussiert werden kann.

Ziel des Scripts: Das Script ist darauf ausgelegt, die Benutzererfahrung für Tastaturnutzer zu verbessern, indem es sicherstellt, dass relevante Elemente fokussiert und aktiviert werden, und unnötige oder unerwartete Navigationsereignisse vermieden werden. Es sorgt dafür, dass der Fokus der Tastaturnavigation logisch und benutzerfreundlich bleibt, besonders in komplexen Webseitenstrukturen.


Hinweis: Das Script ist möglicherweise nicht für die direkte Verwendung durch Copy und Paste geeignet.

/* === ALLGEMEINE Tastaturnavigation & Fokusverwaltung === */

// Event-Handler für die Enter-Taste zur Verwaltung der Navigation und des Fokus im Dokument.
document.addEventListener('keydown', function(event) {
    const tagName = event.target.tagName.toLowerCase();
    
    if (event.key === 'Enter' && tagName !== 'input' && tagName !== 'textarea') {
        event.preventDefault(); // Verhindert das Standardverhalten der Enter-Taste
        focusNextElementIfAboveOffset(50);
    }
});

// Funktion, um sicherzustellen, dass Elemente oberhalb einer bestimmten Schwelle (z.B. 50px) nicht fokussiert werden.
function focusNextElementIfAboveOffset(offset) {
    const activeElement = document.activeElement;

    if (activeElement && activeElement !== document.body) {
        const elementRect = activeElement.getBoundingClientRect();

        if (elementRect.top < offset) {
            focusNextRelevantElementBelowOffset(offset);
        } else {
            activateElement(activeElement);
        }
    } else {
        focusFirstRelevantElementBelowOffset(offset);
    }
}

// Funktion, um das nächste relevante Element unterhalb der Offset-Schwelle zu fokussieren.
function focusNextRelevantElementBelowOffset(offset) {
    const allFocusableElements = Array.from(document.querySelectorAll('#content summary, #content pre, #content a[href], #content button, #content input, #content textarea')); // Entfernt .overflow-scroll-gradient__scroller
    for (const element of allFocusableElements) {
        const elementRect = element.getBoundingClientRect();

        if (elementRect.top >= offset && isElementInViewport(element)) {
            element.focus({ preventScroll: true });
            return;
        }
    }
}

// Funktion, um das erste relevante Element unterhalb der Offset-Schwelle zu fokussieren.
function focusFirstRelevantElementBelowOffset(offset) {
    const allFocusableElements = Array.from(document.querySelectorAll('#content summary, #content pre, #content a[href], #content button, #content input, #content textarea'));
    for (const element of allFocusableElements) {
        const elementRect = element.getBoundingClientRect();

        if (elementRect.top >= offset && isElementInViewport(element)) {
            element.focus({ preventScroll: true });
            return;
        }
    }
}

// Funktion, um zu überprüfen, ob ein Element im sichtbaren Bereich des Viewports ist.
function isElementInViewport(element) {
    const rect = element.getBoundingClientRect();
    return (
        rect.top >= 0 &&
        rect.left >= 0 &&
        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
        rect.right <= (window.innerWidth || document.documentElement.clientWidth)
    );
}

// Funktion zum Aktivieren eines Elements.
function activateElement(element) {
    element.focus({ preventScroll: true });
}

// Überwachung des Scrollens mit Debouncing und "Above the Fold"-Logik
let aboveTheFold = true;
let navigationPaused = false;
let lastScrollY = 0;
let scrollTimeout;
const headerHeight = 50;

// Überwachung des Scrollens
window.addEventListener('scroll', function() {
    const currentScrollY = window.scrollY;

    if (Math.abs(currentScrollY - lastScrollY) < 10) return;

    clearTimeout(scrollTimeout);
    scrollTimeout = setTimeout(function() {
        const foldBoundary = window.innerHeight * 0.5;
        const activeElement = document.activeElement;

        if (window.scrollY > foldBoundary) {
            aboveTheFold = false;
        } else {
            if (!aboveTheFold) {
                resetTabindex();
            }
            aboveTheFold = true;
        }

        if (activeElement && !isElementInViewport(activeElement)) {
            activeElement.blur();
        }

        if (activeElement) {
            const rect = activeElement.getBoundingClientRect();
            const viewportThreshold = 100;

            if (rect.top < headerHeight || rect.top < viewportThreshold) {
                activeElement.blur();
            }
        }

        lastScrollY = currentScrollY;
    }, 100);
});

// Überwachung des Fokus-Wechsels außerhalb des Headerbereichs
document.addEventListener('focusout', function(event) {
    const headerElement = document.querySelector('#masthead') || document.querySelector('.header-main');
    if (headerElement && headerElement.contains(event.target)) {
        navigationPaused = false;
    }
});

// Funktion zum Zurücksetzen des Tabindex
function resetTabindex() {
    const firstFocusableElement = document.querySelector('a, button, input, textarea, select, [tabindex]:not([tabindex="-1"])');
    if (firstFocusableElement) {
        firstFocusableElement.focus();
    }
}

/* = Ende ALLGEMEINE Tastaturnavigation & Fokusverwaltung = */

Bereit für Anpassungen? Profis wissen:
Vor dem Erfolg gilt es, auf alle Aspekte vorbereitet zu sein!

3. Fokussierung und Markierung von EMBEDs

Im Folgenden sprechen wir über die WordPress-Embeds, die durch das Einfügen eines Links in eine separate Zeile automatisch visuell dargestellt werden. Grundsätzlich handelt es sich dabei um 'iframes', die jedoch nicht mit herkömmlichen 'iframes' zu verwechseln sind.

Um die Barrierefreiheit und Benutzerfreundlichkeit zu verbessern, haben wir ein Skript entwickelt, das iframes so behandelt, als wären sie anklickbare Links. Dies ermöglicht eine einfache Navigation und Fokusverwaltung über die Tastatur.

Funktionsweise

Unser Skript "EMBED Iframe-Link-Navigation & Fokusverwaltung" transformiert eingebettete Inhalte (iframes) in fokussierbare und anklickbare Links. Dies geschieht, indem jedem iframe eine HTML-Verlinkung hinzugefügt und ein tabIndex gesetzt wird. Diese einfache, aber wirkungsvolle Lösung stellt sicher, dass Nutzer eingebettete Inhalte direkt mit der Tastatur erreichen können, ohne auf die Maus angewiesen zu sein.

Darüber hinaus wird über CSS eine optische Rückmeldung eingebaut, die signalisiert, dass der iframe über die Tab-Taste fokussiert werden kann. Diese auch Benachrichtigung sorgt für eine klare visuelle Rückmeldung und verbessert das Benutzererlebnis.

  1. Barrierefreiheit:
    • Das Skript ermöglicht es, dass eingebettete Inhalte, die in der Regel nicht leicht über die Tastatur erreichbar sind, mit einem tabIndex und einer Fokusmarkierung versehen werden. Dies bedeutet, dass Nutzer die Inhalte mit der Tab-Taste durchgehen und direkt fokussieren können.
  2. Tastaturnavigation:
    • Jedes iframe wird wie ein anklickbarer Link behandelt, was bedeutet, dass man mit der Enter-Taste direkt auf den Inhalt zugreifen kann. Das verbessert die Interaktion für Tastaturnutzer erheblich und entspricht den Anforderungen an zugängliche Webseiten.
  3. Visuelles Feedback:
    • Das visuelle Feedback wird vollständig durch CSS gesteuert. Eine dezente Nachricht, die über der eingebetteten Datei angezeigt wird, informiert den Nutzer darüber, dass der Inhalt mit der Tab-Taste fokussiert werden kann. Diese Nachricht ist besonders hilfreich für Nutzer, die sich nicht sicher sind, wie sie den Inhalt per Tastatur steuern können.
  4. Einfacher Einsatz:
    • Das Skript kann unkompliziert in bestehende Projekte integriert werden. Es fügt keine zusätzliche Komplexität hinzu und funktioniert mit bereits eingebundenen iframes.

Technische Details

Das Skript verwendet einfaches JavaScript, um alle iframe-Elemente mit der Klasse .wp-embedded-content auszuwählen und in anklickbare Links zu verwandeln. Es wird jedem iframe ein Wrapper (a-Tag) hinzugefügt, der die URL des iframes als Ziel hat. Der tabIndex wird gesetzt, um die Tastaturnavigation zu aktivieren.

Folgend ist der Code des Skripts, das für die Tastaturnavigation und Fokusverwaltung sorgt, darunter ist ein CSS-Vorschlag und dann unser CSS-Beispiel.


Hinweis: Das Script ist möglicherweise nicht für die direkte Verwendung durch Copy und Paste geeignet.

iframe-embed-link-focus-control_v1.js

/**
 * -----------------------------------------------------------------------------
 * Scriptname: Iframe-Embed-Link-Navigation & Fokusverwaltung
 * Version:    1.0
 * Datum:      2024-09-14
 * Autor:      [Team Wegerl.at]
 * -----------------------------------------------------------------------------
 *
 * Beschreibung:
 * Dieses Skript behandelt eingebettete Inhalte (iframes/Embed) so, als wären sie
 * anklickbare Links. Es ermöglicht die Tastaturnavigation und Fokusverwaltung 
 * für Embeds, indem ein tabIndex hinzugefügt wird.
 * Das Styling, das dem Nutzer zeigt, dass die Inhalte mit der Tab-Taste 
 * fokussiert werden können, wird durch CSS gesteuert und angepasst.
 * 
 * Funktionen:
 * - Wandelt iframes in anklickbare Links um, sodass sie per Tastatur fokussierbar sind.
 * - Fügt Tastaturnavigation und Fokusverwaltung hinzu.
 * - CSS-basierte Benachrichtigung für den Nutzer über die Tab-Taste zur Fokussierung.
 * - Unterstützung für Barrierefreiheit durch tabIndex und visuelles Feedback.
 * 
 * -----------------------------------------------------------------------------
 */

/* === EMBED Iframe-Link-Navigation & Fokusverwaltung === */

// Funktion, um iframes wie Links zu behandeln
function makeIframesFocusable() {
    const iframes = document.querySelectorAll('iframe.wp-embedded-content'); // Selektiert alle iframes mit der Klasse wp-embedded-content

    iframes.forEach(iframe => {
        // Erstelle einen Wrapper-Link um das iframe
        const link = document.createElement('a');
        link.href = iframe.src; // Setzt die URL des iframes als href
        link.tabIndex = 0; // Macht den Link fokussierbar
        link.className = 'iframe-link'; // Füge eine Klasse für weiteres Styling hinzu

        // Füge den Link vor dem iframe ein und verschiebe das iframe in den Link
        iframe.parentNode.insertBefore(link, iframe);
        link.appendChild(iframe);

        // Optional: Event Listener für die Enter-Taste, um den Link zu aktivieren
        link.addEventListener('keydown', (event) => {
            if (event.key === 'Enter') {
                window.location.href = link.href; // Weiterleitung bei Enter
            }
        });
    });
}

// Funktion aufrufen, um iframes wie Links zu behandeln
makeIframesFocusable();


/* = Ende EMBED Iframe-Link-Navigation & Fokusverwaltung = */

Diese Scripts verbessern die Zugänglichkeit und Benutzerfreundlichkeit von Webseiten erheblich, indem sie sicherstellen, dass die Navigation und die Aktivierung von Elementen sowohl für Maus- als auch für Tastaturnutzer nahtlos funktionieren.

CSS-Vorschlag

Ein weiteres Feature ist die Einbindung einer CSS-Nachricht, die durch ein ::after Pseudo-Element dargestellt wird. Diese Nachricht erscheint beim Fokus und informiert den Nutzer, dass er mit der Tab-Taste den eingebetteten Inhalt ansteuern kann.

/* --- Voschlag 1: EMBEDS Link-Navigation-Focus. Der Hinweis "Fokussiere mit Tab" steht oben --- */
.iframe-link {
    display: inline-block;
    position: relative;
}

.iframe-link:focus {
    outline: 3px solid #007acc !important;
}

.iframe-link:focus::after {
    content: "Fokussiere mit Tab";
    color: #007acc;
    font-weight: bold;
    position: absolute;
    left: 10%;
    top: -23px;
    background-color: #f0f0f0;
    padding: 5px;
    z-index: 1;
}

.wp-embedded-content {
    margin-bottom: -10px;
}

/* - Ende Vorschlag 1: EMBEDS Link-Navigation-Focus. Der Hinweis "Fokussiere mit Tab" steht oben - */

/* --- Vorschlag 2: EMBEDS Link-Navigation-Focus. Der Hinweis "Fokussiere mit Tab" steht unten --- */
.iframe-link {
    /*display: inline-block;*/
    position: relative;
}
.iframe-link:focus {
    outline: 3px solid #007acc !important;
}
.iframe-link:focus::after {
    content: "Fokussiere mit Tab";
    color: #007acc;
    font-weight: bold;
    position: absolute;
    left: 10%;
    top: 10px;
    background-color: #f0f0f0;
    padding: 5px;
    z-index: 1;
}
.wp-embedded-content {
    margin-bottom: -10px;
}

/* - Ende Vorschlag 2: EMBEDS Link-Navigation-Focus. Der Hinweis "Fokussiere mit Tab" steht unten - */
  • Hinweis: Durch die Verwendung von display: inline-block; kann gesteuert werden, ob der Hinweis "Fokussiere mit Tab" oben oder unten angezeigt wird. In diesem Zusammenhang ist das Styling mit ::before wirkungslos.

Das folgende Embed als Beispiel: Die Enter-Taste betätigen, um das Embed zu fokussieren. Durch weiteres Drücken der Tab-Taste werden die Links im Embed nacheinander fokussiert. Letzteres geschieht automatisch im Embed. Zunächst geht es darum, die erste Fokussierung zu sehen, um sicherzustellen, dass das Embed fokussiert werden kann.

  • Hinweis: Es gibt bekannte Einschränkungen bei der Fokussierbarkeit von iframe-Elementen, insbesondere wenn sie nur teilweise im Viewport sichtbar sind. Technische Versuche, iframes durch Scrollen oder Overlays fokussierbar zu machen, waren nicht erfolgreich oder scheitern an browserseitigen Sicherheitsmechanismen. Das iframe ist jedoch immer fokussierbar, wenn der untere Teil vollständig im Viewport sichtbar ist, auch wenn der obere Teil außerhalb des sichtbaren Bereichs liegt.

Tastaturnavigation: Fokussierung und Interaktion mit JavaScript

Unser CSS ist ein weiteres Beispiel:

/* --- EMBEDS Link-Navigation-Focus --- */

.iframe-link {
    /* display: inline-block; */
    margin-left: 15px !important;
    position: relative;
}

.iframe-link:focus {
    outline: 3px solid #fd8826 !important;
}

.iframe-link:focus::after {
    content: "Fokussiere mit Tab";
    color: #fd8826;
    font-weight: bold;
    position: absolute;
    left: 10%;
    top: 15px;
    background-color: white;
    padding: 5px;
    z-index: 1;
}

.wp-embedded-content {
    margin-bottom: -15px;
}

@media all and (min-width: 700px) {
    .readermode .iframe-link {
        margin-left: 14.6% !important;
        position: relative;
    }
}

/* - Ende EMBEDS Link-Navigation-Focus - */

➡︎ Tastaturnavigation auf der Website

Diese JavaScript-Lösungen sind Erweiterungen der vorherigen Vorschläge. Es ist nicht anders, nur einige Teile des Scripts bieten möglicherweise mehr Funktionen, als normalerweise benötigt werden, und können bei Bedarf problemlos entfernt werden – mit gewissen Einschränkungen. ChatGPT kann dabei jederzeit unterstützen, und das grundlegende Script ist bereits vorhanden.

HEADER und ALLGEMEINE Tastaturnavigation und Fokusverwaltung

Dieses Script erweitert die Tastaturnavigation auf unserer Website. Es enthält unter anderem Anpassungen, wie die Möglichkeit, die Inhalte von Boxzilla-Pop-up zu fokussieren. Auch grundlegende Funktionen, die in Verbindung mit Night Eye stehen und anders sind integriert.


Hinweis: Das Script ist möglicherweise nicht für die direkte Verwendung durch Copy und Paste geeignet.

tastaturnavigation-fokusverwaltung_v3.js

/**
 * -----------------------------------------------------------------------------
 * Scriptname: Tastaturnavigation und Fokusverwaltung
 * Version:    3.0
 * Datum:      2024-09-12
 * Autor:      [Team WP Wegerl]
 * -----------------------------------------------------------------------------
 * Beschreibung:
 * Dieses Script bietet umfassende Tastaturnavigation und Fokusverwaltung für die gesamte Seite, einschließlich der Headerzeile, Seitenleisten und Fußleisten.
 * Es enthält erweiterte Funktionen für die Navigation und Interaktion mittels Tastatur, sowie Anpassungen für spezielle Bereiche wie den Nachtmodus und die Sidebar.
 *
 * Hauptfunktionen im Überblick:
 *
 * - **Tastaturnavigation für Headerzeile:**
 *   - Ermöglicht das Fokussieren und Navigieren durch Header-Elemente mit der Tastatur.
 *   - Verhindert das Entfernen der Tastaturfokus-Klasse bei Nutzung der Maus.
 *   - Unterstützt das Fokussieren und Aktivieren von spezifischen Header-Elementen.
 *
 * - **Tastaturnavigation für Seitenleisten und Fußleisten:**
 *   - Erweiterte Navigation für die Bereiche '#secondary', '#content-sidebar', '#footer-sidebar' und '#colophon'.
 *   - Aktiviert fokussierte Elemente in diesen Bereichen durch die Enter-Taste.
 *
 * - **Toggle-Button für NightEye:**
 *   - Konfiguriert den Toggle-Button für den Nachtmodus, um ihn per Tastatursteuerung (Enter-Taste) zu bedienen.
 *   - Öffnet das Dialogfeld für NightEye bei Klick und ermöglicht die Tastaturbedienung.
 *
 * - **Scroll- und Fokusmanagement:**
 *   - Setzt den Fokus auf ein spezifisches Element, wenn der Benutzer nach oben scrollt.
 *   - Entfernt den Fokus von der Admin-Leiste, wenn der Fokus dorthin verschoben wird.
 *   - Verhindert das Fokussieren auf Elemente außerhalb des Sichtbereichs.
 *
 * - **Allgemeine Navigation und Interaktionen:**
 *   - Ermöglicht die Steuerung der Sichtbarkeit und Aktivierung von Elementen über die Tastatur (Enter- oder Space-Taste).
 *   - Verwaltet Popup-Fenster und die Sichtbarkeit der TOC (Table of Contents) durch Tasteneingaben.
 *   - Schließt Dialoge und Suchfelder bei Escape-Taste und verwaltet den Fokus.
 *
 * - **Erweiterte Navigation für Seitenleisten:**
 *   - Berücksichtigt spezifische Bereiche wie '#secondary', '#content-sidebar', '#footer-sidebar' und '#colophon' für Tastaturnavigation.
 *   - Aktiviert fokussierte Elemente in diesen Bereichen mit der Enter-Taste.
 *
 * - **MutationObserver:**
 *   - Überwacht DOM-Änderungen und passt die Sichtbarkeit und den Fokus von Elementen entsprechend an.
 *
 * - **Event-Handling für Tastatureingaben:**
 *   - Verarbeitet spezifische Tastatureingaben für Navigation und Interaktionen innerhalb der Seite.
 *
 * - **Touch- und Mausinteraktionen:**
 *   - Verarbeitet spezifische Maus- und Touch-Ereignisse zur Verbesserung der Benutzererfahrung.
 */

/* === HEADERBEREICH Tastaturnavigation & Fokusverwaltung === */

document.addEventListener('DOMContentLoaded', function() {
    const body = document.body;
    let toggleButtonSetupDone = false;

    // Erstmalige Tab-Taste-Überprüfung
    function handleFirstTab(event) {
        if (event.key === 'Tab') {
            body.classList.add('keyboard-focused');
            window.removeEventListener('keydown', handleFirstTab);
            window.addEventListener('mousedown', handleMouseDown);
        }
    }

    // Mausklick-Überprüfung nach der Tab-Taste
    function handleMouseDown() {
        body.classList.remove('keyboard-focused');
        window.removeEventListener('mousedown', handleMouseDown);
        window.addEventListener('keydown', handleFirstTab);
    }

    window.addEventListener('keydown', handleFirstTab);

    // Tastaturnavigation für fokussierbare Elemente
    document.querySelectorAll('.focusable').forEach(button => {
        button.addEventListener('keydown', function(event) {
            // Prüfen, ob das fokussierte Element kein Eingabefeld ist
            if (event.key === 'Enter' || event.key === ' ') {
                const tagName = event.target.tagName.toLowerCase();
                if (tagName !== 'input' && tagName !== 'textarea') {
                    event.preventDefault();
                    button.click();
                }
            }
        });
    });

    // Setup für den NightEye-Toggle-Button
    function setupToggleButton() {
        if (toggleButtonSetupDone) return;
        toggleButtonSetupDone = true;

        const toggleCheckbox = document.querySelector('.NightEyeToggleButton input[type="checkbox"]');
        if (toggleCheckbox) {
            toggleCheckbox.setAttribute('tabindex', '0');
            toggleCheckbox.focus();

            toggleCheckbox.addEventListener('keydown', function(event) {
                if (event.key === 'Enter') {
                    event.preventDefault();
                    event.stopPropagation();
                    toggleCheckbox.checked = !toggleCheckbox.checked;
                    toggleCheckbox.dispatchEvent(new Event('change', { bubbles: true }));
                }
            });
        }
    }

    // Listener für das Öffnen des NightEye-Dialogs
    function addDialogOpenListener() {
        const nightEyeWidget = document.querySelector('.NightEyeWidget');
        if (nightEyeWidget) {
            nightEyeWidget.addEventListener('click', function() {
                setupToggleButton();
            });
        }
    }

    addDialogOpenListener();

    // Hier fügen wir den Code für die overflow-scroll-gradient__scroller-Elemente hinzu
    const scrollers = document.querySelectorAll('.overflow-scroll-gradient__scroller');
    scrollers.forEach(scroller => {
        scroller.setAttribute('tabindex', '0');
    });

    // Für Admin-Frontend: Fokus auf spezifisches Element setzen, wenn nach oben gescrollt wird
    function focusOnSpecificElement() {
        const firstFocusableElement = document.querySelector('.main-content .focusable');
        if (firstFocusableElement) {
            firstFocusableElement.focus();
        }
    }

    // Für Admin-Frontend: Fokus auf die Admin-Leiste entfernen
    function removeFocusFromAdminBar() {
        const adminBar = document.getElementById('wpadminbar');
        if (adminBar && document.activeElement.closest('#wpadminbar')) {
            document.activeElement.blur();
        }
    }

    // Für Admin-Frontend: Überwachung des Scroll-Events mit Verzögerung
    window.addEventListener('scroll', function() {
        if (window.scrollY === 0) {
            setTimeout(() => {
                removeFocusFromAdminBar();
                focusOnSpecificElement();
            }, 100); // Verzögerung anpassen, falls nötig
        }
    });

    // Für Admin-Frontend: MutationObserver zur Überwachung von DOM-Änderungen
    const observer = new MutationObserver(function() {
        if (window.scrollY === 0) {
            removeFocusFromAdminBar();
            focusOnSpecificElement();
        }
    });

    observer.observe(document.body, { childList: true, subtree: true });

    // Für Admin-Frontend: Initiales Setup
    document.addEventListener('DOMContentLoaded', function() {
        removeFocusFromAdminBar();
        focusOnSpecificElement();
    });
});

/* = Ende HEADERBEREICH Tastaturnavigation & Fokusverwaltung === */

/* === ALLGEMEINE Tastaturnavigation & Fokusverwaltung === */

// Event-Handler für die Enter-Taste zur Verwaltung der Navigation und des Fokus im Dokument.
document.addEventListener('keydown', function(event) {
    // Überprüfen, ob der Fokus sich nicht auf einem Eingabe- oder Textbereichsfeld befindet
    const tagName = event.target.tagName.toLowerCase();
    
    if (event.key === 'Enter' && tagName !== 'input' && tagName !== 'textarea') {
        event.preventDefault(); // Verhindert das Standardverhalten der Enter-Taste

        // Rufe die Funktion zur Fokussierung auf das nächste Element auf, wenn der aktive Link oberhalb von 50px liegt
        focusNextElementIfAboveOffset(50);
    }
});

// Funktion, um sicherzustellen, dass Elemente oberhalb einer bestimmten Schwelle (z.B. 50px) nicht fokussiert werden.
function focusNextElementIfAboveOffset(offset) {
    const activeElement = document.activeElement;

    if (activeElement && activeElement !== document.body) {
        const elementRect = activeElement.getBoundingClientRect();

        // Überprüfen, ob das aktive Element zu nah am oberen Rand ist (oberhalb von 50px)
        if (elementRect.top < offset) {
            // Fokus auf das nächste relevante Element unterhalb der Offset-Schwelle
            focusNextRelevantElementBelowOffset(offset);
        } else {
            // Wenn das Element unterhalb des Offsets ist, bleibt der Fokus auf dem aktuellen Element
            activateElement(activeElement);
        }
    } else {
        // Falls kein aktives Element vorhanden ist, setze den Fokus auf das erste Element im sichtbaren Bereich
        focusFirstRelevantElementBelowOffset(offset);
    }
}

// Funktion, um das nächste relevante Element unterhalb der Offset-Schwelle zu fokussieren.
function focusNextRelevantElementBelowOffset(offset) {
    const allFocusableElements = Array.from(document.querySelectorAll('#content summary, #content pre, #content a[href], #content button, #content input, #content textarea, .overflow-scroll-gradient__scroller')); // Erweitere hier die Selektoren nach Bedarf
    for (const element of allFocusableElements) {
        const elementRect = element.getBoundingClientRect();

        // Fokus auf das erste Element, das sich unterhalb des Offsets (50px) befindet und im sichtbaren Bereich ist
        if (elementRect.top >= offset && isElementInViewport(element)) {
            element.focus({ preventScroll: true });
            return;
        }
    }
}


//Funktion, um das erste relevante Element unterhalb der Offset-Schwelle zu fokussieren.
function focusFirstRelevantElementBelowOffset(offset) {
    const allFocusableElements = Array.from(document.querySelectorAll('#content summary, #content pre, #content a[href], #content button, #content input, #content textarea, .overflow-scroll-gradient__scroller')); // Erweitere hier die Selektoren nach Bedarf
    for (const element of allFocusableElements) {
        const elementRect = element.getBoundingClientRect();

        // Fokus auf das erste Element, das sich unterhalb des Offsets (50px) befindet und im sichtbaren Bereich ist
        if (elementRect.top >= offset && isElementInViewport(element)) {
            element.focus({ preventScroll: true });
            return;
        }
    }
}

// Funktion, um zu überprüfen, ob ein Element im sichtbaren Bereich des Viewports ist.
function isElementInViewport(element) {
    const rect = element.getBoundingClientRect();
    return (
        rect.top >= 0 &&
        rect.left >= 0 &&
        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
        rect.right <= (window.innerWidth || document.documentElement.clientWidth)
    );
}

// Funktion zum Aktivieren eines Elements.
function activateElement(element) {
    element.focus({ preventScroll: true });
}

// Überwachung des Scrollens mit Debouncing und "Above the Fold"-Logik
let aboveTheFold = true; // Zustand, ob wir uns im "Above the Fold"-Bereich befinden
let navigationPaused = false; // Zustand, ob die Navigation pausiert ist
let lastScrollY = 0; // Variable für die letzte Scroll-Position
let scrollTimeout;
const headerHeight = 50; // Höhe der Headerleiste in Pixeln

// Überwachung des Scrollens
window.addEventListener('scroll', function() {
    const currentScrollY = window.scrollY;

    if (Math.abs(currentScrollY - lastScrollY) < 10) return; // Wenn die Scroll-Änderung zu klein ist, überspringe

    clearTimeout(scrollTimeout);
    scrollTimeout = setTimeout(function() {
        const foldBoundary = window.innerHeight * 0.5; // Definition von "Above the Fold"
        const activeElement = document.activeElement;

        if (window.scrollY > foldBoundary) {
            aboveTheFold = false; // Benutzer hat den "Above the Fold"-Bereich verlassen
        } else {
            if (!aboveTheFold) { // Nur zurücksetzen, wenn wir gerade erst in den "Above the Fold"-Bereich gescrollt haben
                resetTabindex(); // Setzt den Tabindex zurück
            }
            aboveTheFold = true; // Benutzer ist wieder im "Above the Fold"-Bereich
        }

        // Entferne den Fokus, wenn das aktive Element nicht mehr im Viewport ist
        if (activeElement && !isElementInViewport(activeElement)) {
            activeElement.blur();
        }

        // NEUE LOGIK: Fokus entfernen, wenn das aktive Element hinter der Headerleiste liegt
        if (activeElement) {
            const rect = activeElement.getBoundingClientRect();
            const viewportThreshold = 100; // Optionaler Abstand in Pixeln vom oberen Rand

            // Wenn das Element hinter der Headerleiste liegt oder sich dem oberen Rand nähert
            if (rect.top < headerHeight || rect.top < viewportThreshold) {
                activeElement.blur(); // Fokussierung entfernen
            }
        }

        lastScrollY = currentScrollY; // Update lastScrollY after processing
    }, 100); // Timeout nach 100ms Inaktivität
});

// Überwachung des Klicks auf die Headerzeile
const headerElement = document.querySelector('#masthead') || document.querySelector('.header-main');
if (headerElement) {
    headerElement.addEventListener('click', function() {
        navigationPaused = true; // Pausiert die Tastaturnavigation
    });
}

// Überwachung des Fokus-Wechsels im Headerbereich
document.addEventListener('focusin', function(event) {
    if (headerElement && headerElement.contains(event.target)) {
        navigationPaused = true; // Pausiert die Tastaturnavigation, wenn der Fokus im Headerbereich liegt
    }
});

// Überwachung des Fokus-Wechsels außerhalb des Headerbereichs
document.addEventListener('focusout', function(event) {
    if (headerElement && headerElement.contains(event.target)) {
        navigationPaused = false; // Reaktiviert die Tastaturnavigation, wenn der Fokus den Headerbereich verlässt
    }
});

// Funktion zum Zurücksetzen des Tabindex
function resetTabindex() {
    const firstFocusableElement = document.querySelector('a, button, input, textarea, select, [tabindex]:not([tabindex="-1"])');
    if (firstFocusableElement) {
        firstFocusableElement.focus();
    }
}

// Variable zum Verfolgen des aktuell fokussierten Pop-ups
let lastFocusedPopup = null;

// Funktion zum Fokussieren des neuesten sichtbaren Boxzilla-Pop-ups
function focusBoxzillaPopups() {
    // Alle sichtbaren Boxzilla-Pop-ups auswählen
    const popups = document.querySelectorAll('.boxzilla:not([style*="display: none"])');

    // Fokus nur auf das neueste Pop-up setzen
    let focusedAnyPopup = false;
    popups.forEach(popup => {
        const focusableElements = popup.querySelectorAll('a, button, input, textarea, select, [tabindex]:not([tabindex="-1"])');
        if (focusableElements.length > 0) {
            if (popup !== lastFocusedPopup) {
                // Setzt den Fokus auf das erste fokussierbare Element
                const firstFocusableElement = focusableElements[0];
                firstFocusableElement.focus();

                // Scrollen, um sicherzustellen, dass das Pop-up sichtbar ist
                if (popup.scrollIntoViewIfNeeded) {
                    popup.scrollIntoViewIfNeeded(true);
                } else {
                    popup.scrollIntoView({ behavior: 'smooth', block: 'start' });
                }

                // Setze lastFocusedPopup auf das aktuelle Pop-up
                lastFocusedPopup = popup;
                focusedAnyPopup = true;
            }
        }
    });

    return focusedAnyPopup; // Gibt zurück, ob mindestens ein Pop-up fokussiert wurde
}

// Funktion zur Überwachung von Pop-up-Änderungen
function setupPopupMonitoring() {
    const observer = new MutationObserver(() => {
        // Verzögerung hinzufügen, um sicherzustellen, dass das Pop-up vollständig gerendert ist
        setTimeout(() => {
            focusBoxzillaPopups();
        }, 100); // Verzögerung anpassen, falls nötig
    });

    // Beobachte Änderungen im DOM
    observer.observe(document.body, { childList: true, subtree: true });

    // Initiales Fokussieren beim Laden der Seite
    setTimeout(() => {
        focusBoxzillaPopups();
    }, 100); // Verzögerung anpassen, falls nötig
}

// Starte die Überwachung der Pop-ups
setupPopupMonitoring();

// Funktion zum Fokussieren des ersten relevanten Elements im Inhaltsbereich
function focusFirstRelevantElement() {
    const focusableElements = '#content summary, #content pre, #content iframe, #content embed, #content a[href], #content button, #content input, #content textarea, #content select, .overflow-scroll-gradient__scroller, #content [tabindex]:not([tabindex="-1"])';
    const elements = Array.from(document.querySelectorAll(focusableElements));

    // Priorisiere das Fokussieren von EMBED- und IFRAME-Elementen, wenn sie sichtbar sind
    const firstRelevantElement = elements.find(el => 
        isElementInViewport(el) &&
        (['IFRAME', 'EMBED'].includes(el.tagName) || !isBlockedByEmbed(el))
    );

    if (firstRelevantElement) {
        // Eventuelle Besonderheiten für Firefox beim Fokussieren von `iframe` oder `embed`
        if (firstRelevantElement.tagName === 'IFRAME' || firstRelevantElement.tagName === 'EMBED') {
            // Fallback-Logik für Firefox
            setTimeout(() => firstRelevantElement.focus(), 100);
        } else {
            firstRelevantElement.focus();
        }
    }
}

// Funktion zum Aktivieren eines Elements
function activateElement(element) {
    if (typeof element.click === 'function') {
        element.click();
    }
}

// Funktion zum Überprüfen, ob ein Element im Viewport ist
function isElementInViewport(el) {
    const rect = el.getBoundingClientRect();
    return (
        rect.bottom > 0 &&
        rect.top < window.innerHeight &&
        rect.right > 0 &&
        rect.left < window.innerWidth
    );
}

// Funktion zum Überprüfen, ob ein Element von einem Embed oder Iframe verdeckt wird
function isBlockedByEmbed(el) {
    const embeds = document.querySelectorAll('iframe, embed');
    return Array.from(embeds).some(embed => {
        const rect = embed.getBoundingClientRect();
        const elRect = el.getBoundingClientRect();
        return !(rect.right < elRect.left || 
                 rect.left > elRect.right || 
                 rect.bottom < elRect.top || 
                 rect.top > elRect.bottom);
    });
}

// Schlüsselereignis-Listener für die Escape-Taste
document.addEventListener('keydown', function(event) {
    if (event.key === 'Escape') {

        // Schließe das NightEyeDialog-Element
        const backgroundElement = document.querySelector('.NightEyeDialogBackground');
        if (backgroundElement) {
            backgroundElement.click();
        }

        // Schließe das Suchfeld, falls aktiv
        const activeToggle = document.querySelector('.search-toggle.active');
        if (activeToggle) {
            activeToggle.click();
        }

        // Entferne den Fokus vom aktiven Element
        if (document.activeElement) {
            document.activeElement.blur();
        }
    }

    // Öffnen der Suche mit der 7-Taste
    if (event.key === '7') {

        // Finde das inaktive Such-Toggle-Element
        const inactiveToggle = document.querySelector('.search-toggle:not(.active)');

        if (inactiveToggle) {
            // Simuliere einen Klick auf das inaktive Toggle-Element, um die Suche zu öffnen
            inactiveToggle.click();
        }

        // Verhindern, dass die 7 in ein Eingabefeld eingegeben wird
        event.preventDefault();
    }

    // Funktion für Enter- oder Space-Taste
    if (event.key === 'Enter' || event.key === ' ') {
        const focusedElement = document.activeElement;

        // Überprüfe, ob das fokussierte Element der Tag-Nachtmodus-Schalter ist
        if (focusedElement && focusedElement.matches('[aria-label="Tag- Nachtmodus"]')) {
            // Simuliere einen Klick auf das fokussierte Element, um den NightEyeDialog aufzurufen
            focusedElement.click();
            event.preventDefault();
        }

        // Optional: Weitere Logik für andere Enter/Space-Aktionen kann hier hinzugefügt werden
    }
});

document.addEventListener('keydown', function(event) {
    // Prüft, ob die Taste 'T' gedrückt wurde
    if (event.key === 't' || event.key === 'T') {
        // Überprüft, ob das aktive Element ein Eingabefeld oder ein Textbereich ist
        if (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA') {
            // Falls das aktive Element ein Eingabefeld oder Textbereich ist, ignoriere den Tastendruck
            return;
        }

        // Sucht nach dem .ez-toc-sticky-fixed-Element
        const tocElement = document.querySelector('.ez-toc-sticky-fixed');

        if (tocElement) {
            // Überprüft, ob das Element die Klasse 'show' hat
            if (tocElement.classList.contains('show')) {
                // Entfernt die Klasse 'show' und fügt 'hide' hinzu, um das Element zu schließen
                tocElement.classList.remove('show');
                tocElement.classList.add('hide');
            } else if (tocElement.classList.contains('hide')) {
                // Entfernt die Klasse 'hide' und fügt 'show' hinzu, um das Element zu öffnen
                tocElement.classList.remove('hide');
                tocElement.classList.add('show');
            } else {
                // Falls weder 'show' noch 'hide' gesetzt ist, wird standardmäßig geöffnet
                tocElement.classList.add('show');
            }
        }
    }
});

// Details-Element/Summary nach öffnen durch Leertaste: Leertaste ist wieder zum Scrollen geeignet
document.addEventListener('keydown', function(event) {
    // Überprüfe, ob die Leertaste gedrückt wurde
    if (event.code === 'Space') {
        const focusedElement = document.activeElement;

        // Überprüfe, ob das fokussierte Element ein <summary> ist
        if (focusedElement.tagName.toLowerCase() === 'summary') {
            // Verhindere das normale Scrollen durch die Leertaste
            event.preventDefault();

            // Öffne oder schließe das <details>-Element
            const detailsElement = focusedElement.parentElement;
            if (detailsElement.hasAttribute('open')) {
                detailsElement.removeAttribute('open');
            } else {
                detailsElement.setAttribute('open', true);
            }

            // Entferne die Fokussierung vom <summary>-Element
            focusedElement.blur();
        }
    }
});

/* = Ende ALLGEMEINE Tastaturnavigation & Fokusverwaltung = */

Tastaturbedienung

Keyboard: Tastaturnavigation
Tastaturnavigation Clker-Free-Vector-Images (Tastaturlayout English)
  • Tabulatortaste (Tab): Navigiert durch interaktive Elemente wie Links und Buttons.
  • Shift + Tab: Verschiebt den Fokus zurück zum vorherigen Element.
  • Enter-Taste: Aktiviert das aktuell fokussierte Element. Im Inhaltsbereich bewirkt die erste Betätigung die Fokussierung, während die zweite Betätigung das Element aktiviert.
  • Pfeiltasten: Scrollen innerhalb von Texten oder Menüs.
  • Leertaste: Aktiviert Buttons in der Headerleiste ähnlich wie die Enter-Taste und wird im Content zum abschnittsweisen Scrollen verwendet.
  • Shift + Leertaste: Abschnittweies Scrollen nach oben.
  • 7-Taste: Tippe '7', um die Suche zu aktivieren und 'Esc', um sie abzubrechen.
  • Escape-Taste (Esc):  Bricht alle Fokussierungen ab und schließt Dialoge.

  • T-Taste: Das Sticky-Toc (Inhaltsverzeichnis) aus- einblenden.
  • Ctrl + Alt: Den internen Link in einem neuen Tab öffnen.

Entwicklungsteil

InfoBei der kompakten Darstellung der Skripte als Entwicklungsteil trat ein Problem auf, das sich gut als Beispiel eignet, um darauf aufmerksam zu machen.

Das hier im Details-Element ist ein Beispiel dafür, wie sich ein geschlossenes detailsElement oder ein Element in einem Scroller verhält, wenn es den <pre>-Tag enthält:  Die nächsten Links und Elemente unter dem aufklappbaren Element wird mit 'Enter' nicht fokussiert, wenn das details-Element eingeklappt ist. Unsichtbare, aber technisch noch im DOM vorhandene Inhalte können dann die Navigation beeinträchtigen. Dies tritt jedoch nicht bei normalen Inhalten auf.

Das Problem tritt also auf, wenn ein <pre>-Tag in einem <details>-Element oder in einem Scrollcontainer (z.B. mit overflow: auto oder scroll) enthalten ist – unabhängig davon, ob der <pre>-Tag eine festgelegte Höhe hat oder nicht. Es liegt an der Art und Weise, wie der <pre>-Tag als Block-Element innerhalb dieser Container funktioniert.

Warum tritt das Problem auf?

  1. Block-Level-Verhalten des <pre>-Tags:
    • Der <pre>-Tag ist ein Block-Element, das von Haus aus eine spezielle Formatierung für den Inhalt übernimmt (Zeilenumbrüche und Leerzeichen werden beibehalten). Als Block-Element nimmt es in der Layout-Struktur eine signifikante Position ein.
    • In Verbindung mit Containern wie <details> oder scrollbaren Bereichen kann der Browser Schwierigkeiten haben, den Inhalt richtig zu verwalten, insbesondere was die Fokussierung von Elementen betrifft.
  2. Verhalten im <details>-Element:
    • Wenn das <details>-Element geschlossen ist, bleibt der Inhalt des <pre>-Tags technisch im DOM (Document Object Model) erhalten, ist aber nicht sichtbar. Dies führt dazu, dass der Browser die Existenz des <pre>-Tags weiterhin berücksichtigt, auch wenn es nicht gerendert wird.
    • Problem: Da der Inhalt des <pre>-Tags als "blockierender" Inhalt im DOM vorhanden bleibt, kann dies die Navigation stören, besonders wenn versucht wird, nachfolgende Links oder interaktive Elemente zu fokussieren. Der Browser „verliert“ manchmal den Kontext oder blockiert die Navigation, da er weiterhin den blockbasierten <pre>-Inhalt berücksichtigt, obwohl er visuell nicht verfügbar ist.
  3. Verhalten im Scrollcontainer:
    • Ähnlich verhält es sich bei <pre>-Tags in einem Scrollcontainer. Da das <pre>-Tag als Block-Element oft größere Textblöcke enthält und für formatierten Text gedacht ist, kann es sein, dass der Scrollcontainer Schwierigkeiten hat, den Fokus auf nachfolgende Elemente zu verschieben, wenn das <pre>-Tag sichtbar ist.
    • Problem: Wenn ein großes <pre>-Element in einem scrollbaren Bereich ist, und der sichtbare Bereich des Scrollcontainers endet, kann der Browser den Fokus schwer über das <pre>-Tag hinaus bewegen. Der Inhalt des <pre>-Tags blockiert effektiv die Fokussierung auf nachfolgende interaktive Elemente, da der Browser das Block-Level-Verhalten des <pre>-Tags priorisiert.

Das Problem entsteht also, wenn der <pre>-Tag als Block-Element in einem <details>-Element oder in einem Scrollcontainer verwendet wird, und nicht aufgrund der Höhe oder anderer Formatierungen. Das Block-Level-Verhalten des <pre>-Tags führt dazu, dass der Browser Schwierigkeiten hat, die Fokussierung auf nachfolgende Elemente richtig zu verwalten, was die Fokussierung durch die Enter-Taste beeinträchtigen kann. Das passiert nicht, wenn man allein die Tab-Taste drückt.

Details mit <pre>-Tag

Überholte Versionen HEADER und ALLGEMEINE Tastaturnavigation & Fokusverwaltung:

Tastaturnavigation-und-Fokusverwaltung_v2.js

Tastaturnavigation und Fokusverwaltung.js (_v1)

Entwicklungsbeispiel "Tastaturnavigation Headerzeile" und die "Allgemeine Navigation und Fokusverwaltung":

/* === Tastaturnavigation Headerzeile === */

document.addEventListener('DOMContentLoaded', function() {
	 // Finde alle Elemente mit der angegebenen Klasse
    const scrollers = document.querySelectorAll('.overflow-scroll-gradient__scroller');

    // Füge jedem Element tabindex="0" hinzu
    scrollers.forEach(scroller => {
        scroller.setAttribute('tabindex', '0');
    });
	
    const body = document.body;
    let toggleButtonSetupDone = false;

    // Erstmalige Tab-Taste-Überprüfung
    function handleFirstTab(event) {
        console.log('Tab event detected');
        if (event.key === 'Tab') {
            body.classList.add('keyboard-focused');
            window.removeEventListener('keydown', handleFirstTab);
            window.addEventListener('mousedown', handleMouseDown);
        }
    }

    // Mausklick-Überprüfung nach der Tab-Taste
    function handleMouseDown() {
        console.log('Mouse down detected');
        body.classList.remove('keyboard-focused');
        window.removeEventListener('mousedown', handleMouseDown);
        window.addEventListener('keydown', handleFirstTab);
    }

    window.addEventListener('keydown', handleFirstTab);

    // Tastaturnavigation für fokussierbare Elemente
    document.querySelectorAll('.focusable').forEach(button => {
        button.addEventListener('keydown', function(event) {
            console.log('Focusable keydown event detected:', event.key);
            if (event.key === 'Enter' || event.key === ' ') {
                event.preventDefault();
                button.click();
            }
        });
    });

    // Setup für den NightEye-Toggle-Button
    function setupToggleButton() {
        if (toggleButtonSetupDone) return;
        toggleButtonSetupDone = true;

        const toggleCheckbox = document.querySelector('.NightEyeToggleButton input[type="checkbox"]');
        if (toggleCheckbox) {
            console.log('Setting up toggle button');
            toggleCheckbox.setAttribute('tabindex', '0');
            toggleCheckbox.focus();

            toggleCheckbox.addEventListener('keydown', function(event) {
                console.log('Toggle button keydown event detected:', event.key);
                if (event.key === 'Enter') {
                    event.preventDefault();
                    event.stopPropagation();
                    toggleCheckbox.checked = !toggleCheckbox.checked;
                    toggleCheckbox.dispatchEvent(new Event('change', { bubbles: true }));
                }
            });
        }
    }

    // Listener für das Öffnen des NightEye-Dialogs
    function addDialogOpenListener() {
        const nightEyeWidget = document.querySelector('.NightEyeWidget');
        if (nightEyeWidget) {
            nightEyeWidget.addEventListener('click', function() {
                console.log('NightEyeWidget clicked');
                setupToggleButton();
            });
        }
    }

    addDialogOpenListener();
});

/* = Ende Tastaturnavigation Headerzeile === */

/* === Anpassung für die allgemeine Navigation und Fokusverwaltung === */

// Schlüsselereignis-Listener für die Enter-Taste
document.addEventListener('keydown', function(event) {
    if (!aboveTheFold && !navigationPaused && event.key === 'Enter') {
        event.preventDefault(); // Verhindere das Standardverhalten der Enter-Taste

        // Überprüfe, ob Boxzilla-Pop-ups geöffnet sind und setze den Fokus darauf
        if (focusBoxzillaPopups()) {
            return; // Beende die Funktion, wenn Pop-ups fokussiert wurden
        }

        const activeElement = document.activeElement;

        if (!activeElement || activeElement === document.body || !isElementInViewport(activeElement) || !activeElement.closest('#content')) {
            // Setze den Fokus auf das erste relevante sichtbare Element im #content
            focusFirstRelevantElement();
        } else {
            // Wenn das fokussierte Element im sichtbaren Bereich und im Inhalt ist, aktiviere es
            activateElement(activeElement);
        }
    }
});

// Überwachung des Scrollens mit Debouncing und "Above the Fold"-Logik
let aboveTheFold = true; // Zustand, ob wir uns im "Above the Fold"-Bereich befinden
let navigationPaused = false; // Zustand, ob die Navigation pausiert ist
let lastScrollY = 0; // Variable für die letzte Scroll-Position
let scrollTimeout;

// Überwachung des Scrollens
window.addEventListener('scroll', function() {
    const currentScrollY = window.scrollY;

    if (Math.abs(currentScrollY - lastScrollY) < 10) return; // Wenn die Scroll-Änderung zu klein ist, überspringe

    clearTimeout(scrollTimeout);
    scrollTimeout = setTimeout(function() {
        const foldBoundary = window.innerHeight * 0.5; // Definition von "Above the Fold"
        const activeElement = document.activeElement;

        if (window.scrollY > foldBoundary) {
            aboveTheFold = false; // Benutzer hat den "Above the Fold"-Bereich verlassen
        } else {
            if (!aboveTheFold) { // Nur zurücksetzen, wenn wir gerade erst in den "Above the Fold"-Bereich gescrollt haben
                resetTabindex(); // Setzt den Tabindex zurück
            }
            aboveTheFold = true; // Benutzer ist wieder im "Above the Fold"-Bereich
        }

        // Entferne den Fokus, wenn das aktive Element nicht mehr im Viewport ist
        if (activeElement && !isElementInViewport(activeElement)) {
            activeElement.blur();
            console.log('Element out of viewport, focus removed:', activeElement);
        }

        lastScrollY = currentScrollY; // Update lastScrollY after processing
    }, 100); // Timeout nach 100ms Inaktivität
});

// Überwachung des Klicks auf die Headerzeile
const headerElement = document.querySelector('#masthead') || document.querySelector('.header-main');
if (headerElement) {
    headerElement.addEventListener('click', function() {
        navigationPaused = true; // Pausiert die Tastaturnavigation
        console.log('Navigation paused due to header interaction');
    });
}

// Überwachung des Fokus-Wechsels im Headerbereich
document.addEventListener('focusin', function(event) {
    if (headerElement && headerElement.contains(event.target)) {
        navigationPaused = true; // Pausiert die Tastaturnavigation, wenn der Fokus im Headerbereich liegt
        console.log('Navigation paused due to header focus');
    }
});

// Überwachung des Fokus-Wechsels außerhalb des Headerbereichs
document.addEventListener('focusout', function(event) {
    if (headerElement && headerElement.contains(event.target)) {
        navigationPaused = false; // Reaktiviert die Tastaturnavigation, wenn der Fokus den Headerbereich verlässt
        console.log('Navigation resumed after leaving header');
    }
});

// Funktion zum Zurücksetzen des Tabindex
function resetTabindex() {
    const firstFocusableElement = document.querySelector('a, button, input, textarea, select, [tabindex]:not([tabindex="-1"])');
    if (firstFocusableElement) {
        firstFocusableElement.focus();
        console.log('Tabindex reset and focus set on:', firstFocusableElement);
    } else {
        console.log('No focusable element found to reset tabindex');
    }
}

// Funktion zum Fokussieren von Boxzilla-Pop-ups
/*function focusBoxzillaPopups() {
    const popups = document.querySelectorAll('.boxzilla:not([style*="display: none"])'); // Selektor für sichtbare Boxzilla-Pop-ups
    let focusedAnyPopup = false;

    // Durchlaufe alle sichtbaren Boxzilla-Pop-ups
    popups.forEach(popup => {
        const focusableElements = popup.querySelectorAll('a, button, input, textarea, select, [tabindex]:not([tabindex="-1"])');
        if (focusableElements.length > 0) {
            focusableElements[0].focus(); // Setzt den Fokus auf das erste fokussierbare Element
            focusedAnyPopup = true;
            console.log('Focus set on Boxzilla popup:', popup);
        }
    });

    return focusedAnyPopup; // Gibt zurück, ob mindestens ein Pop-up fokussiert wurde
}*/

// Variable zum Verfolgen des aktuell fokussierten Pop-ups
let lastFocusedPopup = null;

// Funktion zum Fokussieren des ersten sichtbaren Boxzilla-Pop-ups
function focusBoxzillaPopups() {
    // Alle sichtbaren Boxzilla-Pop-ups auswählen
    const popups = document.querySelectorAll('.boxzilla:not([style*="display: none"])');

    // Fokus nur auf das neueste Pop-up setzen
    let focusedAnyPopup = false;
    popups.forEach(popup => {
        const focusableElements = popup.querySelectorAll('a, button, input, textarea, select, [tabindex]:not([tabindex="-1"])');
        if (focusableElements.length > 0) {
            if (popup !== lastFocusedPopup) {
                // Setzt den Fokus auf das erste fokussierbare Element
                const firstFocusableElement = focusableElements[0];
                firstFocusableElement.focus();

                // Scrollen, um sicherzustellen, dass das Pop-up sichtbar ist
                if (popup.scrollIntoViewIfNeeded) {
                    popup.scrollIntoViewIfNeeded(true);
                } else {
                    popup.scrollIntoView({ behavior: 'smooth', block: 'start' });
                }

                // Setze lastFocusedPopup auf das aktuelle Pop-up
                lastFocusedPopup = popup;
                focusedAnyPopup = true;
                console.log('Focus set on Boxzilla popup:', popup);
            }
        }
    });

    return focusedAnyPopup; // Gibt zurück, ob mindestens ein Pop-up fokussiert wurde
}

// Funktion zur Überwachung von Pop-up-Änderungen
function setupPopupMonitoring() {
    const observer = new MutationObserver(() => {
        // Verzögerung hinzufügen, um sicherzustellen, dass das Pop-up vollständig gerendert ist
        setTimeout(() => {
            focusBoxzillaPopups();
        }, 100); // Verzögerung anpassen, falls nötig
    });

    // Beobachte Änderungen im DOM
    observer.observe(document.body, { childList: true, subtree: true });

    // Initiales Fokussieren beim Laden der Seite
    setTimeout(() => {
        focusBoxzillaPopups();
    }, 100); // Verzögerung anpassen, falls nötig
}

// Starte die Überwachung der Pop-ups
setupPopupMonitoring();

// Funktion zum Fokussieren des ersten relevanten Elements im Inhaltsbereich
function focusFirstRelevantElement() {
    const focusableElements = '#content iframe, #content embed, #content a[href], #content button, #content input, #content textarea, #content select, #content [tabindex]:not([tabindex="-1"])';
    const elements = Array.from(document.querySelectorAll(focusableElements));

    // Priorisiere das Fokussieren von EMBED- und IFRAME-Elementen, wenn sie sichtbar sind
    const firstRelevantElement = elements.find(el => 
        isElementInViewport(el) &&
        (['IFRAME', 'EMBED'].includes(el.tagName) || !isBlockedByEmbed(el))
    );

    if (firstRelevantElement) {
        // Eventuelle Besonderheiten für Firefox beim Fokussieren von `iframe` oder `embed`
        if (firstRelevantElement.tagName === 'IFRAME' || firstRelevantElement.tagName === 'EMBED') {
            // Fallback-Logik für Firefox
            setTimeout(() => firstRelevantElement.focus(), 100);
        } else {
            firstRelevantElement.focus();
        }
        console.log('Focus set on first relevant element:', firstRelevantElement);
    } else {
        console.log('No relevant focusable element found in #content');
    }
}

// Funktion zum Aktivieren eines Elements
function activateElement(element) {
    if (typeof element.click === 'function') {
        element.click();
        console.log('Element activated:', element);
    } else {
        console.log('Element cannot be activated:', element);
    }
}

// Funktion zum Überprüfen, ob ein Element im Viewport ist
function isElementInViewport(el) {
    const rect = el.getBoundingClientRect();
    return (
        rect.bottom > 0 &&
        rect.top < window.innerHeight &&
        rect.right > 0 &&
        rect.left < window.innerWidth
    );
}

// Funktion zum Überprüfen, ob ein Element von einem Embed oder Iframe verdeckt wird
function isBlockedByEmbed(el) {
    const embeds = document.querySelectorAll('iframe, embed');
    return Array.from(embeds).some(embed => {
        const rect = embed.getBoundingClientRect();
        const elRect = el.getBoundingClientRect();
        return !(rect.right < elRect.left || 
                 rect.left > elRect.right || 
                 rect.bottom < elRect.top || 
                 rect.top > elRect.bottom);
    });
}

// Schlüsselereignis-Listener für die Escape-Taste
document.addEventListener('keydown', function(event) {
    if (event.key === 'Escape') {
        console.log('Escape-Taste wurde gedrückt');

        // Schließe das NightEyeDialog-Element
        const backgroundElement = document.querySelector('.NightEyeDialogBackground');
        if (backgroundElement) {
            backgroundElement.click();
            console.log('NightEyeDialog geschlossen');
        }

        // Schließe das Suchfeld, falls aktiv
        const activeToggle = document.querySelector('.search-toggle.active');
        if (activeToggle) {
            activeToggle.click();
            console.log('Suchfeld geschlossen durch Klicken auf das aktive Toggle-Element');
        }

        // Entferne den Fokus vom aktiven Element
        if (document.activeElement) {
            document.activeElement.blur();
            console.log('Fokus entfernt');
        }
    }

    // Öffnen der Suche mit der 7-Taste
    if (event.key === '7') {
        console.log('7-Taste wurde gedrückt');

        // Finde das inaktive Such-Toggle-Element
        const inactiveToggle = document.querySelector('.search-toggle:not(.active)');

        if (inactiveToggle) {
            // Simuliere einen Klick auf das inaktive Toggle-Element, um die Suche zu öffnen
            inactiveToggle.click();
            console.log('Suchfeld geöffnet durch Klicken auf das inaktive Toggle-Element');
        }
        
        // Verhindern, dass die / in ein Eingabefeld eingegeben wird
        event.preventDefault();
    }

    // Funktion für Enter- oder Space-Taste
    if (event.key === 'Enter' || event.key === ' ') {
        const focusedElement = document.activeElement;

        // Überprüfe, ob das fokussierte Element der Tag-Nachtmodus-Schalter ist
        if (focusedElement && focusedElement.matches('[aria-label="Tag- Nachtmodus"]')) {
            console.log('Tag-Nachtmodus-Schalter wurde aktiviert');
            
            // Simuliere einen Klick auf das fokussierte Element, um den NightEyeDialog aufzurufen
            focusedElement.click();
            event.preventDefault();
        }

        // Optional: Weitere Logik für andere Enter/Space-Aktionen kann hier hinzugefügt werden
    }
});

/* = Ende Anpassung für die allgemeine Navigation und Fokusverwaltung === */

Das oben gezeigte JavaScript zeigt möglicherweise keine Fokussierung von Embeds bei der Verwendung der Enter-Taste.


Überholte Version Fokussierung und Markierung von EMBEDs:

Die Fokussierung der WP-Embeds wurden im Skript von "3. Fokussierung und Markierung von EMBEDs" vollständig neu überarbeitet und sind daher deutlich performanter. Das Folgende ist eine Dokumentation der veralteten Herangehensweise.

Die Links in einem Embed werden zwar durch die Tab-Taste nacheinander aktiviert, doch mit der Enter-Taste ließ sich die Fokussierung bislang nicht richtig umsetzen. Da Embeds generell schwerer zu fokussieren sind und das Aktivieren mit Enter nicht dieselbe visuelle Rückmeldung wie bei Links bietet, war das ein Problem. Das Embed wird zwar durch Enter Fokussiert, aber diese Fokussierung wird nicht visuell deutlich. Der erste Link in einem Embed wird erst mit einem weiteren Druck auf die Tab-Taste fokussiert. Im Folgenden geht es um die primäre Fokussierung.

Mit einem JavaScript konnten wir das Problem so lösen, dass das gesamte Embed markiert wird, wenn es direkt mit der Enter-Taste aktiviert wird. Diese Markierung erfolgt jedoch nur, wenn Enter verwendet wird, nicht bei einer Fokussierung durch Tab, da die Links im Embed ohnehin durch Tab optisch hervorgehoben werden.

  • CSS-Anwendung bei Enter-Taste: Das Skript fügt ein benutzerdefiniertes CSS hinzu, um ein Embed-Element hervorzuheben, wenn es durch Drücken der Enter-Taste im Viewport fokussiert wird.
  • Keine CSS-Anwendung bei Links vor Embeds: Wenn ein Link direkt vor einem Embed fokussiert wird, wird das CSS nicht angewendet, um unnötige Hervorhebungen zu vermeiden.
  • CSS-Entfernung bei Tab-Navigation: Wenn durch die Tab-Taste ein anderes Element als das Embed fokussiert wird, wird das benutzerdefinierte CSS entfernt.
  • Scroll-Überwachung: Beim Scrollen wird das CSS automatisch entfernt, wenn das Embed den Viewport verlässt.
  • Fokus-Überwachung: Das Skript überwacht den Fokuswechsel und passt das CSS entsprechend an, je nachdem, ob das Embed im Viewport sichtbar ist und fokussiert wird.
  • Hilfsfunktion zur Sichtbarkeitsprüfung: Eine Funktion prüft, ob das Embed tatsächlich im sichtbaren Bereich des Viewports liegt, bevor das CSS angewendet oder entfernt wird.

Dieses JavaScript-Skript bietet eine Lösung zur Verwaltung der Fokussierung und visuellen Markierung von Embed-Elementen auf unserer Webseite. Es sorgt dafür, dass EMBEDs beim Fokus oder Klick hervorgehoben werden und bietet eine verbesserte Benutzererfahrung, indem es visuelle Hinweise gibt und die Fokussierung gezielt steuert. Das Skript behandelt verschiedene Interaktionen wie Klicks, Tastatureingaben und Scrollen, um sicherzustellen, dass die Sichtbarkeit und Interaktivität von Embeds optimal gehandhabt werden.

Die Hauptfunktionen umfassen:

  • Automatische Markierung und Entfernen der Markierung bei Fokuswechsel
  • Visuelle Hervorhebung durch benutzerdefiniertes CSS
  • Intelligente Verwaltung der Fokussierung, um Konflikte zwischen Links und Embeds zu vermeiden.

iframe-embed-focus-control-plus-nachricht_v1.js

iframe-embed-focus-control_v2.js

iframe-embed-focus-control_v1.js

Entwicklungsbeispiel "Embed Fokussieren":
Ziel war es, dass Embeds durch Enter fokussiert werden können, ähnlich wie es normalerweise mit der Tab-Taste geschieht. Allerdings blieb das folgende CSS wirkungslos:

/* Versuch: Embed Link durch Enter fokussieren */

.wp-embedded-content:focus,
iframe.wp-embedded-content:focus {
    outline: 1px solid gray;
}

Auch der Ansatz, das gesamte Embed durch Einfügen einer CSS-Klasse (focused) im JavaScript zu fokussieren und visuell hervorzuheben, scheiterte. In diesem Fall verhinderten Sicherheitsmechanismen wie Same-Origin-Policies oder strenge Content Security Policies (CSP), dass die Classe per JavaScript hinzugefügt und über CSS visualisiert werden konnte.

.wp-embedded-content.focused,
iframe.wp-embedded-content.focused {
    outline: 1px solid gray;
}

Diese Ansätze waren also erfolglos.

Die nächste Idee war, das Embed durch Enter zu visualisieren, indem es dauerhaft hervorgehoben wird. Hierfür sollte ein einfaches CSS-Styling verwendet werden:

.wp-embedded-content {
    outline: 1px solid gray;
}

Logischerweise sollte das CSS nur wirksam werden, wenn das Embed im Viewport ist und erst durch Drücken der Enter-Taste aktiviert wird. Zudem sollte die Markierung wieder entfernt werden, wenn das Embed den Viewport verlässt oder der Fokus per Tab auf das nächste Element wechselt. Diese Funktionalität konnte erfolgreich umgesetzt werden.

Ein Problem bleibt jedoch bestehen: Wenn sich ein Link oberhalb des Embeds befindet und dieser durch Enter fokussiert wurde, wird das Embed nach dem Drücken der Tab-Taste wie gewohnt fokussiert, während der Fokus vom Link entfernt wird. Das funktioniert soweit gut. Interessanterweise wird bei einem Embed ohne vorhergehenden Link oder Element im Viewport durch Drücken der Enter-Taste keine Markierung angezeigt, da sich das Embed nur durch die Tab-Taste fokussieren lässt.

Das folgende JavaScript integriert diese Funktionalität. Es stellt sicher, dass das CSS nur dann aktiv wird, wenn das Embed im Viewport ist und kein Link oder Element zuvor fokussiert wurde, Entwicklung:

/* --- Embed als gesamtens mit Enter markieren --- */

// Funktion, um das CSS für das spezifische Element hinzuzufügen
function addCustomCSS(embedElement) {
    if (!embedElement.querySelector('.wp-embedded-content-css')) {
        const style = document.createElement('style');
        style.className = 'wp-embedded-content-css'; // Füge eine Klasse hinzu
        style.type = 'text/css';
        const css = `
            .wp-embedded-content {
                outline: 1px solid gray;
            }
        `;
        style.appendChild(document.createTextNode(css));
        embedElement.appendChild(style);
    }
}

// Funktion, um das CSS von einem spezifischen Element zu entfernen
function removeCustomCSS(embedElement) {
    const style = embedElement.querySelector('.wp-embedded-content-css');
    if (style) {
        style.remove(); // Entferne das CSS-Element
    }
}

// Funktion zum Überprüfen, ob ein Embed im Viewport sichtbar ist
function getEmbedInViewport() {
    const embeds = document.querySelectorAll('iframe, embed');
    return Array.from(embeds).find(embed => isElementInViewport(embed));
}

// Funktion zum Überprüfen, ob ein Link vor einem Embed fokussiert wird
function getLinkBeforeEmbed() {
    const links = document.querySelectorAll('#content a');
    return Array.from(links).find(link => {
        const linkRect = link.getBoundingClientRect();
        const embed = getEmbedInViewport();
        if (embed) {
            const embedRect = embed.getBoundingClientRect();
            return linkRect.bottom < embedRect.top && isElementInViewport(link);
        }
        return false;
    });
}

// Überwachung der Enter-Taste
document.addEventListener('keydown', function(event) {
    if (event.key === 'Enter') {
        const activeElement = document.activeElement;
        const embedElement = getEmbedInViewport();
        const linkBeforeEmbed = getLinkBeforeEmbed();

        if (linkBeforeEmbed && linkBeforeEmbed === activeElement) {
            // Kein CSS anwenden, wenn der Link vor dem Embed fokussiert ist
            return;
        }

        if (embedElement && isElementInViewport(embedElement)) {
            event.preventDefault(); // Verhindere Standardverhalten für Enter
            addCustomCSS(embedElement);
            console.log('Custom CSS applied to the embed in the viewport.');
        }
    }
});

// Überwachung der Tab-Taste
document.addEventListener('keydown', function(event) {
    if (event.key === 'Tab') {
        const embedElement = getEmbedInViewport();
        const activeElement = document.activeElement;

        if (embedElement && isElementInViewport(embedElement)) {
            if (activeElement === embedElement) {
                addCustomCSS(embedElement);
            } else {
                removeCustomCSS(embedElement);
            }
        }
    }
});

// Überwachung des Scrollens, um das CSS zurückzusetzen, wenn das Embed den Viewport verlässt
window.addEventListener('scroll', function() {
    const embeds = document.querySelectorAll('iframe, embed');
    embeds.forEach(embed => {
        if (!isElementInViewport(embed)) {
            removeCustomCSS(embed); // Entferne das CSS von nicht sichtbaren Embeds
        }
    });
});

// Überwachung des Fokus-Wechsels (Tab- und Enter-Navigation)
document.addEventListener('focusin', function() {
    const embedElement = getEmbedInViewport();
    const activeElement = document.activeElement;

    if (embedElement && isElementInViewport(embedElement)) {
        if (activeElement === embedElement) {
            addCustomCSS(embedElement);
        } else {
            removeCustomCSS(embedElement);
        }
    }
});

// Hilfsfunktion zum Überprüfen, ob ein Element im Viewport sichtbar ist
function isElementInViewport(el) {
    const rect = el.getBoundingClientRect();
    return (
        rect.bottom > 0 &&
        rect.top < window.innerHeight &&
        rect.right > 0 &&
        rect.left < window.innerWidth
    );
}

/* - Ende Embed als gesamtes mit Enter markieren - */

Folgende beide Codes sind relativ ähnlich und erfüllen ihre Funktion. Es gibt jedoch einige Unterschiede, die die Stabilität und allgemeine Handhabung beeinflussen können. Ich werde die Vor- und Nachteile beider Ansätze zusammenfassen und eine Empfehlung aussprechen.

Erster Code

  • Vorteile:
    • Nutzt die Funktion getLinkBeforeEmbed, um sicherzustellen, dass ein vor dem Embed fokussierter Link erkannt wird, bevor das CSS angewendet wird.
    • Die Logik zur Überprüfung des Links vor dem Embed ist detailliert und spezifisch.
  • Nachteile:
    • Der Code ist etwas länger und komplexer durch die Verwendung der zusätzlichen getLinkBeforeEmbed-Funktion.
    • Da die Logik für das Entfernen des CSS auf dem focusin-Event basiert, könnte es in bestimmten Fällen zu Timing-Problemen kommen, wenn der Fokus schnell gewechselt wird.

Zweiter Code

  • Vorteile:
    • Der Code ist stabil und einfach zu warten.
    • Die Verwendung des focusout-Events zum Entfernen des CSS ist robuster und stellt sicher, dass das CSS zuverlässig entfernt wird, wenn das Embed den Fokus verliert.
    • Die Funktion isLinkBeforeEmbedInViewport ist einfacher, was potenziell weniger Fehlerquellen bietet.
  • Nachteile:
    • Ein kleiner Nachteil könnte sein, dass das Entfernen des CSS nicht auf eine spezielle Bedingung wie im ersten Code basiert, sondern auf einem simpleren Ansatz. Das könnte unter bestimmten Bedingungen zu einem unerwarteten Verhalten führen.

Erster Code:

/* --- Embed als gesamtens mit Enter markieren, Optimierung 1  --- */
// Funktion, um das CSS für das spezifische Element hinzuzufügen
function addCustomCSS(embedElement) {
    if (!embedElement.querySelector('.wp-embedded-content-css')) {
        const style = document.createElement('style');
        style.className = 'wp-embedded-content-css'; // Füge eine Klasse hinzu
        style.type = 'text/css';
        style.textContent = `
            .wp-embedded-content {
                outline: 1px solid gray;
            }
        `;
        embedElement.appendChild(style);
    }
}

// Funktion, um das CSS von einem spezifischen Element zu entfernen
function removeCustomCSS(embedElement) {
    const style = embedElement.querySelector('.wp-embedded-content-css');
    if (style) {
        style.remove(); // Entferne das CSS-Element
    }
}

// Funktion zum Überprüfen, ob ein Embed im Viewport sichtbar ist
function getEmbedInViewport() {
    const embeds = document.querySelectorAll('iframe, embed');
    return Array.from(embeds).find(isElementInViewport);
}

// Funktion zum Überprüfen, ob ein Link vor einem Embed fokussiert wird
function getLinkBeforeEmbed() {
    const links = document.querySelectorAll('#content a');
    const embed = getEmbedInViewport();
    if (!embed) return null;
    return Array.from(links).find(link => {
        const linkRect = link.getBoundingClientRect();
        const embedRect = embed.getBoundingClientRect();
        return linkRect.bottom < embedRect.top && isElementInViewport(link);
    });
}

// Überwachung der Enter-Taste
document.addEventListener('keydown', function(event) {
    if (event.key === 'Enter') {
        const activeElement = document.activeElement;
        const embedElement = getEmbedInViewport();
        const linkBeforeEmbed = getLinkBeforeEmbed();

        if (linkBeforeEmbed && linkBeforeEmbed === activeElement) {
            // Kein CSS anwenden, wenn der Link vor dem Embed fokussiert ist
            return;
        }

        if (embedElement && isElementInViewport(embedElement)) {
            event.preventDefault(); // Verhindere Standardverhalten für Enter
            addCustomCSS(embedElement);
            console.log('Custom CSS applied to the embed in the viewport.');
        }
    }
});

// Überwachung der Tab-Taste
document.addEventListener('keydown', function(event) {
    if (event.key === 'Tab') {
        const embedElement = getEmbedInViewport();
        const activeElement = document.activeElement;

        if (embedElement && isElementInViewport(embedElement)) {
            if (activeElement === embedElement) {
                addCustomCSS(embedElement);
            } else {
                removeCustomCSS(embedElement);
            }
        }
    }
});

// Überwachung des Scrollens, um das CSS zurückzusetzen, wenn das Embed den Viewport verlässt
window.addEventListener('scroll', function() {
    const embeds = document.querySelectorAll('iframe, embed');
    embeds.forEach(embed => {
        if (!isElementInViewport(embed)) {
            removeCustomCSS(embed); // Entferne das CSS von nicht sichtbaren Embeds
        }
    });
});

// Überwachung des Fokus-Wechsels (Tab- und Enter-Navigation)
document.addEventListener('focusin', function() {
    const embedElement = getEmbedInViewport();
    const activeElement = document.activeElement;

    if (embedElement && isElementInViewport(embedElement)) {
        if (activeElement === embedElement) {
            addCustomCSS(embedElement);
        } else {
            removeCustomCSS(embedElement);
        }
    }
});

// Hilfsfunktion zum Überprüfen, ob ein Element im Viewport sichtbar ist
function isElementInViewport(el) {
    const rect = el.getBoundingClientRect();
    return (
        rect.bottom > 0 &&
        rect.top < window.innerHeight &&
        rect.right > 0 &&
        rect.left < window.innerWidth
    );
}

/* - Ende Embed als gesamtens mit Enter markieren, Optimierung 1 - */

Zweiter Code:

/* --- Embed als gesamtens mit Enter markieren, Optimierung 2 --- */

// Funktion, um das CSS für das spezifische Element hinzuzufügen
function addCustomCSS(embedElement) {
    if (!embedElement.querySelector('.wp-embedded-content-css')) {
        const style = document.createElement('style');
        style.className = 'wp-embedded-content-css';
        style.type = 'text/css';
        style.textContent = `
            .wp-embedded-content {
                outline: 1px solid gray;
            }
        `;
        embedElement.appendChild(style);
    }
}

// Funktion, um das CSS von einem spezifischen Element zu entfernen
function removeCustomCSS(embedElement) {
    const style = embedElement.querySelector('.wp-embedded-content-css');
    if (style) {
        style.remove();
    }
}

// Funktion zum Überprüfen, ob ein Embed im Viewport sichtbar ist
function getEmbedInViewport() {
    const embeds = document.querySelectorAll('iframe, embed');
    return Array.from(embeds).find(isElementInViewport);
}

// Funktion zum Überprüfen, ob vor dem Embed ein Link im Viewport sichtbar ist
function isLinkBeforeEmbedInViewport() {
    const embed = getEmbedInViewport();
    if (!embed) return false;

    const links = document.querySelectorAll('#content a');
    return Array.from(links).some(link => {
        const linkRect = link.getBoundingClientRect();
        const embedRect = embed.getBoundingClientRect();
        return linkRect.bottom < embedRect.top && isElementInViewport(link);
    });
}

// Überwachung der Enter-Taste
document.addEventListener('keydown', function(event) {
    if (event.key === 'Enter') {
        const embedElement = getEmbedInViewport();

        if (embedElement && isElementInViewport(embedElement) && !isLinkBeforeEmbedInViewport()) {
            event.preventDefault(); // Verhindere Standardverhalten für Enter
            addCustomCSS(embedElement);
            console.log('Custom CSS applied to the embed in the viewport.');
        }
    }
});

// Überwachung der Tab-Taste
document.addEventListener('keydown', function(event) {
    if (event.key === 'Tab') {
        const embedElement = getEmbedInViewport();
        const activeElement = document.activeElement;

        if (embedElement && isElementInViewport(embedElement)) {
            if (activeElement === embedElement) {
                addCustomCSS(embedElement);
            } else {
                removeCustomCSS(embedElement);
            }
        }
    }
});

// Überwachung des Fokus-Wechsels (Tab- und Enter-Navigation)
document.addEventListener('focusin', function(event) {
    const embedElement = getEmbedInViewport();
    const activeElement = document.activeElement;

    if (embedElement && isElementInViewport(embedElement)) {
        if (activeElement === embedElement) {
            addCustomCSS(embedElement);
        } else {
            removeCustomCSS(embedElement);
        }
    }
});

// Überwachung des Fokus-Verlassens (wenn Tab verwendet wird)
document.addEventListener('focusout', function(event) {
    const embedElement = event.target;
    if (embedElement && embedElement.tagName.toLowerCase() === 'iframe' || embedElement.tagName.toLowerCase() === 'embed') {
        removeCustomCSS(embedElement);
    }
});

// Überwachung des Scrollens, um das CSS zurückzusetzen, wenn das Embed den Viewport verlässt
window.addEventListener('scroll', function() {
    const embeds = document.querySelectorAll('iframe, embed');
    embeds.forEach(embed => {
        if (!isElementInViewport(embed)) {
            removeCustomCSS(embed); // Entferne das CSS von nicht sichtbaren Embeds
        }
    });
});

// Hilfsfunktion zum Überprüfen, ob ein Element im Viewport sichtbar ist
function isElementInViewport(el) {
    const rect = el.getBoundingClientRect();
    return (
        rect.bottom > 0 &&
        rect.top < window.innerHeight &&
        rect.right > 0 &&
        rect.left < window.innerWidth
    );
}

/* - Ende Embed als gesamtens mit Enter markieren, Optimierung 2 - */

Empfehlung

ChatGPT empfahl den zweiten Code aufgrund seiner Einfachheit und der Nutzung von focusout, um das CSS zu entfernen. Der Code ist stabiler, weil er den Fokusverlust effizienter überwacht und somit das Risiko von Timing-Problemen minimiert. Er ist zudem einfacher zu verstehen und zu warten, was in der Regel für langfristige Stabilität und Zuverlässigkeit von Vorteil ist.

Wenn in der Praxis feststellt wird, dass bestimmte Fälle nicht ausreichend abgedeckt sind, kann der zweite Code immer noch anpasst werden. In den meisten Anwendungsfällen sollte dieser jedoch zuverlässig funktionieren.

Illustration: Emmenthaler-Cheese
Illustration Clker-Free-Vector-Images

Testlink, der sich bei geschlossenem details-Element oder einem Scrollbereich mit Inhalten im <pre>-Tag nicht per 'Enter' fokussieren lässt: Scrolle zum Entwicklungsteil. Links weiter unterhalb sind nicht betroffen.

Zusatzinformationen

Ankerlinks sollten nicht im <a>-Tag sein?

Update: durch die Änderung von #content a zu #content a[href] ist folgendes nicht mehr relevant:

Vermeidung unnötiger Fokussierung: Ankerlinks (die durch das <a>-Tag definiert werden) können dazu führen, dass unerwünschte Fokussierung auf sie gesetzt wird, was oft zu einer leeren Fokussierung führt. Wenn die Fokussierung auf einem Ankerlink nicht erforderlich ist, sollte dieser nicht fokussierbar sein. Eine mögliche Lösung besteht darin, den Anker durch ein <div> oder <span> mit einer ID zu ersetzen, wenn keine Fokussierung gewünscht ist.

Hinweis: Ankerlinks, die von <a id="Anker"></a> zu <span id="Anker"></span> geändert wurden, sind im Editor visuell nicht mehr sichtbar gekennzeichnet.

Weitere Anpassungen

Im Zusammenhang mit der Tabnavigation gibt es hier der Website folgende Artikel:

Nachlese

Plug-ins

Es gibt eine Vielzahl von Plug-ins, die bestimmte Funktionen zur Barrierefreiheit abdecken. Während sie für einfache und schnelle Implementierungen hilfreich sein können, können sie in speziellen Anwendungsfällen manchmal nicht die erwartete Flexibilität oder Leistung bieten. Auch wenn einige Plug-ins zusätzliche Features wie einen Dunkelmodus bereitstellen, entsprechen diese möglicherweise nicht immer den individuellen Vorstellungen oder Anforderungen.

Für Entwickler und Webseitenbetreiber, die eine besonders präzise Anpassung wünschen, ist es oft sinnvoll, eigene Lösungen zu implementieren. Dennoch bieten Plug-ins eine solide Basis, insbesondere für diejenigen, die auf eine schnelle Umsetzung und Standardfunktionen Wert legen.

Anhang: Barrierefreiheit

Ein Tool zum Testen, das uns sehr ausführlich erscheint und eigentlich keine Wünsche offenlässt, ist https://wave.webaim.org/.

Auch wenn auf der Website nicht alles in Bezug auf die Kontrastprüfung perfekt ist, eignet sich das Tool hervorragend, um andere Ungereimtheiten leicht zu finden und zu beheben.

Hinweise zum <noscript>-Elements

Anmerkung zum Test und Hinweise zum <noscript>-Elements in der Webseite, das im WAVE-Tool als Problem markiert wird. Hier eine kurze Erklärung:

Das <noscript>-Element wird verwendet, um Inhalte für Benutzer bereitzustellen, die JavaScript in ihrem Browser deaktiviert haben. Es wird aber auch von Crawlern und Barrierefreiheits-Tools erkannt. Obwohl es kein direktes Barrierefreiheitsproblem darstellt, kann es von Prüftools als Hinweis darauf aufgenommen werden, dass der Inhalt möglicherweise anders gerendert wird, wenn JavaScript deaktiviert ist.

Warum wird es angezeigt?

Das <noscript>-Element wird von Autoptimize eingefügt. Autoptimize ist ein beliebtes Plugin zur Optimierung von Websites, und es sorgt unter anderem dafür, dass Bilder und andere Medien lazy-loaded (also nur dann geladen) werden, wenn sie im sichtbaren Bereich erscheinen.

Dabei kann Autoptimize das <noscript>-Element als Fallback verwenden, um sicherzustellen, dass Inhalte auch dann angezeigt werden, wenn JavaScript deaktiviert ist oder Lazy Loading aus irgendeinem Grund nicht funktioniert. Das <noscript>-Element enthält dann meist das Bild oder den Inhalt in normaler Form, damit es auch ohne JavaScript geladen wird.


Und der https://validator.w3.org/ kann auch immer mal gut sein 😛

wp wegerl.at

Der Beitrag wurde mit fachlicher Unterstützung erstellt.


Aktualisiert im Jahr 2024 September