Es würde mich überraschen, wenn Sie noch nie einen Geister-Button 👻 gesehen hätten. Sie wissen schon, die mit einem transparenten Hintergrund, der sich beim Hovern mit einer Vollfarbe füllt. Smashing Magazine hat einen ganzen Artikel, der sich mit dieser Idee beschäftigt. In diesem Artikel werden wir einen Geister-Button erstellen, aber das wird der einfache Teil sein. Der lustige und knifflige Teil wird die Animation des Füllens dieses Geister-Buttons sein, sodass der Hintergrund sich in die Richtung füllt, aus der der Cursor darüber schwebt.
Hier ist ein grundlegender Start für einen Geister-Button
Siehe den Pen
Basic Ghost Button 👻 von Jhey (@jh3y)
auf CodePen.
In den meisten Fällen hat background-color eine transition zu einer Vollfarbe. Es gibt Designs, bei denen sich der Button für einen visuellen Reiz von links nach rechts, von oben nach unten usw. füllt. Hier zum Beispiel von links nach rechts
Siehe den Pen
Directional filling Ghost Button 👻 von Jhey (@jh3y)
auf CodePen.
Hier gibt es einen kleinen Detailkritikpunkt in Bezug auf die Benutzererfahrung (UX). Es fühlt sich falsch an, wenn man gegen die Füllrichtung hovert. Betrachten Sie dieses Beispiel. Der Button füllt sich von links, während Sie von rechts darüber schweben.

Es ist besser, wenn sich der Button von unserem anfänglichen Hoverpunkt aus füllt.

Wie können wir dem Button also ein Richtungsbewusstsein verleihen? Ihr erster Instinkt mag darin bestehen, eine JavaScript-Lösung zu verwenden, aber wir können stattdessen etwas mit CSS und etwas zusätzlichem Markup erstellen.
Für diejenigen, die dem Lager TL;DR angehören, hier sind einige reine CSS-Geister-Buttons mit Richtungsbewusstsein!
Siehe den Pen
Pure CSS Ghost Buttons w/ Directional Awareness ✨👻😎 von Jhey (@jh3y)
auf CodePen.
Lassen Sie uns dieses Ding Schritt für Schritt aufbauen. Der gesamte Code ist in dieser CodePen-Sammlung verfügbar.
Erstellen einer Grundlage
Beginnen wir mit der Schaffung der Grundlagen unseres Geister-Buttons. Das Markup ist unkompliziert.
<button>Boo!</button>
Unsere CSS-Implementierung wird CSS-Custom-Properties nutzen. Diese erleichtern die Wartung. Sie ermöglichen auch eine einfache Anpassung durch Inline-Eigenschaften.
button {
--borderWidth: 5;
--boxShadowDepth: 8;
--buttonColor: #f00;
--fontSize: 3;
--horizontalPadding: 16;
--verticalPadding: 8;
background: transparent;
border: calc(var(--borderWidth) * 1px) solid var(--buttonColor);
box-shadow: calc(var(--boxShadowDepth) * 1px) calc(var(--boxShadowDepth) * 1px) 0 #888;
color: var(--buttonColor);
cursor: pointer;
font-size: calc(var(--fontSize) * 1rem);
font-weight: bold;
outline: transparent;
padding: calc(var(--verticalPadding) * 1px) calc(var(--horizontalPadding) * 1px);
transition: box-shadow 0.15s ease;
}
button:hover {
box-shadow: calc(var(--boxShadowDepth) / 2 * 1px) calc(var(--boxShadowDepth) / 2 * 1px) 0 #888;
}
button:active {
box-shadow: 0 0 0 #888;
}
Wenn wir alles zusammenfügen, erhalten wir das hier
Siehe den Pen
Ghost Button Foundation 👻 von Jhey (@jh3y)
auf CodePen.
Großartig! Wir haben einen Button und einen Hover-Effekt, aber noch keine Füllung. Das machen wir als Nächstes.
Hinzufügen einer Füllung
Dazu erstellen wir Elemente, die den gefüllten Zustand unseres Geister-Buttons darstellen. Der Trick besteht darin, diese Elemente mit clip-path zu beschneiden und zu verstecken. Wir können sie beim Hovern über den Button offenbaren, indem wir den clip-path animieren.

Sie müssen mit dem übergeordneten Button übereinstimmen. Unsere CSS-Variablen werden hierbei sehr hilfreich sein.
Auf den ersten Gedanken hin hätten wir Pseudo-Elemente verwenden können. Es wird jedoch nicht genügend Pseudo-Elemente für jede Richtung geben. Außerdem würden sie die Zugänglichkeit beeinträchtigen ... aber dazu später mehr.
Beginnen wir damit, eine einfache Füllung von links nach rechts beim Hovern hinzuzufügen. Zuerst fügen wir einen Span hinzu. Dieser Span benötigt den gleichen Textinhalt wie der Button.
<button>Boo!
<span>Boo!</span>
</button>
Jetzt müssen wir unseren Span mit dem Button ausrichten. Unsere CSS-Variablen werden hier die Hauptarbeit leisten.
button span {
background: var(--buttonColor);
border: calc(var(--borderWidth) * 1px) solid var(--buttonColor);
bottom: calc(var(--borderWidth) * -1px);
color: var(--bg, #fafafa);
left: calc(var(--borderWidth) * -1px);
padding: calc(var(--verticalPadding) * 1px) calc(var(--horizontalPadding) * 1px);
position: absolute;
right: calc(var(--borderWidth) * -1px);
top: calc(var(--borderWidth) * -1px);
}
Schließlich schneiden wir den Span ausser Sicht und fügen eine Regel hinzu, die ihn beim Hovern durch Aktualisieren des Clips wieder sichtbar macht. Das Definieren eines Übergangs gibt ihm den letzten Schliff.
button span {
--clip: inset(0 100% 0 0);
-webkit-clip-path: var(--clip);
clip-path: var(--clip);
transition: clip-path 0.25s ease, -webkit-clip-path 0.25s ease;
// ...Remaining div styles
}
button:hover span {
--clip: inset(0 0 0 0);
}
Siehe den Pen
Ghost Button w/ LTR fill 👻 von Jhey (@jh3y)
auf CodePen.
Hinzufügen von Richtungsbewusstsein
Wie können wir also Richtungsbewusstsein hinzufügen? Wir brauchen vier Elemente. Jedes Element ist dafür verantwortlich, einen Eintrittspunkt für den Hover zu erkennen. Mit clip-path können wir den Buttonbereich in vier Segmente unterteilen.

:hover-SegmenteFügen wir vier Spans zu einem Button hinzu und positionieren sie so, dass sie den Button ausfüllen.
<button>
Boo!
<span></span>
<span></span>
<span></span>
<span></span>
</button>
button span {
background: var(--bg);
bottom: calc(var(--borderWidth) * -1px);
-webkit-clip-path: var(--clip);
clip-path: var(--clip);
left: calc(var(--borderWidth) * -1px);
opacity: 0.5;
position: absolute;
right: calc(var(--borderWidth) * -1px);
top: calc(var(--borderWidth) * -1px);
z-index: 1;
}
Wir können jedes Element ansprechen und mit CSS-Variablen einen Clip und eine Farbe zuweisen.
button span:nth-of-type(1) {
--bg: #00f;
--clip: polygon(0 0, 100% 0, 50% 50%, 50% 50%);
}
button span:nth-of-type(2) {
--bg: #f00;
--clip: polygon(100% 0, 100% 100%, 50% 50%);
}
button span:nth-of-type(3) {
--bg: #008000;
--clip: polygon(0 100%, 100% 100%, 50% 50%);
}
button span:nth-of-type(4) {
--bg: #800080;
--clip: polygon(0 0, 0 100%, 50% 50%);
}
Cool. Um das zu testen, ändern wir die Deckkraft beim Hovern.
button span:nth-of-type(1):hover,
button span:nth-of-type(2):hover,
button span:nth-of-type(3):hover,
button span:nth-of-type(4):hover {
opacity: 1;
}

Ups. Hier gibt es ein Problem. Wenn wir ein Segment betreten und hovern, aber dann über ein anderes Segment hovern, ändert sich die Füllrichtung. Das wird komisch aussehen. Um das zu beheben, können wir beim Hovern einen z-index und clip-path setzen, damit ein Segment den Raum ausfüllt.
button span:nth-of-type(1):hover,
button span:nth-of-type(2):hover,
button span:nth-of-type(3):hover,
button span:nth-of-type(4):hover {
--clip: polygon(0 0, 100% 0, 100% 100%, 0 100%);
opacity: 1;
z-index: 2;
}
Siehe den Pen
Pure CSS Directional Awareness w/ clip-path 👻 von Jhey (@jh3y)
auf CodePen.
Alles zusammenfügen
Wir wissen, wie man die Füllanimation erstellt, und wir wissen, wie man die Richtung erkennt. Wie können wir die beiden zusammenfügen? Verwenden Sie den Geschwister-Kombinator!
Dadurch können wir beim Hovern eines Richtung-Segments ein bestimmtes Füllelement offenbaren.
Zuerst aktualisieren wir das Markup.
<button>
Boo!
<span></span>
<span></span>
<span></span>
<span></span>
<b>Boo!</b>
<b>Boo!</b>
<b>Boo!</b>
<b>Boo!</b>
</button>
Nun können wir das CSS aktualisieren. Bezüglich unserer Links-nach-rechts-Füllung können wir die gleiche Formatierung wiederverwenden. Wir müssen nur für jedes Element einen spezifischen clip-path einstellen. Ich habe die Reihenfolge ähnlich wie bei einigen Eigenschaftswerten gewählt. Das erste Kind ist oben, das zweite ist rechts und so weiter.
button b:nth-of-type(1) {
--clip: inset(0 0 100% 0);
}
button b:nth-of-type(2) {
--clip: inset(0 0 0 100%);
}
button b:nth-of-type(3) {
--clip: inset(100% 0 0 0);
}
button b:nth-of-type(4) {
--clip: inset(0 100% 0 0);
}
Das letzte Stück ist die Aktualisierung des clip-path für das entsprechende Element beim Hovern über das gekoppelte Segment.
button span:nth-of-type(1):hover ~ b:nth-of-type(1),
button span:nth-of-type(2):hover ~ b:nth-of-type(2),
button span:nth-of-type(3):hover ~ b:nth-of-type(3),
button span:nth-of-type(4):hover ~ b:nth-of-type(4) {
--clip: inset(0 0 0 0);
}
Tada! Wir haben einen reinen CSS-Geister-Button mit Richtungsbewusstsein.
Siehe den Pen
Pure CSS Ghost Button w/ Directional Awareness 👻 von Jhey (@jh3y)
auf CodePen.
Barrierefreiheit (Accessibility)
In seinem jetzigen Zustand ist der Button nicht barrierefrei.

Diese zusätzlichen Elemente helfen nicht viel, da ein Screenreader den Inhalt viermal wiederholt. Wir müssen diese Elemente vor einem Screenreader verstecken.
<button>
Boo!
<span></span>
<span></span>
<span></span>
<span></span>
<b aria-hidden="true">Boo!</b>
<b aria-hidden="true">Boo!</b>
<b aria-hidden="true">Boo!</b>
<b aria-hidden="true">Boo!</b>
</button>
Keine wiederholten Inhalte mehr.
Siehe den Pen
Accessible Pure CSS Ghost Button w/ Directional Awareness 👻 von Jhey (@jh3y)
auf CodePen.
Das ist alles!
Mit etwas zusätzlichem Markup und etwas CSS-Trickerei können wir Geister-Buttons mit Richtungsbewusstsein erstellen. Verwenden Sie einen Präprozessor oder erstellen Sie eine Komponente in Ihrer App, und Sie müssen nicht auch den gesamten HTML-Code schreiben.
Hier ist eine Demo, die Inline-CSS-Variablen verwendet, um die Button-Farbe zu steuern.
Siehe den Pen
Pure CSS Ghost Buttons w/ Directional Awareness ✨👻😎 von Jhey (@jh3y)
auf CodePen.
Erwähnenswert ist, dass
div-Elemente keine gültigen Kinder für dasbutton-Element sind (obwohl sie meiner Meinung nach in modernen Browsern keine Fehler verursachen).Ja, guter Punkt! Obwohl es keine Fehler verursachte, habe ich den Artikel aktualisiert, sodass gültige Inline-Elemente innerhalb des
buttonverwendet werden.Es verstößt auch gegen die HTML-Spezifikationen, divs in Buttons zu setzen
Ja, guter Punkt! Ich habe das Markup aktualisiert, um nur Inline-Elemente innerhalb des
buttonzu verwenden.Ich habe vor etwa 6 Jahren ein „richtungsbewusstes Hover“ gemacht, daher ist es gut, eine moderne Version mit clip-path zu sehen :). Gut gemacht.
Meiner (https://codepen.io/paulobrien/details/kKaJq) war ein bisschen unübersichtlich, funktionierte aber ziemlich gut.
Ich mag diesen Ansatz besser wegen der verbesserten Browserunterstützung. Ich frage mich jedoch, wie es sich verhalten würde, wenn man das Seitenverhältnis oder die Abmessungen des Buttons nicht garantieren kann.
Cool, aber beim Hovern weg bewegt es sich in die gleiche Richtung wie beim Hovern.
calc() funktioniert für die Position links oben für divs nicht ... zumindest bei mir, ich habe es versucht.
Ich muss eine bestimmte Höhe für div festlegen, dann würde der Hover funktionieren, ansonsten füllt er den gesamten vertikalen Raum aus.
Ich liebe es, wie CSS mich nach all den Jahren immer noch überrascht :D
Viel Arbeit für einen subtilen Effekt, aber extrem clever. Ich liebe es (auch wenn ich zögern würde, es zu implementieren).
Wahrscheinlich ausserhalb des Rahmens, aber die logische Weiterentwicklung davon erfordert, dass das Mouseleave auch richtungsabhängig ist :)
Ich stimme Thibaud vollkommen zu :D Ich glaube, es sollte möglich sein. Ich habe noch keine Lösung ausprobiert.
sieht verdächtig ähnlich aus wie mein Pen https://codepen.io/srekoble/pen/zQXGbZ?editors=1100 vor fast 3 Monaten, aus Spass :)
Ha, ich bin mir bei der Wortwahl nicht sicher. Ich würde nicht so weit gehen wie „verdächtig“
Ich hatte diesen Pen allerdings noch nicht gesehen. Danke fürs Teilen!
Aber füllt sich der Button oder leert er sich?
Es ist erwähnenswert, dass der vorherige CSS-Tricks-Artikel über richtungsbewusste Hover-Effekte (einschließlich CSS) eine bessere Unterstützung bietet: https://css-tricks.de/direction-aware-hover-effects/
So eine kreative Idee, danke für Ihre Zeit und Mühe!