Die schlimmsten UX-Anti-Patterns und wie man sie behebt
Die schlimmsten UX-Anti-Patterns in Produktion, mit Vorher-Nachher-Code für Dark Patterns, defekte Toggles und Barrierefreiheit.

Letzte Woche wollte ich auf der Website einer großen Fluggesellschaft meine Cookie-Einstellungen anpassen. Der Button 'Alle akzeptieren' war knallblau und nicht zu übersehen. Der Link 'Einstellungen verwalten'? Grauer Text in 11px, versteckt unter einem Absatz Juristendeutsch. Als ich ihn endlich gefunden hatte, landete ich auf einer Seite mit 47 einzelnen Schaltern, alle standardmäßig aktiviert, und weit und breit kein Button 'Alle ablehnen'. Ich saß da und klickte mindestens eine Minute lang Schalter an, bevor ich aufgab und einfach meine Cookies manuell löschte.
Das ist kein Einzelfall. Das ist die Regel. Schlechtes UX ist nicht nur nervig, es ist feindselig. Und das Schlimmste? Die meisten dieser Anti-Patterns haben denkbar einfache Lösungen, die weniger Zeit kosten als die Dark-Pattern-Verrenkungen, die sie ersetzen. Ich entwickle seit über zehn Jahren Webanwendungen und bin ehrlich verblüfft, dass wir dieses Zeug immer noch ausliefern. Also reden wir über die schlimmsten Übeltäter und wie wir sie ausmerzen.
Dark Patterns, die Nutzer wie Opfer behandeln
Dark Patterns entstehen nicht aus Versehen. Irgendwer saß in einem Meeting, schaute auf die Conversion-Zahlen und entschied, dass Nutzer auszutricksen eine akzeptable Geschäftsstrategie ist. Genau das macht sie so ärgerlich: Sie sind bewusst gewollt.
Confirmshaming: Schuldgefühle als UI-Element
Die kennst du bestimmt. Ein Modal poppt auf und fragt, ob du den Newsletter abonnieren willst. Der Akzeptieren-Button sagt 'Ja, ich will Geld sparen!'. Der Ablehnen-Button sagt 'Nein danke, ich zahle lieber den vollen Preis'. Das ist Confirmshaming, und es ist überall: auf E-Commerce-Seiten, in SaaS-Onboarding-Flows, sogar in manchen Entwicklertools. Es funktioniert bei einem winzigen Prozentsatz der Nutzer und vergrault alle anderen.
Die Lösung ist peinlich einfach: neutrale Formulierungen für beide Optionen.
<!-- BEFORE: Manipulative confirmshaming -->
<div class="modal">
<p>Join 50,000 smart developers!</p>
<button class="btn-primary">Yes, sign me up!</button>
<button class="btn-link text-sm">
No thanks, I don't care about my career
</button>
</div>
<!-- AFTER: Respectful, neutral options -->
<div class="modal">
<p>Get weekly frontend tips — no spam, unsubscribe anytime.</p>
<button class="btn-primary">Subscribe</button>
<button class="btn-secondary">No thanks</button>
</div>
Beachte, dass die Nachher-Version auch auf die aufgeblähten Social-Proof-Angaben verzichtet und ein klares Versprechen zum Thema Spam ergänzt. Respekt schafft mehr Vertrauen als Manipulation. Deine Conversion auf lange Sicht wird es dir danken.
Das Roach Motel: Anmeldung mit einem Klick, Kündigung in sieben Schritten
Anmelden dauert 30 Sekunden. Kündigen erfordert, dass du dich durch Einstellungen > Konto > Abo > Tarif verwalten > Tarif kündigen > Sag uns den Grund > Bist du sicher > Mit dem Kundenservice sprechen > Trotzdem kündigen navigierst. Manche Dienste verlangen immer noch einen Anruf. 2026. Ein Abo, das du mit einem einzigen Klick abgeschlossen hast.
Mir ist egal, was deine Retention-Metriken sagen. Nutzer, die festsitzen, sind keine treuen Kunden, sondern Geiseln, die Rückbuchungen und Ein-Stern-Bewertungen produzieren. Mach die Kündigung genauso einfach wie die Anmeldung.
- Platziere die Kündigungsoption in den Kontoeinstellungen, dort, wo Leute sie erwarten
- Maximal zwei Schritte: 'Bist du sicher?' und dann 'Erledigt, dein Konto ist gekündigt'
- Verstecke den Kündigen-Button nicht hinter einem Link 'Support kontaktieren'
- Wenn du einen Rabatt zur Kundenbindung anbietest, ist das okay, aber mach ihn nicht zu einem Pflichtschritt im Ablauf
- Schick eine Bestätigungs-E-Mail mit einem Reaktivierungslink, statt die Kündigung wie etwas Unumkehrbares wirken zu lassen
Defekte Toggle-Schalter und verwirrende UI-Steuerelemente
Hier ein kleines Experiment: Geh in die Einstellungen deines Handys und zähl, wie viele Schalter du nicht sofort als an oder aus erkennst. Ich warte.
Der mehrdeutige Toggle ist einer der häufigsten UI-Fehler, die mir bei Code-Reviews begegnen. Ein Toggle sollte genau eine Sache vermitteln: den aktuellen Zustand. Ist das an oder aus? Mehr nicht. Trotzdem liefern Entwickler immer wieder Toggles aus, bei denen beide Zustände fast identisch aussehen, bei denen die Farbcodierung mehrdeutig ist oder bei denen der Schalter zeigt, was als Nächstes passiert, statt was gerade passiert.
/* BEFORE: Both states look nearly identical */
.toggle {
width: 48px;
height: 24px;
background: #d1d5db;
border-radius: 12px;
cursor: pointer;
}
.toggle.active {
background: #9ca3af; /* barely different from inactive */
}
/* AFTER: Unmistakable state difference + accessible */
.toggle {
width: 48px;
height: 24px;
background: #d1d5db;
border-radius: 12px;
cursor: pointer;
position: relative;
}
.toggle[aria-checked="true"] {
background: #2563eb; /* strong contrast from inactive */
}
.toggle .label {
font-size: 10px;
font-weight: 600;
color: white;
}
.toggle[aria-checked="true"] .label::after { content: "ON"; }
.toggle[aria-checked="false"] .label::after { content: "OFF"; }
Drei Regeln für Toggles, die niemanden verwirren: unterschiedliche Farben für jeden Zustand (mit genug Kontrast, damit es auch für farbenblinde Nutzer funktioniert), ein Textlabel im oder neben dem Schalter und korrekte aria-checked-Attribute, damit Screenreader den Zustand ansagen können. Wer sich allein auf Farbe verlässt, hat in einem Zug UX und Barrierefreiheit verbockt.
Hör auf, native Formularelemente neu zu erfinden
Ich prüfe viele Frontend-PRs, und ein Muster bringt mich zur Weißglut: selbstgebaute Dropdowns, die die Tastaturnavigation kaputt machen. Ein Entwickler verbringt zwei Tage damit, ein schickes Auswahlmenü von Grund auf aus einem Haufen divs und Click-Handlern zu bauen. In der Demo sieht es super aus. Dann versucht ein Nutzer, sich durch ein Formular zu tabben, landet beim eigenen Dropdown, und nichts passiert. Keine Unterstützung für Pfeiltasten. Keine Typeahead-Suche. Funktioniert nicht mit Passwortmanagern. Bricht auf dem Handy.
Dabei erledigt das native <select>-Element, oder eine gut getestete Bibliothek wie Radix UI oder Headless UI, all das ohne Mehraufwand. Die HTML-Popover-API und das <selectlist>-Element werden inzwischen gut von Browsern unterstützt. Nutz sie. Deinen Nutzern ist egal, ob dein Dropdown eine eigene Animation hat. Ihnen ist wichtig, dass es funktioniert.
Barrierefreiheits-Anti-Patterns, die echte Nutzer ausschließen
Barrierefreiheit ist kein nettes Extra. Es ist kein Feature, das man im nächsten Sprint nachschiebt. Weltweit leben über eine Milliarde Menschen mit einer Form von Behinderung, und der WebAIM Million Report stellt regelmäßig fest, dass 96 % und mehr der million meistbesuchten Websites nachweisbare WCAG-Verstöße haben. Das sind keine obskuren Randfälle, sondern kaputte Buttons, fehlende Labels und Bilder ohne Alt-Text.
Das sehe ich am häufigsten:
- Bilder ohne Alt-Text: Screenreader sagen nur 'Bild' und machen weiter
- Kontrastverhältnisse unter 4,5:1: Text wird für sehbehinderte Nutzer unlesbar
- Keine Tastaturnavigation: Wenn man sich nicht durch deine App tabben kann, sind Tastatur- und Switch-Nutzer ausgesperrt
- Fokusfallen in Modals: Der Nutzer öffnet einen Dialog und kommt ohne Maus nicht mehr heraus
- Fehlende Formularlabels: Der Screenreader weiß nicht, wofür ein Eingabefeld gedacht ist
- Automatisch abspielende Videos ohne Pause-Button: desorientierend für Nutzer mit Gleichgewichtsstörungen
Der schnellste Gewinn ist, automatisierte Barrierefreiheitsprüfungen in deine CI-Pipeline einzubauen. Sie finden nicht alles, denn automatisierte Tools erkennen vielleicht 30–40 % der Probleme. Aber sie fangen das Offensichtliche ab, bevor es ausgeliefert wird.
// BEFORE: No accessibility testing at all
test('homepage loads', async ({ page }) => {
await page.goto('/');
await expect(page.locator('h1')).toBeVisible();
});
// AFTER: Accessibility violations fail the build
import AxeBuilder from '@axe-core/playwright';
test('homepage loads and is accessible', async ({ page }) => {
await page.goto('/');
await expect(page.locator('h1')).toBeVisible();
const a11yResults = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa'])
.analyze();
expect(a11yResults.violations).toEqual([]);
});
Fünf Minuten Einrichtung. Läuft bei jedem PR. Findet fehlende Alt-Texte, kaputte ARIA-Rollen, unzureichenden Kontrast und Dutzende andere Fehler automatisch. Es gibt keine Ausrede, das nicht zu tun.
Kognitive Überlastung: Die Einstellungsseite aus der Hölle
Das menschliche Arbeitsgedächtnis hält gleichzeitig etwa vier bis sieben Elemente. Das ist kein Vorschlag, sondern eine harte kognitive Grenze. Wenn deine Oberfläche 200 Optionen ohne Hierarchie auf einer Seite abkippt, gibst du Nutzern keine Kontrolle. Du gibst ihnen Entscheidungslähmung.
Ich habe einmal die Einstellungen in einem Projektmanagement-Tool gezählt, das wir bei der Arbeit benutzt haben. 347 Optionen. Eine Seite. Keine Suche. Keine Gruppierung über vage Kategorien wie 'Allgemein' und 'Erweitert' hinaus. Die Hälfte des Teams hatte nie eine einzige Einstellung geändert, weil die Seite so überwältigend war, dass sie sie sofort wieder schlossen.
Die Lösung ist Progressive Disclosure. Zeig die fünf Einstellungen, die Leute tatsächlich ändern. Pack alles andere in klar beschriftete, aufklappbare Abschnitte. Füg eine Suchleiste hinzu. Und um Himmels willen: Stell sinnvolle Standardwerte bereit, damit die meisten Nutzer die Einstellungsseite gar nicht erst brauchen.
Wenn deine Einstellungsseite eigene Dokumentation braucht, ist die Einstellungsseite das Problem.
Benachrichtigungsflut erzieht Nutzer dazu, alles zu ignorieren
Wenn jedes Ereignis eine Benachrichtigung auslöst (ein Teamkollege ist einem Channel beigetreten, jemand hat mit einem Emoji reagiert, ein Deployment ist fertig, ein Kalendertermin beginnt in 30 Minuten), lernen Nutzer, alle zu ignorieren. Dein Benachrichtigungssystem ist zu weißem Rauschen geworden. Die eine kritische Meldung, die wirklich zählt? Begraben unter 47 ungelesenen Benachrichtigungen.
Konservative Standardwerte sind die Antwort. Neue Nutzer sollten nur kritische Benachrichtigungen bekommen. Weniger dringende Dinge bündelst du in einem täglichen Digest. Und immer, wirklich immer, lässt du Nutzer direkt in der Benachrichtigung selbst stummschalten oder anpassen, nicht auf einer versteckten Einstellungsseite drei Klicks entfernt.
Langsame UI ist kaputte UI: Performance als UX-Problem
Ein Button, der zwei Sekunden zum Reagieren braucht, ist nicht langsam. Er ist kaputt. Nutzer denken nicht 'Ah, der Server verarbeitet meine Anfrage.' Sie denken 'Ist mein Klick angekommen?' und klicken noch einmal. Jetzt hast du doppelte Übermittlungen, verwirrte Zustände und einen Nutzer, der deiner App nicht mehr traut.
Alles über 100 ms fühlt sich träge an. Alles über einer Sekunde reißt den Gedankengang des Nutzers ab. Trotzdem liefern wir weiterhin mehrere Megabyte große JavaScript-Bundles, render-blockierende Drittanbieter-Skripte und Layout-Verschiebungen, die Leute auf das falsche Element klicken lassen. Die Lösung ist nicht kompliziert. Sie erfordert nur, dass dir etwas daran liegt.
// BEFORE: User clicks, waits 2 seconds, nothing happens
async function handleLike(postId: string) {
const result = await fetch(`/api/posts/${postId}/like`, {
method: 'POST',
});
if (result.ok) {
setLikeCount(prev => prev + 1); // UI updates after network round-trip
}
}
// AFTER: Optimistic update — UI responds instantly
function handleLike(postId: string) {
// Update UI immediately
setLikeCount(prev => prev + 1);
// Sync with server in background
startTransition(async () => {
const result = await fetch(`/api/posts/${postId}/like`, {
method: 'POST',
});
if (!result.ok) {
// Rollback only on failure
setLikeCount(prev => prev - 1);
toast.error('Something went wrong. Try again.');
}
});
}
Optimistische Updates, Skeleton-Screens statt Spinner, lazy geladenes nicht-kritisches JavaScript und das Monitoring der Core Web Vitals als echte Metriken, nicht als nachträglicher Gedanke. Das sind keine fortgeschrittenen Techniken. Das sind Grunderwartungen.
Mobile UX-Anti-Patterns, die einfach nicht sterben wollen
Mobile hat seine eigene Kategorie von UX-Sünden, vor allem weil Entwickler weiterhin auf einem brandneuen iPhone testen und das dann als erledigt betrachten.
Touch-Ziele, die chirurgische Präzision verlangen
Apples Richtlinien verlangen mindestens 44 x 44 CSS-Pixel für Touch-Ziele. WCAG 2.2 sieht das genauso. Trotzdem sehe ich immer noch 20-Pixel-Schließen-Buttons in Modals, winzige Links, die im Footer dicht aneinandergedrängt sind, und Icon-Buttons, die auf dem Handy praktisch nicht zu treffen sind. Für Nutzer mit motorischen Einschränkungen ist es noch schlimmer.
/* BEFORE: Tiny, frustrating touch targets */
.close-btn {
width: 20px;
height: 20px;
font-size: 12px;
}
.footer-links a {
padding: 2px 4px;
font-size: 11px;
}
/* AFTER: Actually tappable elements */
.close-btn {
min-width: 44px;
min-height: 44px;
display: flex;
align-items: center;
justify-content: center;
}
.footer-links a {
padding: 12px 8px;
font-size: 14px;
/* spacing between adjacent targets */
margin: 4px 0;
}
Vollbild-Interstitials, die Inhalte blockieren
Du tippst auf ein Suchergebnis. Die Seite lädt. Bevor du auch nur ein Wort lesen kannst, verlangt ein Vollbild-Modal deine E-Mail-Adresse. Du hast den Inhalt noch gar nicht gesehen. Warum sollte man da abonnieren?
Google bestraft aufdringliche Interstitials in den Suchrankings seit 2017. Trotzdem halten sie sich, weil irgendwo jemand auf ein Dashboard schaut, das eine E-Mail-Erfassungsquote von 2 % zeigt, und das als Erfolg verbucht, während er die 40 % Absprungrate ignoriert, die dadurch entsteht. Nutz Inline-Banner oder Bottom Sheets. Warte, bis der Nutzer tatsächlich mit deinem Inhalt interagiert hat, bevor du irgendetwas abfragst. Ein Leser, der drei Artikel fertig gelesen hat, abonniert gern. Ein Leser, der dreimal unterbrochen wurde, geht und kommt nie wieder.
Wie man eine UX-Qualitätskultur aufbaut (und nicht nur einzelne Bugs behebt)
Anti-Patterns einzeln zu beheben ist notwendig, aber nicht ausreichend. Wenn dein Prozess sie immer wieder hervorbringt, brauchst du einen besseren Prozess. Das funktioniert tatsächlich:
- Füg axe-core zu deiner CI-Pipeline hinzu: automatisierte a11y-Prüfungen bei jedem PR
- Mach UX-Review zum Teil des Code Reviews, nicht zu einem separaten Prozess nur für Design
- Teste mit 5 echten Nutzern, bevor du größere Features ausliefert. 5 Nutzer decken etwa 85 % der Usability-Probleme auf
- Verfolge Abschlussraten und Fehlerraten bei Aufgaben, nicht nur Seitenaufrufe und Verweildauer
- Nutze ein Design-System mit fertigen, barrierefreien Komponenten, damit einzelne Entwickler nicht dieselben Interaktionsprobleme immer wieder von Null lösen
- Nutz dein eigenes Produkt konsequent: Wenn der Entwickler der Einstellungsseite sie täglich selbst verwenden muss, wird sie schnell repariert
Die beste UX-Verbesserung, die ich je gemacht habe, begann damit, dass ich unseren eigenen Checkout-Prozess auf dem Handy ausprobieren wollte und um 23 Uhr wütende Nachrichten in den Produkt-Channel tippte.
Jedes Anti-Pattern in diesem Artikel hat eine einfache Lösung. Keine davon erfordert brandneue Technologie oder massive Neugestaltungen. Sie erfordern, dass dir etwas daran liegt. Fang heute mit einem Fix an. Mach diese Woche ein Barrierefreiheits-Audit. Teste diesen Monat mit einem echten Nutzer. Gutes UX geht nicht um große Gesten, sondern darum, konsequent Respekt vor den Nutzern über kurzfristige Metriken zu stellen. Die Lücke zwischen Software, die Leute ertragen, und Software, die Leute lieben, ist kleiner, als du denkst. Es sind einfach tausend kleine Entscheidungen, gut getroffen.


