Alt-Tags sind der bekannteste Aspekt beim Erstellen barrierefreier Webseiten, werden aber leider oft vernachlässigt oder schlecht implementiert. Alt-Tags sind kurze Textbeschreibungen, die Bildern hinzugefügt werden. Bildschirmleseprogramme lesen Benutzern den Inhalt einer Webseite vor und die Bildbeschreibungen sind das, was sie lesen, um sehbehinderten Benutzern mitzuteilen, was in den Bildern auf der Seite enthalten ist, da sie diese nicht sehen können.
Leider kommt es häufig vor, dass bei Bildern sämtliche Alt-Tags fehlen. Ich habe auch schon Alt-Tags gesehen, die auf eine Weise missbraucht wurden, die es sehbehinderten Benutzern erschwert, z. B. Tags, die nur „Bild“ oder „Abbildung“ sagen, Tags, die niedliche Bildunterschriften sind, die ein Autor hinzugefügt hat, ohne Bezug darauf zu nehmen, was auf dem Bild zu sehen ist (z. B. ein Bild von einem Kaffee und einem Laptop auf einer Blog-Seite mit der Überschrift „Liebes Tagebuch, ich würde gerne als Gastautor ausgewählt werden“). Ich habe auch Alt-Tags gesehen, die drei Zeilen mit SEO-Schlüsselwörtern enthielten. Können Sie sich vorstellen, dass Sie versuchen, sich anzuhören, was auf einer Website steht, und nur „Bild von Bild“ oder eine lange Liste mit SEO-Schlüsselwörtern hören?
Dies ist eine Chrome-Erweiterung, die sehbehinderten Benutzern die Möglichkeit bietet, fehlerhafte Alt-Tags zu überschreiben und Open AI zu nutzen, um KI-generierte Beschreibungen einzufügen. Auf diese Weise kann ein sehbehinderter Benutzer tatsächlich auf alle Inhalte einer Webseite zugreifen, auf die auch ein sehbehinderter Benutzer zugreifen kann (oder wird zumindest nicht durch eine lange Liste von SEO-Schlüsselwörtern ausgebremst).
Wenn Sie nur die Erweiterung möchten, können Sie dieses Repo herunterladen und den Anweisungen in der README-Datei folgen.
Wenn Sie jedoch an einer Schritt-für-Schritt-Anleitung zum Erstellen einer Chrome-Erweiterung mit OpenAI interessiert sind, finden Sie nachfolgend eine Schritt-für-Schritt-Anleitung.
Lassen Sie uns zunächst eine grundlegende Chrome-Vorlage erstellen und ausführen. Klonen Sie dieses Repository und folgen Sie den Anweisungen in der README-Datei:
Sobald Sie es eingerichtet und installiert haben, sollte in Ihrer Erweiterungsleiste ein Bildsymbol angezeigt werden (ich empfehle, es anzuheften, um das Testen zu beschleunigen). Wenn Sie darauf klicken, sollte ein Popup mit „Hallo Welt“ angezeigt werden.
Öffnen wir den Boilerplate-Code und gehen wir die vorhandenen Dateien durch. Dabei werden auch einige Grundlagen der Chrome-Erweiterung behandelt:
Static/manifest.json – Jede Chrome-Erweiterung hat eine manifest.json-Datei. Sie enthält grundlegende Informationen und Einstellungen zur Erweiterung. In unserer Manifestdatei haben wir einen Namen, eine Beschreibung, eine Hintergrunddatei mit der Einstellung src/background.js, ein Symbol mit der Einstellung image-icon.png (dies ist das Symbol, das im Erweiterungsmenü als Darstellung der Erweiterung angezeigt wird) und sie legt popup.html als Dateiquelle für unser Popup fest.
src/background.js – Eine background.js-Datei, die in unserem Manifest eingerichtet wurde. Der Code in dieser Datei wird im Hintergrund ausgeführt und überwacht Ereignisse, die Funktionen in der Erweiterung auslösen.
src/content.js – Jedes Skript, das im Kontext der Webseite ausgeführt wird oder die Webseite ändert, wird in ein Inhaltsskript eingefügt.
src/popup.js, static/popup.css und static/popup.html - Diese Dateien steuern das Popup, das angezeigt wird, wenn Sie auf das Erweiterungssymbol klicken.
Lassen Sie uns einige Grundlagen einrichten – öffnen Sie static/manifest.json und ändern Sie den Namen und die Beschreibung in „Screen Reader Image Description Generator“ (oder was auch immer Sie bevorzugen).
Aktivieren Sie die Interaktion mit Webseiten mithilfe eines Inhaltsskripts
Unsere Erweiterung überschreibt Alt-Tags auf der Website, auf der sich der Benutzer befindet. Das bedeutet, dass wir Zugriff auf die HTML-Seite benötigen. Dies können Sie in Chrome-Erweiterungen über Inhaltsskripte tun. Unser Inhaltsskript befindet sich in unserer Datei src/content.js.
Die einfachste Möglichkeit, ein Inhaltsskript einzufügen, besteht darin, dem Manifest ein Feld „scripts“ mit einem Verweis auf eine JS-Datei hinzuzufügen. Wenn Sie ein Inhaltsskript auf diese Weise einrichten, wird das verknüpfte Skript ausgeführt, wenn die Erweiterung geladen wird. In unserem Fall möchten wir jedoch nicht, dass unsere Erweiterung automatisch ausgeführt wird, wenn ein Benutzer die Erweiterung öffnet. Bei einigen Websites sind Alt-Tags für Bilder völlig ausreichend, daher möchten wir den Code nur ausführen, wenn der Benutzer entscheidet, dass dies erforderlich ist.
Wir werden in unserem Popup eine Schaltfläche und in unserem Inhaltsskript ein Konsolenprotokoll hinzufügen, sodass das Inhaltsskript geladen wird, wenn der Benutzer auf die Schaltfläche klickt. Dies können wir bestätigen, indem wir unsere Anweisung in der Chrome-Konsole anzeigen.
Popup.html
<button id="generate-alt-tags-button">Generate image descriptions</button>
src/inhalt.js
console.log('hello console')
Um diesen Schaltflächenklick im Popup mit dem Inhaltsskript zu verbinden, sind sowohl popup.js als auch background.js erforderlich.
In popup.js holen wir uns den Button aus dem DOM und fügen einen Event-Listener hinzu. Wenn ein Benutzer auf den Button klickt, senden wir eine Nachricht, die besagt, dass das Inhaltsskript eingefügt werden soll. Wir nennen die Nachricht „injectContentScript“.
const generateAltTagButton = document.body.querySelector('#generate-alt-tags-button'); generateAltTagButton.addEventListener('click', async () => { chrome.runtime.sendMessage({action: 'injectContentScript'}) });
In background.js haben wir den Code, der Ereignisse überwacht und darauf reagiert. Hier richten wir einen Ereignislistener ein, und wenn die empfangene Nachricht „injectContentScript“ lautet, führt er das Inhaltsskript im aktiven Tab (der aktuellen Webseite des Benutzers) aus.
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.action === 'injectContentScript') { chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { chrome.scripting.executeScript({ target: { tabId: tabs[0].id }, files: ['content.js'] }); }); } });
Der letzte Schritt zur Einrichtung besteht darin, unserem Manifest die Berechtigungen „activeTab“ und „scripting“ hinzuzufügen. Die Berechtigung „scripting“ ist erforderlich, um Inhaltsskripte auszuführen. Wir müssen auch Berechtigungen für die Seiten hinzufügen, in die wir das Skript einfügen. In diesem Fall fügen wir das Skript in die aktuelle Website des Benutzers ein, also in dessen aktiven Tab, und genau das ermöglicht die Berechtigung „activeTab“.
In manifest.json:
"permissions": [ "activeTab", "scripting" ],
An diesem Punkt müssen Sie möglicherweise die Erweiterung aus Chrome entfernen und neu laden, damit sie ordnungsgemäß ausgeführt wird. Sobald sie ausgeführt wird, sollten wir unser Konsolenprotokoll in unserer Chrome-Konsole sehen.
Hier ist ein GitHub-Link für funktionierenden Code für das Repo in dieser Phase .
Seitenbilder sammeln und Test-Alt-Tags einfügen
Unser nächster Schritt besteht darin, mithilfe unserer Inhaltsskriptdatei alle Bilder auf der Seite abzurufen, damit wir diese Informationen für unsere API-Aufrufe zum Abrufen von Bildbeschreibungen bereit haben. Wir möchten auch sicherstellen, dass wir nur Aufrufe für Bilder durchführen, bei denen Beschreibungen hilfreich sind. Einige Bilder sind rein dekorativ und müssen Screenreader mit ihren Beschreibungen nicht verlangsamen. Wenn Sie beispielsweise eine Suchleiste haben, die sowohl die Beschriftung „Suchen“ als auch ein Lupensymbol enthält, bedeutet dies, dass das Alt-Tag eines Bilds auf eine leere Zeichenfolge gesetzt ist oder aria-hidden auf „true“ gesetzt ist, dass das Bild nicht in einen Screenreader aufgenommen werden muss und wir die Generierung einer Beschreibung dafür überspringen können.
Also sammeln wir zunächst in content.js alle Bilder auf der Seite. Ich füge ein console.log hinzu, damit ich schnell bestätigen kann, dass es richtig funktioniert:
const images = document.querySelectorAll("img"); console.log(images)
Dann durchlaufen wir die Bilder und suchen nach Bildern, für die wir einen Alt-Tag generieren müssen. Dazu gehören alle Bilder, die keinen Alt-Tag haben, Bilder, deren Alt-Tag keine leere Zeichenfolge ist, und Bilder, die nicht explizit mit dem Attribut „aria-hidden“ vor Bildschirmleseprogrammen verborgen wurden.
for (let image of images) { const imageHasAltTag = image.hasAttribute('alt'); const imageAltTagIsEmptyString = image.hasAttribute('alt') && image.alt === ""; const isAriaHidden = image.ariaHidden ?? false; if (!imageHasAltTag || !imageAltTagIsEmptyString || !isAriaHidden) { // this is an image we want to generate an alt tag for! } }
Dann können wir eine Testzeichenfolge hinzufügen, um die Alt-Tags festzulegen, damit wir bestätigen können, dass wir eine funktionale Möglichkeit haben, sie festzulegen, bevor wir mit unseren OpenAI-Aufrufen fortfahren. Unsere content.js sieht jetzt so aus:
function scanPhotos() { const images = document.querySelectorAll("img"); console.log(images) for (let image of images) { const imageHasAltTag = image.hasAttribute('alt'); const imageAltTagIsEmptyString = image.hasAttribute('alt') && image.alt === ""; const isAriaHidden = image.ariaHidden ?? false; if (!imageHasAltTag || !imageAltTagIsEmptyString || !isAriaHidden) { image.alt = 'Test Alt Text' } } } scanPhotos()
Wenn wir an diesem Punkt die Chrome-Entwicklertools-Elemente öffnen und auf ein Bild klicken, sollte als Alt-Tag „Test Alt Text“ festgelegt sein.
Ein funktionierendes Repository mit dem aktuellen Stand des Codes finden Sie hier.
OpenAI installieren und Bildbeschreibungen generieren
Um OpenAI verwenden zu können, müssen Sie einen OpenAI-Schlüssel generieren und Ihrem Konto Guthaben hinzufügen. So generieren Sie einen OpenAI-Schlüssel:
Speichern Sie diesen Schlüssel. Halten Sie ihn außerdem geheim. Stellen Sie sicher, dass Sie ihn nicht in öffentliche Git-Repos pushen.
Nun zurück zu unserem Repo. Zuerst wollen wir OpenAi installieren. Führen Sie im Terminal im Projektverzeichnis Folgendes aus:
npm install openai
Jetzt importieren wir OpenAI in content.js, indem wir diesen Code oben in der Datei hinzufügen und Ihren OpenAI-Schlüssel in Zeile 1 einfügen:
const openAiSecretKey = 'YOUR_KEY_GOES_HERE' import OpenAI from "openai"; const openai = new OpenAI({ apiKey: openAiSecretKey, dangerouslyAllowBrowser: true });
„DangerouslyAllowBrowser“ ermöglicht den Aufruf mit Ihrem Schlüssel aus dem Browser. Im Allgemeinen ist dies eine unsichere Vorgehensweise. Da wir dieses Projekt nur lokal ausführen, lassen wir es so, anstatt einen Back-End-Abruf einzurichten. Wenn Sie OpenAI in anderen Projekten verwenden, befolgen Sie unbedingt die Best Practices zur Geheimhaltung des Schlüssels.
Jetzt fügen wir unseren Aufruf hinzu, damit OpenAI Bildbeschreibungen generiert. Wir rufen den Endpunkt zum Erstellen von Chat-Abschlüssen auf ( OpenAI-Dokumente für den Endpunkt zum Erstellen von Chat-Abschlüssen ).
Wir müssen unsere eigene Eingabeaufforderung schreiben und auch die Quell-URL des Bildes angeben ( weitere Informationen zur Eingabeaufforderungstechnik von KI ). Sie können die Eingabeaufforderung beliebig anpassen. Ich habe mich dafür entschieden, die Beschreibungen auf 20 Werke zu beschränken, da OpenAI lange Beschreibungen zurückgab. Außerdem fiel mir auf, dass Logos wie Yelp- oder Facebook-Logos vollständig beschrieben wurden (d. h. „eine große blaue Box mit einem weißen kleinen f darin“), was nicht hilfreich war. Falls es sich um eine Infografik handelt, bitte ich darum, die Wortbegrenzung zu ignorieren und den vollständigen Bildtext weiterzugeben.
Hier ist der vollständige Aufruf, der den Inhalt der ersten KI-Antwort zurückgibt und den Fehler auch an eine „handleError“-Funktion übergibt. Ich habe ein console.log jeder Antwort eingefügt, damit wir schneller Feedback darüber erhalten, ob der Aufruf erfolgreich war oder nicht:
async function generateDescription(imageSrcUrl) { const response = await openai.chat.completions.create({ model: "gpt-4o-mini", messages: [ { role: "user", content: [ { type: "text", text: "Describe this image in 20 words or less. If the image looks like the logo of a large company, just say the company name and then the word logo. If the image has text, share the text. If the image has text and it is more than 20 words, ignore the earlier instruction to limit the words and share the full text."}, { type: "image_url", image_url: { "url": imageSrcUrl, }, }, ], }, ], }).catch(handleError); console.log(response) if (response) { return response.choices[0].message.content;} } function handleError(err) { console.log(err); }
Wir fügen einen Aufruf dieser Funktion in die if-Anweisung ein, die wir zuvor geschrieben haben (wir müssen außerdem am Anfang der scanImages-Funktion ein async-Schlüsselwort hinzufügen, um diesen asynchronen Aufruf einzuschließen):
const imageDescription = await generateDescription(image.src) if (!imageDescription) { return; } image.alt = imageDescription
Hier ist an dieser Stelle ein Link zum vollständigen content.js und Repo.
Erstellen der Benutzeroberfläche
Als Nächstes möchten wir unsere Benutzeroberfläche so gestalten, dass der Benutzer weiß, was passiert, nachdem er auf die Schaltfläche zum Generieren der Tags geklickt hat. Das Laden der Tags dauert einige Sekunden, daher möchten wir eine „Laden“-Meldung anzeigen, damit der Benutzer weiß, dass es funktioniert. Darüber hinaus möchten wir ihn darüber informieren, ob es erfolgreich war oder ob ein Fehler aufgetreten ist. Um die Dinge einfach zu halten, haben wir ein allgemeines Benutzernachrichten-Div im HTML und verwenden dann popup.js, um dem Benutzer dynamisch die entsprechende Nachricht einzufügen, basierend auf dem, was in der Erweiterung passiert.
Durch die Einrichtung der Chrome-Erweiterungen ist unser Inhaltsskript (content.js) von unserem popup.js getrennt und sie können Variablen nicht wie typische JavaScript-Dateien gemeinsam nutzen. Das Inhaltsskript kann dem Popup über die Nachrichtenübermittlung mitteilen, dass die Tags geladen werden oder erfolgreich geladen wurden. Wir haben die Nachrichtenübermittlung bereits verwendet, als wir dem Hintergrundarbeiter mitteilten, dass er das Inhaltsskript einfügen soll, wenn ein Benutzer auf die ursprüngliche Schaltfläche klickt.
Zuerst fügen wir in unserem HTML unter unserer Schaltfläche ein Div mit der ID „user-message“ hinzu. Ich habe auch eine etwas ausführlichere Beschreibung für die erste Nachricht hinzugefügt.
<div id="user-message"> <img src="image-icon.png" width="40" class="icon" alt=""/> This extension uses OpenAI to generate alternative image descriptions for screen readers. </div>
Dann fügen wir in unserem popup.js einen Listener hinzu, der auf alle gesendeten Nachrichten lauscht, die möglicherweise ein Update des Erweiterungsstatus enthalten. Wir schreiben auch etwas HTML, das wir basierend auf dem Statusergebnis einfügen, das wir vom Inhaltsskript zurückerhalten.
const userMessage = document.body.querySelector('#user-message'); chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { renderUI(message.action) } ); function renderUI(extensionState) { generateAltTagButton.disabled=true; if (extensionState === 'loading') { userMessage.innerHTML = '<img src="loading-icon.png" width="50" class="icon" alt=""/> New image descriptions are loading... <br> <br>Please wait. We will update you when the descriptions have loaded.' } else if (extensionState === 'success') { userMessage.innerHTML = '<img src="success-icon.png" width="50" class="icon" alt=""/> New image descriptions have been loaded! <br> <br> If you would like to return to the original image descriptions set by the web page author, please refresh the page.' } else if (extensionState === 'errorGeneric') { userMessage.innerHTML = '<img src="error-icon.png" width="50" class="icon"alt=""/> There was an error generating new image descriptions. <br> <br> Please refresh the page and try again.' } else if (extensionState === 'errorAuthentication') { userMessage.innerHTML = '<img src="error-icon.png" width="50" class="icon"alt=""/> There was an error generating new image descriptions. <br> <br> Your OpenAI key is not valid. Please double check your key and try again.' } else if (extensionState === 'errorMaxQuota') { userMessage.innerHTML = '<img src="error-icon.png" width="50" class="icon"alt=""/> There was an error generating new image descriptions. <br> <br> You\'ve either used up your current OpenAI plan and need to add more credit, or you\'ve made too many requests too quickly. Please check your plan, add funds if needed, or slow down the requests.' } }
In unserem Inhaltsskript definieren wir eine neue Variable namens „extensionState“, die entweder „initial“ (die Erweiterung ist geladen, aber es ist noch nichts passiert), „loading“, „success“ oder „error“ sein kann (wir werden auch einige andere Fehlerzustände basierend auf OpenAI-Fehlermeldungen hinzufügen). Wir aktualisieren auch die Erweiterungsstatusvariable und senden jedes Mal eine Nachricht an popup.js, wenn sich der Status ändert.
let extensionState = 'initial';
Unser Fehlerhandler für wird:
function handleError(err) { if (JSON.stringify(err).includes('401')) { extensionState = 'errorAuthentication' chrome.runtime.sendMessage({action: extensionState}) } else if (JSON.stringify(err).includes('429')) { extensionState = 'errorMaxQuota' chrome.runtime.sendMessage({action: extensionState}) } else { extensionState = 'errorGeneric' chrome.runtime.sendMessage({action: extensionState}) } console.log(err); }
Und innerhalb unserer Funktion „scanPhotos“ setzen wir den Status zu Beginn der Funktion auf „Wird geladen“ und auf „Erfolgreich“, wenn sie vollständig ohne Fehler ausgeführt wird.
async function scanPhotos() { extensionState = 'loading' chrome.runtime.sendMessage({action: extensionState}) const images = document.querySelectorAll("img"); for (let image of images) { const imageHasAltTag = image.hasAttribute('alt'); const imageAltTagIsEmptyString = image.hasAttribute('alt') && image.alt === ""; const isAriaHidden = image.ariaHidden ?? false; if (!imageHasAltTag || !imageAltTagIsEmptyString || !isAriaHidden) { const imageDescription = await generateDescription(image.src) if (!imageDescription) { return; } image.alt = imageDescription } } extensionState = 'success' chrome.runtime.sendMessage({action: extensionState}) }
Beheben verwirrenden Popup-Verhaltens – Beibehalten des Erweiterungsstatus beim Schließen und erneuten Öffnen von Popups
Möglicherweise fällt Ihnen an dieser Stelle auf, dass, wenn Sie Alt-Tags generieren, eine Erfolgsmeldung erhalten und das Popup schließen und erneut öffnen, die ursprüngliche Meldung angezeigt wird, die den Benutzer auffordert, neue Alt-Tags zu generieren. Obwohl die generierten Alt-Tags jetzt im Code enthalten sind!
In Chrome ist jedes Mal, wenn Sie ein Erweiterungs-Popup öffnen, ein brandneues Popup. Es merkt sich nichts, was die Erweiterung zuvor getan hat oder was im Inhaltsskript ausgeführt wird. Wir können jedoch sicherstellen, dass jedes neu geöffnete Popup den genauen Status der Erweiterung wiedergibt, indem wir es beim Öffnen den Erweiterungsstatus aufrufen und überprüfen lassen. Dazu lassen wir ein Popup eine weitere Nachricht übermitteln, die diesmal den Erweiterungsstatus anfordert, und fügen einen Nachrichtenlistener in unsere content.js ein, der auf diese Nachricht wartet und den aktuellen Status zurücksendet.
popup.js
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { chrome.tabs.sendMessage(tabs[0].id, {action: "getExtensionState"}, function(response) { // if the content script hasn't been injected, then the code in that script hasn't been run, and we'll get an error or no response if (chrome.runtime.lastError || !response) { return; } else if (response) { // if the code in content script HAS been injected, we'll get a response which tells us what state the code is at (loading, success, error, etc) renderUI(response.extensionState) } }); });
Inhalt.js
chrome.runtime.onMessage.addListener( function(request, sender, sendResponse) { if (request.action === "getExtensionState") sendResponse({extensionState}); });
Wenn das Inhaltsskript nie ausgeführt wurde (d. h. der Benutzer hat nie auf die Schaltfläche geklickt, um Alt-Tags zu generieren), gibt es keine Erweiterungsstatusvariable oder Ereignislistener. In diesem Fall gibt Chrome als Antwort einen Laufzeitfehler zurück. Wir schließen also eine Überprüfung auf einen Fehler ein und lassen die Standardbenutzeroberfläche unverändert, wenn wir einen erhalten.
Erweiterungszugänglichkeit - Aria-Live, Farbkontrast und Schließen-Schaltfläche
Diese Erweiterung ist für Benutzer von Bildschirmleseprogrammen konzipiert. Jetzt müssen wir sicherstellen, dass sie tatsächlich mit einem Bildschirmleseprogramm verwendet werden kann! Jetzt ist ein guter Zeitpunkt, Ihr Bildschirmleseprogramm einzuschalten und zu prüfen, ob alles gut funktioniert.
Es gibt ein paar Dinge, die wir für die Zugänglichkeit bereinigen möchten. Zunächst möchten wir sicherstellen, dass der gesamte Text einen ausreichend hohen Kontrast aufweist. Für die Schaltfläche habe ich mich entschieden, den Hintergrund auf #0250C5 und die Schriftart auf fettweiß einzustellen. Dies hat ein Kontrastverhältnis von 7,1 und ist sowohl auf AA- als auch auf AAA-Ebene WCAG-konform. Sie können das Kontrastverhältnis für alle Farben, die Sie verwenden möchten, hier im WebAim Contrast Checker überprüfen.
Zweitens stelle ich bei der Verwendung meines Screenreaders fest, dass dieser die Aktualisierungen nicht automatisch vorliest, wenn sich die Benutzernachricht in eine Lade-, Erfolgs- oder Fehlermeldung ändert. Um dies zu beheben, verwenden wir ein HTML-Attribut namens aria-live. Mit Aria-live können Entwickler den Screenreadern mitteilen, dass sie die Benutzer über Änderungen informieren sollen. Sie können aria-live entweder auf assertiv oder höflich einstellen – wenn es auf assertiv eingestellt ist, werden Aktualisierungen sofort vorgelesen, unabhängig davon, ob andere Elemente in der Warteschlange des Screenreaders darauf warten, vorgelesen zu werden. Wenn es auf höflich eingestellt ist, wird die Aktualisierung am Ende von allem vorgelesen, was der Screenreader gerade vorliest. In unserem Fall möchten wir den Benutzer so schnell wie möglich informieren. Also fügen wir dieses Attribut in popup-container, dem übergeordneten Element unseres Benutzernachrichtenelements, hinzu.
<div class="popup-container" aria-live="assertive">
Zu guter Letzt fällt mir auf, dass es beim Verwenden des Screenreaders keine einfache Möglichkeit gibt, das Popup zu schließen. Wenn Sie eine Maus verwenden, klicken Sie einfach irgendwo außerhalb des Popups und es schließt sich, aber ich kann nicht ganz herausfinden, wie man es mit der Tastatur schließt. Daher werden wir unten im Popup eine Schaltfläche „Schließen“ hinzufügen, damit Benutzer es einfach schließen und zur Webseite zurückkehren können.
In popup.html fügen wir hinzu:
<div> <button id="close-button">Close</button> </div>
In popup.js fügen wir dem onclick die Funktion „close“ hinzu:
const closeButton = document.body.querySelector('#close-button'); closeButton.addEventListener('click', async () => { window.close() });
Und das ist es! Wenn Sie Fragen oder Anregungen haben, wenden Sie sich bitte an uns.