Hier kommt ein Erfahrungsbericht unserer Webentwickler Fabian und Lennart, in dem sie erzählen, wie sie eine Website mit dem WordPress-Theme Divi auf Barrierefreiheit optimieren:
Wir nutzen Divi schon seit Jahren hier bei Hansolu und sind sehr happy über die vielfältigen Möglichkeiten, die der Visual Builder bietet. Als wir uns allerdings vermehrt mit dem Thema Barrierefreiheit beschäftigt haben, ist uns schnell aufgefallen, dass Divi nicht die erforderlichen Boardmittel hat, um eine Website barrierefrei zu gestalten. Auf Nachfrage bei dem Divi Support verwiesen sie uns auf ein Plugin und dass die Entwickler zurzeit an der V5 von Divi arbeiten und Features nachgereicht werden, sobald Divi 5 Live ist.
In diesem Beitrag beschreiben wir die Probleme und wie wir sie gelöst haben. Die meisten Lösungen sind eher für Entwickler gedacht, da wir in Ergänzung zu Plugins eigenen Code geschrieben haben. Diesen haben wir hier auch zur Verfügung gestellt.
Häufigste Probleme bei der Barrierefreiheit mit Divi
Das hier sind aus unserer Sicht die Hauptprobleme bei der Optimierung einer Website mit Divi auf Barrierefreiheit:
Fehlende Tastaturnavigation
- Divi bietet keinen Tastaturfokus und die Navigation lässt sich auch nicht mit der Tastatur bedienen
Fehlende ARIA Unterstützung
- Divi bietet keine Einstellungsmöglichkeiten an, um ARIA Attribute zu hinterlegen in Modulen.
Viewport Meta Scalable No
- Von Haus aus lässt Divi das Reinzoomen auf Mobile nicht zu.
Keyboard Traps sind möglich, Module nicht bedienbar
- Wenn man sich mit der Tastatur über die Website bewegt, kann man viele Module nicht bedienen oder man landet in sogenannten Keyboardtraps – also man kommt hier nicht mehr weiter ohne die Bedienung mit der Maus.
Navigation Namen problematisch, Suche Englisch getextet
- Die Menünamen sind auf Englisch eingestellt und auch die Suchfunktion lässt sich nicht anpassen.
Wie wir Divi barrierefrei machen
Plugins von Divi Module
Wir haben zuerst auf eine reine scriptbasierte Umsetzung gesetzt. Haben dann aber festgestellt, dass hier zu viele individuelle Anpassungen gemacht werden müssen, wenn man im Content einer Website arbeitet. Daher haben wir uns entschieden, eine Plugin-Lösung zu verwenden. Hier sind wir dann auf die Plugins von Divi Module gestoßen. Diese bieten mehrere Plugins zur Optimierung der Barrierefreiheit an. Zum einen Divi Accessibility Tweaks und Accessibility Attributes. Diese werden auch vom Divi Support empfohlen, um die Barrierefreiheit zu erreichen.
Plugin: Divi Accessibility Tweaks
Tastaturnavigation
Divi Module fügt eine Funktion hinzu, um den Tastaturfokus hervorzuheben. Den Rahmen kann man farblich anpassen.
Website Navigation
Divi Module fügt einige Verbesserungen in den vorhandenen Modulen von Divi ein, damit diese barrierefrei werden. Für die Eindeutschung benötigt man hier allerdings noch ein paar Anpassungen, wie weiter unten erklärt wird.
Module
Die Divi Module sind standardmäßig nicht durch die Tastatur bedienbar und nicht für Screenreader Nutzer zu verstehen. Für diese Module werden die fehlenden Attribute ergänzt und eine Tastaturbedienung hinzugefügt.
Menü Optimierung
Das Divi Menü wird mit den Einstellungen mit der Tastatur bedienbar.
Links – Bypass Block
Um direkt auf den Inhalt springen zu können, bietet Divi Accessibility Tweaks auch die Anpassung der Sprunglinks an. Diese können auch farblich angepasst werden.
Plugin: Divi Accessibility Attributes
Für die Optimierung auf der Content Ebene kann man mit dem Plugin bei Sektionen und Modulen nun ARIA Attribute setzen, welche zum Beispiel für bestimmte Bilder oder Buttons wichtig sind.
Module Einstellungen
Hier können bestimmte ARIA Attribute aktiviert und deaktiviert werden. Je nachdem, wofür sie benötigt werden.
Divi Elemente – Main
Divi hat standardmäßig keine Main Sektion, sondern nur Header und Footer. Dieses wird jetzt um ein role=“main“ ergänzt.
ARIA Hidden
Divi Module fügt bei den angegebenen Klassen oder IDs das ARIA Attribut „Hidden“ hinzu, damit diese Elemente nicht vom Screenreader vorgelesen werden.
ARIA Link
Divi Module fügt bei den angegebenen Klassen oder IDs das ARIA Attribut „Link“ hinzu.
ARIA Button
Divi Module fügt bei den angegebenen Klassen oder IDs das ARIA Attribut „Button“ hinzu. WICHTIG: in der Standard-Ausführung werden hier auch die Divi Button (.et-pb-button) als Button deklariert. Diese sind aber als Link zu verstehen. Daher empfehlen wir, diese Einstellung zu löschen.
ARIA Required
Divi Module fügt bei den angegebenen Klassen oder IDs das ARIA Attribut „Required“ hinzu.
Tab Index
Divi Module fügt bei den angegebenen Klassen oder IDs einen Tab Index von 0 hinzu.
Divi Modle Anpassungen mit Visual Builder
Divi Module liefert eine umfangreiche Bearbeitungsmöglichkeit im Visual Builder. Hier kann man in jedem Modul, Sektion oder Zeile über den Erweitert-Reiter Einstellungen für die ARIA Attribute hinterlegen.
Scriptlösungen für Divi Barrierefreiheit – Zusätzlich zu Divi Module
Die Scripte haben wir über ein Child Theme eingebunden und diese in einer code.js über die functions.php eingesetzt.
Mobiles Menü, aria labels für die empty links
setTimeout(() => {
$('a.sub-menu-toggle').each(function () {
$(this).attr({
'aria-label': 'Submenü öffnen',
'role': 'button'
})
});
}, 400);
Suche im Divi Standard-Menü barrierefrei machen
const searchIcon = $('#et_search_icon');
$('input.et-search-field').attr({
'placeholder': 'Suche...',
'title': "Webseite durchsuchen"
});
$('#searchsubmit_header').remove();
searchIcon.on('click', function () {
const nav = $(this).parent('#et_top_search').siblings('#top-menu-nav').find('> ul > li > a');
nav.each(function () {
$(this).attr('tabindex', '-1');
})
$('#et_search_icon').attr('tabindex', '-1');
$('span.et_close_search_field').on('click', function () {
$('#et_search_icon').attr('tabindex', '0');
nav.each(function () {
$(this).removeAttr('tabindex');
})
});
$('#page-container').on('click', function (e) {
if ($(e.target).parents('#main-header').length === 0) {
$('#et_search_icon').attr('tabindex', '0');
$('input.et-search-field').attr('tabindex', '-1');
$('.et_close_search_field').attr('tabindex', '-1');
nav.each(function () {
$(this).removeAttr('tabindex');
})
$('#et_search_icon').focus();
// listener entfernen
$('#page-container').off('click');
}
})
});
Lightbox in Divi barrierefrei machen
let lightbox_clicked;
$('a.et_pb_lightbox_image').on('keydown', function (e) {
if (e.keyCode === 13) {
lightbox_clicked = $(this).find('img');
const observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.target.classList.contains('mfp-removing')) {
setTimeout(function () {
lightbox_clicked.closest('a.et_pb_lightbox_image').focus();
$('body').children().removeAttr('inert');
}, 1000);
}
});
});
setTimeout(() => {
observer.observe(document.querySelector('.mfp-wrap'), {
attributes: true,
attributeFilter: ['class']
});
}, 100);
const close = $('.mfp-close');
close.removeAttr('title');
close.attr('aria-label', 'Schließen (Esc)');
}
});
$('a.et_pb_lightbox_image img').on('click', function (e) {
lightbox_clicked = $(this);
const observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.target.classList.contains('mfp-removing')) {
setTimeout(function () {
lightbox_clicked.closest('a.et_pb_lightbox_image').focus();
$('body').children().removeAttr('inert');
}, 1000);
}
});
});
setTimeout(() => {
observer.observe(document.querySelector('.mfp-wrap'), {
attributes: true,
attributeFilter: ['class']
});
}, 100);
const close = $('.mfp-close');
close.removeAttr('title');
close.attr('aria-label', 'Schließen (Esc)');
});
Links in neuem Tab öffnen
$('a').each(function () {
if ($(this).attr('target') === '_blank') {
const ariaLabel = $(this).attr('aria-label');
if (ariaLabel) {
$(this).attr('aria-label', ariaLabel + ', Link öffnet in einem neuen Tab');
} else {
const text = $(this).text();
$(this).attr('aria-label', text + ', Link öffnet in einem neuen Tab');
}
}
})
Sekundäre Navigation barrierefrei machen
function makeSecondaryMenuAccesible() {
const secondaryMenu = $("#et-secondary-nav");
const secondaryMenuLinks = secondaryMenu.find("a");
const etInfo = $("#et-info");
etInfo.attr({
role: "navigation",
"aria-label": "Kontaktinformationen",
});
const linksInEtInfo = $("#et-info a");
linksInEtInfo.attr("role", "menuitem");
linksInEtInfo.each(function () {
var linkText = $(this).text();
$(this).removeAttr("aria-hidden");
$(this).attr("aria-label", "Kontaktieren Sie uns über " + linkText);
});
secondaryMenu.attr("role", "menubar");
secondaryMenuLinks.each(function (index) {
$(this).attr("role", "menuitem");
});
secondaryMenu.find("li").each(function () {
$(this).attr("role", "none");
});
// const icon = $('<span class="dashicons dashicons-universal-access"></span>');
// firstLinkInSecondaryMenu.addClass("secondary-menu-link-with-icon");
// firstLinkInSecondaryMenu.prepend(icon);
const emailLink = secondaryMenu.find('a[href^="mailto:"]');
const phoneLink = secondaryMenu.find('a[href^="tel:"]');
const textInEmailLink = emailLink.text();
const textInPhoneLink = phoneLink.text();
emailLink.attr("aria-label", "Kontaktieren Sie uns per E-Mail: " + textInEmailLink);
phoneLink.attr("aria-label", "Rufen Sie uns an: " + textInPhoneLink);
emailLink.addClass("secondary-menu-link-with-icon");
phoneLink.addClass("secondary-menu-link-with-icon");
const emailIcon = $('<span class="dashicons dashicons-email-alt"></span>');
const phoneIcon = $(
'<span class="et-pb-icon phoneicon-sec-nav"></span>'
);
emailLink.prepend(emailIcon);
phoneLink.prepend(phoneIcon);
}
Diese Funktion fügt dem Logo ARIA-Atrribute hinzu
/**
* Diese Funktion fügt dem Logo ARIA-Atrr. hinzu
* @return void
*/
function initLogoARIA() {
const logo = $("#logo");
logo.attr({
"alt": "",
"aria-hidden": "true",
"role": "presentation",
});
// find out if the slug is /
const locationHref = window.location.href;
const parentA = logo.parent("a");
parentA.attr("aria-label", "Zur Startseite navigieren");
const parentAHref = parentA.attr("href");
if (locationHref === parentAHref) {
parentA.attr("aria-current", "page");
}
}
Alt-Texte von dekorativen Elementen entfernen
/**
* Diese Funktion entfernt Alt-Texte von dekorativen Elementen
* @return void
*/
function removeAltTextFromDecorativeElements() {
const decorativeElements = $(".et_pb_module.deko").find("img");
decorativeElements.each(function () {
$(this).attr({
alt: "",
role: "presentation",
});
});
}
Hover State zu Button hinzufügen, wenn sie im Fokus sind
function callHoverEventWhenFocusOnButton() {
const buttons = $('.et_pb_button');
buttons.on('focusin', function () {
$(this).addClass('btn-hover');
});
buttons.on('focusout', function () {
$(this).removeClass('btn-hover');
});
}
Lightbox Elemente
Lightbox Galerie Elemente öffnen sich in einem Lightbox-Modal, in welchem dann eine interaktive Galerie mit mehreren Bildern sichtbar werden. Somit muss das Modal-Muster der W3C Web Accessibility Initiative (WAI) erfüllt werden. Das Modal-Muster der WIÁI erfüllen wir mit eigenem jQuery-Code, welche im Wesentlichen wie folgt aufgebaut ist.
function lightbox() {
const lb = $('.et_pb_lightbox_image');
lb.each(function () {
const link = $(this);
const img_in_link = link.find('img');
img_in_link.on('click', function () {
observeMfpContent(link);
});
});
}
// Funktion zum Beobachten des .mfp-content Elements
function observeMfpContent($itemToFocus) {
setTimeout(() => {
const $mfpContent = $(".mfp-content");
const $children = $('body').children();
$children.each(function () {
if (!($(this).hasClass('mfp-wrap'))) {
$(this).attr('inert', 'true')
}
})
if ($mfpContent.length) {
const $closeButton = $(".mfp-close");
function setFocus() {
setTimeout(() => {
$itemToFocus.focus();
}, 1000);
$closeButton.off("click", setFocus);
$(document).off("keydown", escKeyHandler);
$children.removeAttr('inert');
}
function escKeyHandler(e) {
if (e.keyCode === 27) {
setFocus();
}
}
$closeButton.on("click", setFocus);
$(document).on("keydown", escKeyHandler);
}
}, 1000);
}
WpForms
Bei erforderlichen Feldern fügt WPForms ein Sternchen ein, welches dann jedes Mal von Screenreadern vorgelesen wird, obwohl die HTML-Semantik der Felder bereits die Erforderlichkeit deklariert. Daher schreiben wir in die Label zusätzlich (erforderlich) oder (optional), um sehgeschwächten und kognitiv beeinträchtigten Menschen auch ohne Screenreader die Nutzung zu erleichtern. Die Standard-Sternchen verstecken wir mit jQuery-Code vor Screenreader und Hilfstechnologien.
$('.wpforms-required-label').each(function () {
$(this).attr('aria-hidden', 'true');
});
PDF Links ARIA Label
Um bei Links, welche eine PDF-Datei öffnen, den Screenreader-Nutzern verständlich zu machen, dass sich eine PDF-Datei öffnet, bauen wir den vorhandenen Linktext und zusätzlich in einem aria-label den Hinweis „PDF öffnet in neuem Tab“.
$(document).ready(function() {
$('a').each(function() {
var href = $(this).attr('href');
if (href && href.endsWith('.pdf')) {
var linkText = $(this).text().trim();
var ariaLabel = linkText ? linkText + " PDF öffnet in neuem Tab" : "PDF öffnet in neuem Tab";
$(this).attr('aria-label', ariaLabel);
$(this).attr('target', '_blank');
}
});
});
Übersetzungen von englischen Strings
Wir mussten einige Teile des Divi Module Textes für Deutsch übersetzen, da die Suche falsche Begriffe enthält. Das haben wir über das Plugin Loco Translate gelöst, indem wir eine deutsche Übersetzungsdatei angelegt haben.
Dazu haben wir Loco Translate installiert und im Plugin Ordner unter „Divi-Modules – Accessibility Bundle“ unter dem Reiter „Erweitert“ ein weiteres Sprachpaket hinzugefügt. Hier ist einmal die Konfiguration des Sprach-Sets.
Danach konnten wir eine deutsche Datei anlegen und die fehlenden Übersetzungen anlegen. Diese waren wichtig für die Namen der Menüs und die Bezeichnung der Suche. Hier einmal unsere eingefügten Übersetzungen: Primary Menu = Hauptmenü, Primary Mobile Menu = Mobiles Hauptmenü, Close = Schließen, Close search form = Suchfeld schließen, Open search form = Suchfeld öffnen, Search = Website durchsuchen, Search for: = Website durchsuchen:, Secondary Menu = Menü Kontaktmöglichkeiten, Secondary Mobile Menu = Mobiles Menü Kontaktmöglichkeiten.
Divi & Barrierefreiheit: Unsere Einschätzung
Die Erstellung einer barrierefreien Website ist mit den Divi Module Modulen erheblich einfacher geworden – und mit den angewendeten Lösungen lassen sich robuste barrierefreie Websites entwickeln. Zusätzliche Module, die durch andere Plugins eingesetzt werden, müssen natürlich immer geprüft werden.