Geister-Buttons mit Richtungsbewusstsein in CSS

Avatar of Jhey Tompkins
Jhey Tompkins am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

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.

Hover fühlt sich falsch an 👎

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

Hover fühlt sich gut an 👍

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.

Kind-Element mit 50% Clip

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.

Vier :hover-Segmente

Fü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;
}
So nah dran

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.

Das zusätzliche Markup wird von VoiceOver gelesen.

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.