Animationen für geteilten Text erstellen

Ein grundlegender Überblick über das Erstellen von Animationen mit Buchstaben und Wörtern.

In diesem Beitrag möchte ich darüber nachdenken, wie sich geteilte Textanimationen und -interaktionen für das Web lösen lassen, die minimal, barrierefrei und browserübergreifend funktionieren. Demo ansehen

Demo

Falls du lieber ein Video hast, findest du hier eine YouTube-Version dieses Beitrags:

Überblick

Animationen mit geteiltem Text können fantastisch sein. Wir werden in diesem Beitrag kaum an der Oberfläche des Animationspotenzials kratzen, aber es bietet eine Grundlage, auf der wir aufbauen können. Das Ziel ist die schrittweise Animation. Der Text sollte standardmäßig lesbar sein. Die Animation wird oben eingeblendet. Bewegungseffekte für aufgeteilten Text können extravagant und potenziell störend sein. Daher bearbeiten wir HTML nur dann oder wenden Bewegungsstile an, wenn der Nutzer mit Bewegung einverstanden ist.

Im Folgenden erhalten Sie einen allgemeinen Überblick über den Workflow und die Ergebnisse:

  1. Vorbereiten bedingter Variablen für reduzierte Bewegung für CSS und JS
  2. Bereiten Sie Dienstprogramme für geteilten Text in JavaScript vor.
  3. Orchestrieren Sie die Bedingungen und Dienstprogramme beim Seitenaufbau.
  4. Schreiben Sie CSS-Übergänge und -Animationen für Buchstaben und Wörter.

Hier ist eine Vorschau der bedingten Ergebnisse, die wir verwenden werden:

Screenshot der Chrome-Entwicklertools mit geöffnetem Bereich „Elemente“ und reduzierter Bewegung auf „Reduzieren“ und h1 wird ungetrennt angezeigt
Nutzer bevorzugt eingeschränkte Bewegung: Der Text ist lesbar bzw. nicht aufgeteilt

Möchte ein Nutzer möglichst wenig Bewegung, lassen wir das HTML-Dokument unverändert und erstellen keine Animation. Wenn Bewegung in Ordnung ist, fahren wir fort und zerlegen sie. Hier sehen Sie eine Vorschau des HTML-Codes, nachdem JavaScript den Text nach Buchstaben aufgeteilt hat.

Screenshot der Chrome-Entwicklertools mit geöffnetem Bereich „Elemente“ und reduzierter Bewegung auf „Reduzieren“ und h1 wird ungetrennt angezeigt
Keine Bewegung für den Nutzer; der Text wurde in mehrere <span>-Elemente aufgeteilt

Bewegungsbedingungen vorbereiten

Die praktisch verfügbare Medienabfrage @media (prefers-reduced-motion: reduce) wird in diesem Projekt über CSS und JavaScript verwendet. Diese Medienabfrage ist die primäre Bedingung für die Entscheidung, ob Text aufgeteilt werden soll. Die CSS-Medienabfrage wird verwendet, um Übergänge und Animationen zurückzuhalten, während die JavaScript-Medienabfrage verwendet wird, um die HTML-Manipulation zu unterdrücken.

CSS-Bedingung vorbereiten

Ich habe PostCSS verwendet, um die Syntax von Medienabfragen Ebene 5 zu aktivieren, wo ich einen booleschen Wert für Medienabfragen in einer Variablen speichern kann:

@custom-media --motionOK (prefers-reduced-motion: no-preference);

JS-Bedingung vorbereiten

In JavaScript bietet der Browser eine Möglichkeit, Medienabfragen zu prüfen. Ich habe destruktururing verwendet, um das boolesche Ergebnis aus der Medienabfrageprüfung zu extrahieren und umzubenennen:

const {matches:motionOK} = window.matchMedia(
  '(prefers-reduced-motion: no-preference)'
)

Ich kann dann auf motionOK testen und das Dokument nur ändern, wenn der Nutzer die Reduzierung von Bewegungen nicht angefordert hat.

if (motionOK) {
  // document split manipulations
}

Ich kann denselben Wert mithilfe von PostCSS prüfen, um die @nest-Syntax aus Verschachtelungsentwurf 1 zu aktivieren. So kann ich die gesamte Logik der Animation sowie ihre Stilanforderungen für die übergeordneten und untergeordneten Elemente an einem Ort speichern:

letter-animation {
  @media (--motionOK) {
    /* animation styles */
  }
}

Mit der benutzerdefinierten PostCSS-Eigenschaft und einem booleschen JavaScript-Wert können wir den Effekt unter bestimmten Bedingungen aktualisieren. Das bringt uns zum nächsten Abschnitt, in dem ich das JavaScript für die Umwandlung von Zeichenfolgen in Elemente aufschlüssele.

Text wird geteilt

Textbuchstaben, Wörter, Zeilen usw. können nicht einzeln mit CSS oder JS animiert werden. Um diesen Effekt zu erzielen, brauchen wir Boxen. Wenn wir jeden Buchstaben animieren wollen, muss jeder Buchstabe ein Element sein. Wenn wir jedes Wort animieren möchten, muss jedes Wort ein Element sein.

  1. JavaScript-Dienstfunktionen zum Aufteilen von Strings in Elemente erstellen
  2. Nutzung dieser Dienstprogramme orchestrieren

Dienstprogrammfunktion „Buchstaben teilen“

Wir empfehlen, mit einer Funktion zu beginnen, die einen String annimmt und jeden Buchstaben in einem Array zurückgibt.

export const byLetter = text =>
  [...text].map(span)

Mit der Spread-Syntax von ES6 war dies wirklich eine schnelle Aufgabe.

Dienstprogrammfunktion „Wörter aufteilen“

Ähnlich wie beim Aufteilen von Buchstaben verwendet diese Funktion einen String und gibt jedes Wort in einem Array zurück.

export const byWord = text =>
  text.split(' ').map(span)

Mit der split()-Methode für JavaScript-Strings können wir angeben, welche Zeichen als Trennzeichen verwendet werden sollen. Ich ging an ein leeres Leerzeichen weiter, was auf eine Trennung zwischen Wörtern hinweist.

Felder zum Dienstprogramm machen

Für den Effekt sind Felder für jeden Buchstaben erforderlich und in diesen Funktionen wird map() mit einer span()-Funktion aufgerufen. Hier ist die Funktion span().

const span = (text, index) => {
  const node = document.createElement('span')

  node.textContent = text
  node.style.setProperty('--index', index)

  return node
}

Beachten Sie, dass eine benutzerdefinierte Eigenschaft namens --index mit der Arrayposition festgelegt wird. Die Felder für die Buchstabenanimationen sind großartig, aber ein Index für die Verwendung in CSS ist eine scheinbar kleine Ergänzung mit einer großen Wirkung. Besonders auffällig ist dabei die herausragende Wirkung. Wir werden --index verwenden können, um Animationen für einen gestaffelten Look zu verschieben.

Fazit zu Versorgungsunternehmen

Das abgeschlossene Modul splitting.js:

const span = (text, index) => {
  const node = document.createElement('span')

  node.textContent = text
  node.style.setProperty('--index', index)

  return node
}

export const byLetter = text =>
  [...text].map(span)

export const byWord = text =>
  text.split(' ').map(span)

Als Nächstes importieren und verwenden Sie die Funktionen byLetter() und byWord().

Split-Orchestrierung

Wenn die Dienstprogramme zur Aufteilung betriebsbereit sind, bedeutet die Zusammenfassung Folgendes:

  1. Finden, welche Elemente aufgeteilt werden sollen
  2. Teilen und Ersetzen von Text durch HTML

Danach übernimmt CSS die Animation und animiert die Elemente / Felder.

Elemente suchen

Ich habe Attribute und Werte verwendet, um Informationen über die gewünschte Animation und die Aufteilung des Texts zu speichern. Ich habe diese deklarativen Optionen in den HTML-Code eingefügt. Das Attribut split-by wird in JavaScript verwendet, um Elemente zu finden und Felder für Buchstaben oder Wörter zu erstellen. Das Attribut letter-animation oder word-animation wird in CSS verwendet, um Elemente auf untergeordnete Elemente auszurichten und Transformationen und Animationen anzuwenden.

Hier ist ein Beispiel für HTML, das die beiden Attribute veranschaulicht:

<h1 split-by="letter" letter-animation="breath">animated letters</h1>
<h1 split-by="word" word-animation="trampoline">hover the words</h1>

Elemente aus JavaScript suchen

Ich habe die CSS-Selektor-Syntax für die Attributpräsenz verwendet, um die Liste der Elemente zu erfassen, deren Text aufgeteilt werden soll:

const splitTargets = document.querySelectorAll('[split-by]')

Elemente aus CSS finden

Außerdem habe ich den Selektor für die Attributpräsenz in CSS verwendet, um allen Buchstabenanimationen dieselben Basisstile zu geben. Später verwenden wir den Attributwert, um spezifischere Stile hinzuzufügen und so einen Effekt zu erzielen.

letter-animation {
  @media (--motionOK) {
    /* animation styles */
  }
}

Text wird geteilt

Für jedes der aufgeteilten Ziele in JavaScript teilen wir den Text basierend auf dem Wert des Attributs auf und ordnen jeden String einer <span> zu. Wir können dann den Text des Elements durch die Felder ersetzen, die wir erstellt haben:

splitTargets.forEach(node => {
  const type = node.getAttribute('split-by')
  let nodes = null

  if (type === 'letter') {
    nodes = byLetter(node.innerText)
  }
  else if (type === 'word') {
    nodes = byWord(node.innerText)
  }

  if (nodes) {
    node.firstChild.replaceWith(...nodes)
  }
})

Fazit der Orchestrierung

index.js abgeschlossen:

import {byLetter, byWord} from './splitting.js'

const {matches:motionOK} = window.matchMedia(
  '(prefers-reduced-motion: no-preference)'
)

if (motionOK) {
  const splitTargets = document.querySelectorAll('[split-by]')

  splitTargets.forEach(node => {
    const type = node.getAttribute('split-by')
    let nodes = null

    if (type === 'letter')
      nodes = byLetter(node.innerText)
    else if (type === 'word')
      nodes = byWord(node.innerText)

    if (nodes)
      node.firstChild.replaceWith(...nodes)
  })
}

Der JavaScript-Code könnte in folgendem Englisch gelesen werden:

  1. Importieren Sie einige Hilfsprogrammfunktionen.
  2. Prüfe, ob Bewegungen für diesen Nutzer in Ordnung sind. Andernfalls unternimmst du nichts.
  3. Für jedes Element, das aufgeteilt werden soll.
    1. Teile sie danach ein, wie sie aufgeteilt werden sollen.
    2. Ersetzen Sie Text durch Elemente.

Animationen und Übergänge teilen

Die oben genannte Aufteilungsdokumentmanipulation hat gerade eine Vielzahl von möglichen Animationen und Effekten mit CSS oder JavaScript freigeschaltet. Am Ende dieses Artikels finden Sie einige Links, die Ihnen helfen können, die Aufteilung zu erleichtern.

Jetzt ist es an der Zeit zu zeigen, was du damit alles machen kannst. Ich stelle Ihnen 4 CSS-gesteuerte Animationen und Übergänge vor. 🤓

Teilen von Buchstaben

Als Grundlage für die Split-Letter-Effekte fand ich das folgende CSS hilfreich. Ich platziere alle Übergänge und Animationen hinter der Motion-Medienabfrage und weise jedem neuen untergeordneten Buchstaben span eine Anzeigeeigenschaft sowie einen Stil für die Verwendung von Leerräumen zu:

[letter-animation] > span {
  display: inline-block;
  white-space: break-spaces;
}

Der Stil der Leerzeichen ist wichtig, damit die Spannen, die nur ein Leerzeichen sind, nicht durch die Layout-Engine minimiert werden. Kommen wir nun zu den zustandsorientierten, lustigen Dingen.

Beispiel für getrennte Buchstaben

In diesem Beispiel werden CSS-Übergänge zum Effekt „Text teilen“ verwendet. Bei Übergängen brauchen wir Stadien, zwischen denen die Suchmaschine animiert werden kann, und ich habe drei Stadien ausgewählt: keinen Mouseover, den Mauszeiger in einem Satz und den Mauszeiger auf einen Buchstaben.

Wenn der Nutzer den Mauszeiger auf den Satz bzw. den Container bewegt, verkleinere ich alle untergeordneten Elemente, als ob der Nutzer sie weiter weggestoßen hätte. Wenn die Nutzenden die Maus über einen Buchstaben bewegen, bringe ich ihn nach vorne.

@media (--motionOK) {
  [letter-animation="hover"] {
    &:hover > span {
      transform: scale(.75);
    }

    & > span {
      transition: transform .3s ease;
      cursor: pointer;

      &:hover {
        transform: scale(1.25);
      }
    }
  }
}

Beispiel für geteilte Buchstaben

In diesem Beispiel wird eine vordefinierte @keyframe-Animation verwendet, um jeden Buchstaben unendlich zu animieren. Mithilfe des benutzerdefinierten Inline-Attributindex wird ein gestaffelter Effekt erzeugt.

@media (--motionOK) {
  [letter-animation="breath"] > span {
    animation:
      breath 1200ms ease
      calc(var(--index) * 100 * 1ms)
      infinite alternate;
  }
}

@keyframes breath {
  from {
    animation-timing-function: ease-out;
  }
  to {
    transform: translateY(-5px) scale(1.25);
    text-shadow: 0 0 25px var(--glow-color);
    animation-timing-function: ease-in-out;
  }
}

Wörter aufteilen

Flexbox hat in diesen Beispielen für mich als Containertyp funktioniert und die ch-Einheit als gesunde Lückenlänge genutzt.

word-animation {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 1ch;
}
Flexbox-Entwicklertools, die Lücken zwischen Wörtern anzeigen

Beispiel für aufgeteilte Wörter mit Übergang

In diesem Übergangsbeispiel verwende ich wieder den Mauszeiger. Da der Effekt zuerst den Inhalt verbirgt, bis der Mauszeiger darauf bewegt wird, habe ich darauf geachtet, dass die Interaktion und die Stile nur angewendet werden, wenn das Gerät den Mauszeiger darüber bewegen kann.

@media (hover) {
  [word-animation="hover"] {
    overflow: hidden;
    overflow: clip;

    & > span {
      transition: transform .3s ease;
      cursor: pointer;

      &:not(:hover) {
        transform: translateY(50%);
      }
    }
  }
}

Beispiel für geteilte Wörter animiert

In diesem Animationsbeispiel verwende ich wieder CSS @keyframes, um eine gestaffelte unendliche Animation für einen regelmäßigen Textabsatz zu erstellen.

[word-animation="trampoline"] > span {
  display: inline-block;
  transform: translateY(100%);
  animation:
    trampoline 3s ease
    calc(var(--index) * 150 * 1ms)
    infinite alternate;
}

@keyframes trampoline {
  0% {
    transform: translateY(100%);
    animation-timing-function: ease-out;
  }
  50% {
    transform: translateY(0);
    animation-timing-function: ease-in;
  }
}

Fazit

Jetzt, wo du weißt, wie ich es gemacht habe, wie würdest du es tun?! 🙂

Diversifizieren wir unsere Ansätze und lernen Sie alle Möglichkeiten kennen, wie wir das Web nutzen können. Erstelle einen Codepen oder veranstalte deine eigene Demo, twittere mich mit ihr und ich füge sie unten zum Abschnitt „Community-Remixe“ hinzu.

Quelle

Weitere Demos und Inspiration

Community-Remixe