Erstellen eines reinen CSS-Tooltips
Wenn Sie einen schlanken Tooltip benötigen und dafür keine JavaScript-Bibliothek einbinden möchten, kann CSS allein diese Aufgabe erstaunlich gut bewältigen. Keine Abhängigkeiten, keine Event Listener – nur ein paar gut platzierte CSS-Regeln.
Dieser Artikel führt Sie durch eine praxisnahe, moderne Implementierung mit Pseudoelementen, data-Attributen und Transitions sowie durch die Aspekte der Barrierefreiheit, die Sie tatsächlich kennen sollten.
Wichtige Erkenntnisse
- Ein reiner CSS-Tooltip lässt sich mit einem
::after-Pseudoelement,content: attr(data-tooltip)und einem:hover- /:focus-visible-Trigger umsetzen. - Verwenden Sie
opacityundvisibility(nichtdisplay), damit der Tooltip sanft ein- und ausgeblendet werden kann. pointer-events: noneverhindert Flackern, indem es verhindert, dass der Tooltip selbst Hover-Events empfängt.- CSS-Tooltips haben echte Grenzen in der Barrierefreiheit – sie erreichen Screenreader nicht zuverlässig, und das Hover-Verhalten ist auf Touch-Geräten inkonsistent.
- Für geschäftskritische UI-Hinweise sollten Sie auf JavaScript, die Popover-API oder korrekte
aria-describedby-Verweise auf sichtbare Elemente zurückgreifen.
Wie ein reiner CSS-Tooltip funktioniert
Die Grundidee ist einfach: Wenden Sie position: relative auf das Trigger-Element an und nutzen Sie dann ein ::after-Pseudoelement als Tooltip-Bubble, das absolut relativ zu seinem Elternelement positioniert wird. Standardmäßig ausblenden und bei :hover und :focus-visible einblenden.
Da Pseudoelemente nicht direkt aus dem DOM lesen können, übergeben Sie den Tooltip-Text über ein data-tooltip-Attribut und beziehen ihn mit content: attr(data-tooltip) ein. Das hält Ihr HTML sauber und vermeidet das Duplizieren von Text in einem versteckten <span>.
Die HTML-Struktur
<button
class="tooltip-trigger"
data-tooltip="Saves your current progress"
>
Save
</button>
Es ist wichtig, ein <button> oder einen Anker (<a>) als Trigger-Element zu verwenden. Diese Elemente sind nativ fokussierbar, was bedeutet, dass Tastaturnutzer sie ohne zusätzlichen Aufwand erreichen können.
Hinweis: Wenn Sie
aria-describedbyverwenden möchten, muss es auf dieideines echten, sichtbaren Elements im DOM verweisen – nicht auf ein Pseudoelement. Da diese Technik::afternutzt, sollten Siearia-describedbyweglassen, es sei denn, Sie rendern den Tooltip-Text zusätzlich in einem echten Element.
Das CSS
.tooltip-trigger {
position: relative;
cursor: pointer;
}
/* Tooltip bubble */
.tooltip-trigger::after {
content: attr(data-tooltip);
position: absolute;
bottom: calc(100% + 8px);
left: 50%;
transform: translateX(-50%);
background-color: #1a1a1a;
color: #fff;
font-size: 0.8rem;
white-space: nowrap;
padding: 5px 10px;
border-radius: 4px;
/* Hidden by default */
opacity: 0;
visibility: hidden;
transition: opacity 0.2s ease, visibility 0.2s ease;
z-index: 10;
pointer-events: none;
}
/* Show on hover and keyboard focus */
.tooltip-trigger:hover::after,
.tooltip-trigger:focus-visible::after {
opacity: 1;
visibility: visible;
}
Warum opacity + visibility statt display?
Der Wechsel zwischen display: none und display: block lässt sich nicht animieren – der Tooltip würde einfach abrupt erscheinen und verschwinden. Mit opacity in Kombination mit visibility: hidden lässt sich der Tooltip sanft einblenden und gleichzeitig im verborgenen Zustand von Zeigerinteraktionen ausnehmen. Die Kombination aus visibility und opacity verhindert außerdem, dass der versteckte Tooltip visuell interaktiv bleibt.
Warum pointer-events: none?
Ohne diese Regel könnte das Tooltip-Bubble selbst einen Hover-Zustand auslösen, wodurch der Tooltip flackert, sobald der Cursor über ihn fährt. pointer-events: none auf dem ::after-Element verhindert das vollständig.
Discover how at OpenReplay.com.
Warum transform: translateX(-50%) zum Zentrieren?
left: 50% verschiebt die linke Kante des Tooltips zur Mitte des Triggers. Die anschließende Verschiebung mit translateX(-50%) zieht ihn um die Hälfte seiner eigenen Breite zurück und zentriert ihn so unabhängig davon, wie breit der Tooltip-Text ist – ganz ohne fest codierte Pixelwerte.
Einschränkungen bei der Barrierefreiheit, die Sie kennen sollten
Ein reiner CSS-Hover-Tooltip hat echte Einschränkungen:
- Screenreader kündigen ihn möglicherweise nicht an. Die
content-Eigenschaft auf einem Pseudoelement wird nicht von allen Screenreadern zuverlässig vorgelesen. Für kritische Informationen sollten Sie diese in der sichtbaren Benutzeroberfläche darstellen oderaria-describedbyverwenden, das auf ein echtes Element verweist. - Das Hover-Verhalten ist auf Touch-Geräten inkonsistent. Reine CSS-Tooltips sollten nicht für wesentliche Informationen herangezogen werden.
- Keine Rolle und kein Live-Region. CSS allein kann die Tooltip-Semantik nicht an assistive Technologien kommunizieren.
Für einfache ergänzende Hinweise auf interaktiven Elementen ist ein CSS-Tooltip in Ordnung. Für alles, was zur Erledigung einer Aufgabe wesentlich ist, sollten Sie JavaScript einsetzen, um Fokus, Ankündigung und ARIA-Zustand zu verwalten.
Ein Blick nach vorn: CSS Anchor Positioning und die Popover-API
CSS Anchor Positioning macht die Platzierung von Tooltips deutlich flexibler – Sie können einen Tooltip an jedes beliebige Element binden, ohne auf position: relative am Elternelement angewiesen zu sein. Die Browserunterstützung für Anchor Positioning ist laut Can I Use inzwischen in modernen Browsern weitgehend verfügbar.
Für umfangreichere interaktive Funktionen lohnt sich ein Blick auf die Popover-API als native Alternative für interaktive schwebende UI-Elemente.
Fazit
Ein reiner CSS-Tooltip, gebaut mit ::after, content: attr(data-tooltip) und einer visibility/opacity-Transition, ist sauber, schnell und ohne Abhängigkeiten. Kombinieren Sie ihn mit :focus-visible für die Tastaturunterstützung, und Sie haben eine solide Grundlage. Seien Sie dabei nur ehrlich darüber, wo CSS-Tooltips an ihre Grenzen stoßen – für alles, was über ergänzende Hinweise hinausgeht, sollten Sie zu JavaScript oder zu einem nativen Plattform-Feature wie der Popover-API greifen.
FAQs
Ja. Die Position wird über die Offset-Eigenschaften am Pseudoelement gesteuert. Verwenden Sie bottom mit calc(100% + 8px), um ihn oberhalb zu platzieren, top mit calc(100% + 8px), um ihn unterhalb zu platzieren, oder right und left für eine horizontale Anordnung. Sie können auch Variantenklassen wie tooltip-bottom oder tooltip-right erstellen, die diese Eigenschaften überschreiben.
Das Hover-Verhalten ist auf Touch-Geräten inkonsistent, daher sollten reine CSS-Tooltips nicht für wesentliche Informationen verwendet werden. Wenn Ihr Tooltip-Inhalt auf mobilen Geräten wichtig ist, rendern Sie ihn in einem echten Element, das per JavaScript gesteuert wird, oder nutzen Sie die Popover-API, die eine robustere Grundlage für interaktive schwebende UI über verschiedene Eingabearten hinweg bietet.
Die Regel white-space: nowrap hält Tooltips auf einer einzigen Zeile, was auf schmalen Bildschirmen überlaufen kann. Ersetzen Sie sie durch eine max-width und erlauben Sie den Zeilenumbruch, zum Beispiel max-width: 240px und white-space: normal. Für eine dynamische Randerkennung benötigen Sie JavaScript oder CSS Anchor Positioning, das in modernen Browsern flexiblere native Positionierungsmöglichkeiten bietet.
Er ist für nicht-essenzielle, ergänzende Hinweise auf fokussierbaren Elementen wie Buttons und Links akzeptabel. Er reicht nicht aus, wenn der Tooltip Informationen enthält, die zur Erledigung einer Aufgabe erforderlich sind, da der Inhalt von Pseudoelementen von Screenreadern nicht zuverlässig angekündigt wird und das Hover-Verhalten auf Touch-Geräten inkonsistent ist. Für kritische Inhalte sollten Sie ein echtes DOM-Element mit aria-describedby und JavaScript-gesteuertem Verhalten verwenden oder die Popover-API in Betracht ziehen.
Truly understand users experience
See every user interaction, feel every frustration and track all hesitations with OpenReplay — the open-source digital experience platform. It can be self-hosted in minutes, giving you complete control over your customer data. . Check our GitHub repo and join the thousands of developers in our community..