Dies ist eine Sammlung einiger meiner Lieblingstricks, denen ich im Laufe meiner Arbeit an der Website CSS-Tricks begegnet bin. Die meisten davon stammen nicht von mir, sondern von Leuten, die weit klüger sind als ich. Hier stelle ich sie vor und erkläre den Trick, wie ich ihn sehe. Während einige von ihnen vielleicht "nützlicher" sind als andere, gibt es von allen viel zu lernen, egal ob Sie die Technik direkt anwenden oder nicht.

Ein Trick, der in diesem Buch nicht explizit behandelt wird, ist der Trick der "CSS-Zeichnungen". Ich habe im Laufe der Jahre Tausende davon gesehen, besonders wenn ich Leute beobachte, die auf CodePen spielen und lernen, einer weiteren Website, bei der ich mithelfe. Sie reichen von Leuten, die ein Smiley-Gesicht mit Kreisen erstellen, die sie mit border-radius: 50%, Hintergrundfarben und absoluter Positionierung bauen, bis hin zu echten Trompe-l'œil-Meisterwerken, die mit Farbverläufen, Schatten und jeder erdenklichen CSS-Technik erstellt werden. Warum? fragen die Leute unweigerlich. Warum CSS dafür verwenden, wenn man SVG verwenden könnte? Oder Zeichensoftware verwenden, die speziell für die Erstellung von Kunst entwickelt wurde? Warum nicht? wäre vielleicht die bessere Frage. Kunst muss nicht durch die Grenzen dessen gefesselt sein, was jemand als effizienter erachtet. Aber wichtiger noch, und die Ironie ist hier dick, ich finde, dass die Leute, die diese Art von CSS-Zeichnungen und Erkundungen machen, wie auch immer "unpraktisch", am Ende auch in "praktischen" Dingen bessere CSS-Praktiker werden.

Also genießen Sie diese CSS-Tricks, Freunde! Ich hoffe, sie bringen Ihnen ein wenig Freude, und selbst wenn Sie sie nicht sofort in Ihrer Arbeit anwenden können, werden sie Sie durch Ihr Wissen zu einem geschickteren CSS-Entwickler machen, vielleicht ohne dass Sie es überhaupt merken.

Kapitel 1 Squigglevision

Squigglevision ein (echter!) Begriff für Animation, bei der die Linien zu zappeln scheinen, selbst wenn das Objekt/die Szene in Ruhe ist. Es ist Teil des ikonischen Looks von Shows wie Dr. Katz, erinnern Sie sich?

Ein ziemlich einzigartiger Look! Er ist sogar patentiert. Aber das Patent spricht von fünf bearbeiteten Bildern und deren Anzeige in "schneller Abfolge". Wikipedia

Um die Linienoszillationseffekte zu erzeugen, die Squigglevision charakterisieren, schleifen die Animatoren von Tom Snyder Productions fünf leicht unterschiedliche Zeichnungen in einer Sequenz namens Flic.

Im Web würden wir, wenn wir fünf (oder mehr) Bilder in schneller Abfolge animieren müssten, dies wahrscheinlich mit einer step()-basierten @keyframes-Animation und einem Sprite-Sheet tun. Hier ist ein großartiges Beispiel dafür von simuari, das genau zeigt, wie es funktioniert, mit dem Sprite-Sheet oben (10 Bilder kombiniert zu 1) und der Animation darunter.

Aber das ist viel Arbeit! Es gibt eine Möglichkeit, das Wackeln, Schwingen und Zucken bei jedem Element zu erreichen, ohne eine Menge einzelner Bilder von Hand erstellen und spezielle Keyframes in speziellen Größen anfertigen zu müssen, damit es funktioniert.

Der Trick?

Schnell iterierte SVG-Turbulenfilter

Whaaaat? Ja, das ist so cool.

Diesen Trick habe ich von David Khourshid gelernt, der eine wunderbare Demo erstellt hat, Alex the CSS Husky (siehe unten), bei der das Zucken nicht einmal das Hauptmerkmal der Demo war! David sagt, er habe den Trick von Lucas Bebber in einer anderen Demo, die ich unten einbetten werde, gelernt.

(Das ist meine geforkte Version für eine winzige Firefox-Korrektur: Man kann SVG in Firefox nicht display: none; setzen.)

So funktioniert ein einzelner SVG-Turbulenfilter. Zuerst deklarieren Sie ihn mit etwas Inline-<svg>

<svg display="none">
  <defs>
    <filter id="turb">
      <feTurbulence baseFrequency="0.3" numOctaves="2" />
      <feDisplacementMap in="SourceGraphic" scale="20" />
    </filter>
  </defs>
</svg>

Dann können Sie ihn auf jedes HTML-Element anwenden, wie folgt

.filter {
  filter: url("#turb");
}

Hier ist ein Vorher/Nachher

Das ist eine ziemlich extreme Menge an Turbulenzen. Versuchen Sie, sie auf baseFrequency="0.003" zu reduzieren und sehen Sie eine viel subtilere Version. Hmmm – sieht fast aus wie ein ganz leichtes Zucken, nicht wahr?

Der Trick besteht darin, nur ein kleines bisschen zu verwenden, mehrere verschiedene zu machen und dann dazwischen zu animieren.

Hier sind fünf verschiedene Turbulenfilter, alle leicht unterschiedlich voneinander, mit verschiedenen IDs

<svg>
  <filter id="turbulence-1">
    <feTurbulence type="fractalNoise" baseFrequency="0.001" numOctaves="2" data-filterId="3" />
    <feDisplacementMap xChannelSelector="R" yChannelSelector="G" in="SourceGraphic" scale="25" />
  </filter>

  <filter id="turbulence-2">
    <feTurbulence type="fractalNoise" baseFrequency="0.0015" numOctaves="2" data-filterId="3" />
    <feDisplacementMap xChannelSelector="R" yChannelSelector="G" in="SourceGraphic" scale="25" />
  </filter>

  <filter id="turbulence-3">
    <feTurbulence type="fractalNoise" baseFrequency="0.002" numOctaves="2" data-filterId="3" />
    <feDisplacementMap xChannelSelector="R" yChannelSelector="G" in="SourceGraphic" scale="25" />
  </filter>

  <filter id="turbulence-4">
    <feTurbulence type="fractalNoise" baseFrequency="0.0025" numOctaves="2" data-filterId="3" />
    <feDisplacementMap xChannelSelector="R" yChannelSelector="G" in="SourceGraphic" scale="25" />
  </filter>

  <filter id="turbulence-5">
    <feTurbulence type="fractalNoise" baseFrequency="0.003" numOctaves="2" data-filterId="3" />
    <feDisplacementMap xChannelSelector="R" yChannelSelector="G" in="SourceGraphic" scale="25" />
  </filter>

</svg>

Und eine CSS-Keyframe-Animation, um zwischen ihnen zu animieren

@keyframes squigglevision {
  0% {
    filter: url("#turbulence-1");
  }
  25% {
    filter: url("#turbulence-2");
  }
  50% {
    filter: url("#turbulence-3");
  }
  75% {
    filter: url("#turbulence-4");
  }
  100% {
    filter: url("#turbulence-5");
  }
}

Die Sie auf alles anwenden können, was Sie zum Zucken bringen wollen

.squiggle {
  animation: squigglevision 0.4s infinite alternate;
}

Das ist ziemlich genau das, was mit Alex the CSS Husky passiert, nur dass die Filter noch entspannter sind.

Hier ist Lucas' ursprüngliche Demo

Kapitel 2 Harte Stopp-Verläufe

Hier ist ein Beispiel für "traditionelle" Verläufe, bei denen Farben langsam von einer zur anderen überblenden.

Diese werden alle mit CSS-Verläufen erstellt.

Es gibt ein Konzept namens Farbstopps mit Verläufen, die es Ihnen ermöglichen, die Position zu steuern, an der Farben von einer zur nächsten zu überblenden beginnen. Hier ist ein Beispiel, bei dem die erste Farbe den größten Teil des Weges beibehalten wird

Hier ist der Trick: Die Farbstopps können immer näher zusammenrücken und sich sogar am selben Punkt befinden. Das bedeutet, dass anstatt dass die Farbe überhaupt überblendet, eine Farbe stoppt und die andere an einem exakten Punkt beginnen kann. Hier ist eine visuelle Erklärung von konvergierenden Farbstopps

Das untere Beispiel sieht fast so aus, als wären es zwei separate Elemente mit zwei separaten Hintergründen, aber nein, es ist ein einzelnes Element mit harten Stopp-Verläufen, die den Raum visuell trennen. Wenn Sie vertikale Spalten erstellen und deren Hintergründe auf einem einzigen Elternelement verwalten müssten, ist dies eine Möglichkeit! Tatsächlich müssen Sie sich keine Sorgen machen, dass die Elemente die volle Höhe "dehnen", da der Hintergrund den gesamten Bereich abdeckt, was dies zu einem großartigen Trick machte, als wir Spalten basierend auf Floats oder Inline-Block-Elementen erstellen mussten.

Durch die Erweiterung des Konzepts von harten Stopps können wir einen farbgestreiften Balken erstellen. Hier sind Variationen davon, die durch Verschieben der background-position erstellt wurden.

Apropos Streifen: Diese harten Stopp-Verläufe eignen sich hervorragend für gestreifte Hintergründe jeder Art. Mit wiederholenden Verläufen (z. B. repeating-linear-gradient()) wird es etwas einfacher, da Sie nicht 100 % des Platzes füllen müssen, sondern Pixel verwenden und dort stoppen können, wo Sie es benötigen.

Es gibt auch andere Arten von Verläufen! Wir können harte Stopps auch mit radial-gradient und repeating-linear-gradient verwenden!

Beachten Sie im letzten Beispiel, dass Sie immer noch einige Farbüberblendungen sehen. Ein harter Stopp-Verlauf muss nicht ausschließlich verwendet werden. Dieser hat nur einen harten Stopp, der sich wiederholt.

Konische Verläufe sind ein weiterer hervorragender Kandidat für harte Stopp-Verläufe, da sie, wenn sie auf einen Kreis angewendet werden (z. B. border-radius: 50%), sofort zu Tortendiagrammen werden!

Kapitel 3 Ziehbare Elemente

Um es klarzustellen: Selbst wenn wir das in HTML und CSS schaffen, erreichen wir nur, dass das Element über den Bildschirm ziehbar ist. Wenn Sie tatsächlich etwas als Ergebnis dieses Ziehens tun müssen, sind Sie wieder im JavaScript-Bereich.

Dieser Trick stammt von Scott Kellum. Scott hat im Laufe der Jahre eine Reihe meiner absoluten Lieblingstricks für CSS gemacht, wie dieses super einfache @keyframes Setup, das ein Element wie ein alter Schulschirmschoner von den Rändern des Viewports abprallen lässt, bis hin zu einer beeindruckenden Sass-gesteuerten Parallax-Technik.

Es gibt wirklich nur eine CSS-Sache, die uns beim Klicken und Ziehen helfen kann, und das ist die Browser-Benutzeroberfläche, die wir auf Desktop-Browsern erhalten, wenn wir die resize-Eigenschaft verwenden. Hier ist ein <div>, bei dem wir sie verwenden (zusammen mit overflow: hidden;, was eine Voraussetzung dafür ist, dass sie funktioniert)

Wenn Sie sich die Demo auf einem Desktop-Browser ansehen, können Sie die untere rechte Ecke greifen und sie herumziehen.

Nun zum eigentlichen Trick.

Wir können dieses größenveränderbare Element in einen anderen Container einfügen. Dieser Container wird in der Höhe natürlich wachsen, wenn sich die Größe des größenveränderbaren Elements ändert. Er wird seine Breite aufgrund von width: min-content; natürlich ändern.

Nun haben wir ein Elternelement, das sich zusammen mit dem größenveränderbaren Element in der Größe anpasst. Das ist wichtig, denn wir können andere Dinge in dieses Elternelement einfügen, die sich damit mitbewegen. Ich werde ein großes X hineinlegen und es direkt über dem Resizer positionieren, mit pointer-events: none; darauf, damit ich immer noch das Größenanpassen durchführen kann

Wenn wir nun sicherstellen, dass das größenveränderbare Element über opacity: 0; ausgeblendet wird, scheint es, als hätten wir ein ziehbares Element aus dem Nichts gemacht! Wir müssen möglicherweise ein wenig an den Zahlen fummeln, um alles auszurichten, aber es ist machbar

Kapitel 4 Editierbare Stilblöcke

Wenn Sie HTML wie folgt sehen

<p>I'm going to display this text.</p>

Das ist ziemlich intuitiv. So wird der Browser dieses Absatz-Element mit Text anzeigen.

Aber dieser Absatz existiert in einem größeren HTML-Dokument, wie

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>My Website</title>
</head>
<body>
  <p>I'm going to display this text.</p>
</body>
</html>

Warum wird "Meine Website" nicht wie der Absatz angezeigt? Was ist so anders an <title> und <p>. Nun, das ist die Natur von Code. Unterschiedliche Dinge tun unterschiedliche Dinge. Aber in diesem Fall können wir recht einfach nachvollziehen, warum es nicht angezeigt wird.

Wenn wir dieses HTML-Dokument in einem Browser öffnen und dieses <title>-Element inspizieren, wird uns die User-Agent-Stylesheet-Regel anzeigen, dass dieses Element auf display: none; gesetzt ist. Das ist verständlich! Das ist genau das, was wir verwenden, wenn wir Dinge von Websites komplett ausblenden wollen.

Außerdem ist das Elternelement von <title>, <head>, ebenfalls auf display: none; gesetzt.

Hier wird es lustig.

User-Agent-Stile lassen sich sehr leicht überschreiben! Jeder Wert, der von unserem CSS kommt, wird ihn überschreiben. Versuchen wir also Folgendes

<style>
  head, title {
    display: block;
  }
</style>

LOLZ, da ist es! Genau wie ein Absatz

Und wir haben genauso viel Kontrolle darüber wie über alles andere, was bedeutet, dass wir ihm perfekte Stile zuweisen können

Und das kann noch seltsamer werden… Sehen Sie diesen <style>-Block, der sich ebenfalls im <head> befindet? Wir können ihn aus demselben Grund nicht sehen, warum wir den <title> nicht sehen konnten: Er hat display: none;. Wir können das ändern, um ihn auch sichtbar zu machen.

Während wir dabei sind, können wir ihn so aussehen lassen, wie er in unserem Code-Editor aussieht, indem wir ihn den Whitespace respektieren und eine Monospace-Schriftart verwenden

head, title, style {
  display: block;
}
style {
  font-family: monospace;
  white-space: pre;
}

Ha! Was zum Teufel!

Nun können wir noch einen Schritt weiter gehen. Dieser Style-Block? Er kann editierbar werden, weil das dank des Attributs contenteditable eine Sache ist, die jedes HTML-Element tun kann.

<style contenteditable>
  ...
</style>

Nun kann dieser sichtbare <style>-Block wie ein <textarea> bearbeitet werden, und die CSS wird sofort auf das Dokument angewendet.

Definitiv eines der seltsamsten Dinge, zu denen HTML und CSS fähig sind.

Man könnte dies als CSS-Quine bezeichnen ("ein selbstbezügliches Programm, das ohne externen Zugriff seinen eigenen Quellcode ausgeben kann"). Alex Sexton veröffentlichte 2013 ein Beispiel dafür und nennt Anne van Kesteren und Mathias Bynens als Vorläufer. Ich habe Lea Verou gesehen, wie sie es bei Konferenzvorträgen für Live-Coding verwendet!

Kapitel 5 Scroll-Schatten

Die Idee der Scroll-Schatten ergibt absolut viel Sinn. Wenn ein Container nach unten gescrollt wird, sehen Sie einen Schatten am oberen Rand, was klar macht, dass Sie nach oben zurückscrollen können. Und wenn man nach unten scrollen kann, gibt es auch unten einen Schatten, es sei denn, man ist ganz nach unten gescrollt.

Dies ist vielleicht mein liebster CSS-Trick aller Zeiten. Die Idee stammt von Roman Komarov, aber dann entwickelte Lea Verou den extra schicken CSS-Trick und machte ihn populär.

Scroll-Schatten sind eine so schöne UX, dass man sich fragt, warum es keine native Browserfunktion ist oder zumindest einfacher in CSS umzusetzen ist. Man könnte sie als Affordance bezeichnen, einen offensichtlichen visuellen Hinweis, dass Scrollen entweder möglich oder abgeschlossen ist und keine Lernkurve erfordert.

Hier ist ein funktionierendes Beispiel

Es ist ein bisschen verwirrend zu verstehen, wie es funktioniert, teilweise weil es background-attachment: local; verwendet, was, um es gelinde zu sagen, selten ist. Hier ist ein Versuch

  1. Es gibt hier zwei Arten von Schatten
    1. Reguläre Schatten
    2. Abdeckungsschatten
  2. Alle Schatten werden mit Hintergrundverläufen erstellt. Zum Beispiel ein nicht wiederholender radial-gradient, der in der Mitte oben des Elements platziert und so groß ist, dass er wie ein Schatten aussieht.
  3. Die Abdeckungsschatten werden über diesen regulären Schatten platziert, durch die Stapelreihenfolge mehrerer Hintergründe, und können sie vollständig verbergen.
  4. Die regulären Schatten verwenden den Standardwert von background-attachment, nämlich scroll, den Sie kennen werden, weil Hintergründe normalerweise so funktionieren, dass Sie nicht wirklich darüber nachdenken. Die Hintergründe sind einfach da, im sichtbaren Bereich des Elements positioniert und bewegen sich nicht, wenn das Element gescrollt wird.
  5. Die Überlaufschatten verwenden den ungewöhnlichen background-attachment: local;, der sie an den oberen und unteren Rändern des Elements platziert und die gesamte Scrollhöhe des Elements berücksichtigt. Sie bewegen sich, wenn sich die Scrollposition des Elements ändert.

Stellen Sie sich dieses Szenario vor: Das Element hat vertikalen Überlauf und ist gerade ganz nach oben gescrollt. Sowohl der obere Schatten als auch die obere Abdeckung sind am oberen Rand des Elements. Die Abdeckung ist oben und verbirgt den Schatten, als wäre er gar nicht da. Scrollen Sie ein wenig nach unten, und die Abdeckung haftet am oberen Rand des Elements, ist nun vom Überlauf verdeckt, so dass Sie die Abdeckung nicht mehr sehen und der Schatten sich offenbart. Am unteren Rand konnten Sie den Schatten die ganze Zeit sehen, weil die Abdeckung am unteren Rand des Elements haftet und der Schatten am unteren Rand des sichtbaren Bereichs haftet. Scrollen Sie ganz nach unten, und die Abdeckung überlappt den unteren Schatten und verbirgt ihn. Das ist viel zu sagen, aber es funktioniert!

Das Schöne daran ist, dass es nur ein paar Codezeilen sind, die Sie auf ein einziges Element anwenden können, um es fertigzustellen.

.scroll-shadows {
  max-height: 200px;
  overflow: auto;

  background:
    /* Shadow Cover TOP */
    linear-gradient(
      white 30%,
      rgba(255, 255, 255, 0)
    ) center top,
    
    /* Shadow Cover BOTTOM */
    linear-gradient(
      rgba(255, 255, 255, 0), 
      white 70%
    ) center bottom,
    
    /* Shadow TOP */
    radial-gradient(
      farthest-side at 50% 0,
      rgba(0, 0, 0, 0.2),
      rgba(0, 0, 0, 0)
    ) center top,
    
    /* Shadow BOTTOM */
    radial-gradient(
      farthest-side at 50% 100%,
      rgba(0, 0, 0, 0.2),
      rgba(0, 0, 0, 0)
    ) center bottom;
  
  background-repeat: no-repeat;
  background-size: 100% 40px, 100% 40px, 100% 14px, 100% 14px;
  background-attachment: local, local, scroll, scroll;
}

Es muss nicht nur auf weißen Hintergründen funktionieren, aber es muss eine flache Farbe sein.

Hier ist eine Version mit den Farben, die in CSS-Benutzerdefinierte Eigenschaften abstrahiert wurden

Dies kann viel mehr sein als nur eine UI/UX-Nettigkeit, es kann entscheidend sein, um anzuzeigen, wann ein Container mehr Inhalt enthält, der gescrollt werden kann, in einer Situation, in der der Container keinen Scrollbalken oder andere UI-Elemente hat, die anzeigen, dass er scrollbar ist. Betrachten Sie die Geschichte Perfectly Cropped von Tyler Hall, in der er teilt, wie verwirrt seine Familienmitglieder über die Freigabefunktion in iOS 13 sind. Es ist überhaupt nicht offensichtlich, dass man hier nach unten scrollen kann in diesem Screenshot.

Andere Tricks

Vielleicht könnte der Schatten größer oder stärker sein, je nachdem, wie viel es zu scrollen gibt?

Hakim El Hattab tweetete einst ein Beispiel dafür, das dies großartig demonstrierte.

Beachten Sie, dass diese Demo ein wenig JavaScript verwendet, um ihre Wirkung zu erzielen. Natürlich zieht mich die reine CSS-Version an, besonders weil sie so einfach auf ein einzelnes Element angewendet werden kann. Aber es gibt viele Varianten davon mit JavaScript, wie zum Beispiel

Trotz meiner Vorliebe, dies nur in CSS zu tun, gibt es einen weiteren Grund, warum Sie sich für eine JavaScript-gesteuerte Lösung entscheiden möchten: iOS Safari. Im Juni 2019, als iOS 13 veröffentlicht wurde, funktionierte die Version von Safari darin (und in jeder Version danach) nicht mehr. Ich bin mir nicht ganz sicher, warum. Es scheint ein Bug zu sein. Er trat zur gleichen Zeit auf, als die clevere CSS-gesteuerte Parallax-Technik auf iOS Safari nicht mehr funktionierte. Es könnte etwas damit zu tun haben, wie sie bestimmte gemalte Ebenen von Websites "cachen". Es wäre schön, wenn sie es reparieren würden.

Kapitel 6 Perfekte Schriftfallbacks

Wenn Sie benutzerdefinierte Schriftarten im Web laden, ist eine verantwortungsvolle Methode, sicherzustellen, dass die @font-face-Deklaration die Eigenschaft font-display mit einem Wert wie swap oder optional verwendet.

@font-face {
  font-family: 'MyWebFont'; /* Define the custom font name */
  src:  url('myfont.woff2') format('woff2'); /* Define where the font can be downloaded */
  font-display: swap; /* Define how the browser behaves during download */
}

Damit gibt es keine Verzögerung für einen Benutzer, der Ihre Seite lädt, bevor er Text sieht. Das ist gut für die Leistung. Aber es hat einen Design-Kompromiss: Der Benutzer sieht FOUT oder "Flash of Unstyled Text". Das bedeutet, er sieht die Seite mit einer Schriftart laden, die Schriftart lädt, dann vertauscht die Seite diese Schriftart gegen die neue, was zu einer gewissen visuellen Störung und wahrscheinlich zu einem gewissen Reflow führt.

Dieser Trick dient dazu, diese Störung und diesen Reflow zu minimieren!

Dieser Trick stammt von Glen Maddern, der einen Screencast darüber bei Front End Center veröffentlicht hat, der Monica Dinculescus Font Style Matcher in Kombination mit Bram Steins Font Face Observer-Bibliothek verwendet.

Nehmen wir an, Sie laden eine Schriftart von Google Fonts. Hier verwende ich Rubik in zwei Stärken

@import url("https://fonts.googleapis.com/css2?family=Rubik:wght@400;900&display=swap");

Am Ende dieser URL sehen Sie standardmäßig &display=swap, was sie dazu bringt, font-display: swap; in der @font-face-Deklaration einzufügen.

Bei einer langsamen Verbindung sieht eine einfache Textseite so aus:

Zuerst sehen Sie die Fallback-Typografie, dann laden die benutzerdefinierten Schriftarten und Sie sehen, wie die Typografie zu diesen wechselt.

Sehen Sie den Wechsel? Denken Sie daran, das ist gut, in gewisser Weise, denn zumindest ist der Text anfangs sichtbar. Aber der Wechsel ist ziemlich grob. Er wirkt visuell störend.

Lassen Sie uns das beheben.

Mit dem Font Style Matcher-Tool können wir die beiden Schriftarten übereinander legen und sehen, wie unterschiedlich Rubik und die Fallback-Schriftart sind.

Beachten Sie, dass ich hier system-ui als Fallback-Schriftart verwende. Sie sollten eine klassische "websichere" Schriftart für einen Fallback verwenden, wie Georgia, Times New Roman, Arial, Tahoma, Verdana usw. Die überwiegende Mehrheit der Computer hat diese standardmäßig installiert, so dass sie sichere Fallbacks sind.

In unserem Fall haben diese beiden Schriftarten bereits eine nahezu identische "x-Höhe" (beachten Sie die Höhe der roten und schwarzen Kleinbuchstaben oben). Wenn sie das nicht hätten, müssten wir die Schriftgröße und Zeilenhöhe anpassen, um sie anzupassen. Aber glücklicherweise reicht für uns eine Anpassung des Buchstabenabstands aus, um sie sehr nahe zusammenzubringen.

Die Anpassung des Callbacks zur Verwendung von letter-spacing: 0.55px; bringt sie größenmäßig sehr nahe zusammen!

Nun besteht der Trick darin, uns die Möglichkeit zu geben, diese Formatierung nur anzuwenden, bevor die Schriftart geladen wird. Also machen wir sie zum Standardstil und haben dann eine Body-Klasse, die uns mitteilt, dass die Schriftart geladen ist und die Änderungen rückgängig macht.

body {
  font-family: "Rubik", system-ui, sans-serif;
  letter-spacing: 0.55px;
}
body.font-loaded {
  letter-spacing: 0px;
}

Aber wie bekommt man diese font-loaded-Klasse? Die Font Face Observer-Bibliothek macht es sehr einfach und browserübergreifend freundlich. Mit dieser Bibliothek sind es nur ein paar Zeilen JavaScript, um die Klasse anzupassen.

const font = new FontFaceObserver("Rubik", {
  weight: 400
});

font.load().then(function() {
  document.body.classList.add("font-loaded");
});

Sehen Sie nun, wie viel reibungsloser und weniger störend die Schriftartenerfahrung ist

Das ist ein wirklich großartiger Trick!

Hier ist diese minimale Demo

Wenn Sie beim Testen den Wechsel überhaupt nicht sehen können, überprüfen Sie, ob Sie Rubik nicht bereits auf Ihrem Computer installiert haben. Oder Ihr Internet ist vielleicht einfach zu schnell! DevTools können helfen, Ihre Verbindung für Tests zu verlangsamen.

Das kann komplexer werden, wenn Sie mehrere Schriftarten und mehrere Stärken von Schriftarten verwenden. Sie können das Laden jeder einzelnen beobachten und verschiedene Klassen anpassen, während sie geladen werden, und Stile anpassen, um den Reflow so gering wie möglich zu halten.

Kapitel 7 Selbstzeichnende Formen

Das beste Werkzeug zum Zeichnen von Formen, das wir im Web haben, ist SVG, und insbesondere das <path d="" />-Element. Mit der Pfadsyntax können Sie mit seinen Befehlen zum Zeichnen von geraden und gekrümmten Linien alles zeichnen, was Sie wollen. Ein Pfad kann eine solide Form sein, aber für unsere Zwecke hier gehen wir davon aus, dass der Pfad fill: none; hat und wir uns auf den stroke des Pfades konzentrieren und diesen Pfad selbst zeichnen lassen.

Nehmen wir an, wir haben einen einzelnen <path />, der eine coole Form wie diese zeichnet

In unserem SVG stellen wir sicher, dass wir diesen Pfad gut wie folgt eingerichtet haben

<path 
  pathLength="1" 
  stroke="black"
  stroke-width="5"
  fill="none"
  d="..."
/>

Diese zweite Zeile macht diesen Trick sehr einfach umzusetzen, wie Sie gleich sehen werden.

Der Trick selbst, das "Selbstzeichnen" der Form, basiert auf der Idee, dass Striche gestrichelt sein können und Sie die Länge und den Abstand des Strichs steuern können. Stellen Sie sich also vor: Sie machen den Strich (und den Abstand danach) so lang, dass er die gesamte Form bedeckt, so dass es so aussieht, als hätten Sie den Strich überhaupt nicht gestrichelt. Aber dann verschieben Sie den Strich so weit, dass es so aussieht, als gäbe es überhaupt keinen Strich. Dann kommt der entscheidende Punkt: animieren Sie den Versatz, so dass es so aussieht, als würde sich die Form selbst zeichnen.

Deshalb ist pathLength="1" so nützlich. Wir animieren einfach den Versatz von 1 auf 0, was in CSS kinderleicht ist.

path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: dash 5s linear forwards;
}

@keyframes dash {
  from {
    stroke-dashoffset: 1;
  }
  to {
    stroke-dashoffset: 0;
  }
}

Das obige CSS funktioniert bei jedem gestrichelten Pfad, vorausgesetzt, Sie verwenden den pathLength-Trick!

Ein kleines Problem: Safari. Safari mag das pathLength-Attribut auf dem Pfad nicht, daher schlägt der einfache 1-zu-0-Trick fehl. Er ist aber rettbar. Zuerst müssen wir die natürliche Länge des Pfades ermitteln (anstatt sie auf 1 zu erzwingen). Das können wir tun, indem wir ihn im DOM auswählen und

path.getTotalLength();

In unserem obigen Beispiel beträgt die Länge 8085. Also verwenden wir anstelle von 1 diesen Wert in unserem CSS.

path {
  stroke-dasharray: 8085;
  stroke-dashoffset: 8085;

  animation: dash 5s ease-in-out infinite alternate;
}

@keyframes dash {
  from {
    stroke-dashoffset: 8085;
  }
  to {
    stroke-dashoffset: 0;
  }
}

Hier ist ein Fork des Beispiels mit diesem Zusatz, der in allen Browsern funktioniert. Hoffentlich funktioniert pathLength bald auch in Safari, da es viel einfacher ist, die Pfadlänge nicht messen zu müssen.

Mehr

Kapitel 8 Kasten-Buttons

Wir werden zu diesen "kastenartigen Buttons" kommen, aber wir werden box-shadow verwenden, um sie zu erstellen, also machen wir eine schnelle box-shadow-Reise.

Der grundlegende Anwendungsfall für box-shadow ist, einem Element das Aussehen von Dreidimensionalität zu verleihen, indem ein Schatten darunter angewendet wird, als wäre es von der Oberfläche abgehoben.

Die leichten Schatten, die auf diese weißen Kästen angewendet werden, werden durch

.module {
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}

Das heißt

  1. Erstellen Sie eine exakte Kopie der Form dieses Elements (unter Berücksichtigung der border-radius zum Beispiel) und legen Sie sie unter das Element
  2. Verschieben Sie sie horizontal um 0 und vertikal um 1 Pixel (nach unten)
  3. Verzerren Sie sie um 3 Pixel. Nach der Unschärfe gibt es einen optionalen Parameter namens Spread, der es Ihnen erlaubt, den Schatten zu erweitern oder zu verkleinern, der standardmäßig auf 0 steht (tut beides nicht).
  4. Der Hintergrund davon ist schwarz mit 0,2 Deckkraft.

Das ist aber grundlegend. Komm schon. Wir können damit seltsamer werden. Betrachten Sie

  1. Sie können bei diesen Offsets extrem werden.
  2. Sie müssen den Schatten überhaupt nicht verzerren.
  3. Die Farben müssen nicht subtil sein.

Und am wichtigsten

  1. Sie können mehrere Schatten anwenden

Hier sind drei unterschiedlich versetzte Schatten ohne Unschärfe

.module {
  width: 100px;
  height: 100px;
  background: white;
  box-shadow:
    5px 5px 0 #FF9800,
    10px 10px 0 #FFC107,
    15px 15px 0 #607D8B;
}

Wir könnten die Offsets weiter treiben und die "Schatten" vollständig vom Element trennen.

.module {
  width: 50px;
  height: 50px;
  background: white;
  box-shadow:
    55px 55px 0 #FF9800,
    110px 110px 0 #FFC107,
    165px 165px 0 #607D8B;
}

Da wir nun die Fähigkeit haben, unbegrenzte Schatten beliebiger Größe überall zu platzieren, können wir Pixel-Art zeichnen! Alles mit einem einzigen Element! Hier ist ein Burger, Pommes und Shake von Marcus Connor

Steve Jobs, wie von Codrin Pavel gemacht

Oder wie wäre es mit der Mona Lisa, die mit etwa 7.500 Schatten von Jay Salvat erstellt wurde

Auf einer etwas praktischeren Ebene können Sie box-shadow schichten, um Dreidimensionalität und gerichtete Schatten zu simulieren. Kasten-Buttons!

Der Trick besteht darin, dass wir Null-Unschärfe-Schatten verwenden und sie übereinander legen. Wenn wir das Pixel für Pixel tun und die Seiten abwechseln, geben sie uns die Möglichkeit, einen 3D-Box-Look zu kreieren. Hier sind die Grundlagen

.boxy-button {
  --bottom-color: #999;
  --right-color: #ddd;

  box-shadow:
      1px 0   0 var(--right-color),
      1px 1px 0 var(--bottom-color),
      2px 1px 0 var(--right-color),
      2px 2px 0 var(--bottom-color),
      3px 2px 0 var(--right-color),
      3px 3px 0 var(--bottom-color),
      4px 3px 0 var(--right-color),
      4px 4px 0 var(--bottom-color);
}

Wenn wir so weitermachen, können wir einen sehr kastenartigen Button erstellen.

Wenn wir dann Übergänge hinzufügen, können wir ihn sogar sehr drückbar fühlen lassen

Wir könnten die Ein-Zeile-pro-Zeit-Schatten-Technik auch für den "äußeren" Schatten verwenden und den Verlauf simulieren, indem wir die Deckkraft des Schattens jedes Mal ein wenig reduzieren. Das erzeugt eher einen gerichteten Schatten-Look, der cool sein kann.

Hier ist ein Beispiel, bei dem die Richtung anders ist (dank negativer box-shadow-Offsets) und die gerichteten Schatten verwendet werden.

Das ist eine Menge Code für einen lustigen Button, aber sind Buttons es nicht wert? Mit deutlich weniger Code können wir einen weiteren ziemlich lustigen Offset-Look erzielen, diesmal unter Verwendung von inset box-shadow-Tricksereien und kleinen Pseudoelementen, um das fortlaufende Rahmen-Aussehen zu simulieren.

Kapitel 9 Scroll-Anzeige

Es gibt eine eingebaute Browser-Funktion zur Anzeige Ihrer Scroll-Position. Achten Sie darauf: Es ist die Scrollleiste, und sie macht einen großartigen Job. Es gibt sogar eine standardisierte Möglichkeit, Scrollleisten heutzutage zu stylen.

body {
  --scrollbarBG: #CFD8DC;
  --thumbBG: #90A4AE;

  scrollbar-width: thin;
  scrollbar-color: var(--thumbBG) var(--scrollbarBG);
}

Sie möchten vielleicht diese mit -webkit--Stilen kombinieren, um die beste Browserunterstützung zu erzielen. Zum Beispiel

Aber nehmen wir an, Sie waren nicht so sehr daran interessiert, die Scrollleiste zu stylen, wie daran, Ihren eigenen Indikator zu erstellen, um dem Benutzer zu zeigen, wie weit unten er gescrollt hat. Wie eine Fortschrittsleiste, die sich füllt, wenn Sie sich dem Ende eines Artikels nähern.

Mike Riethmuller hat eine Methode gefunden, die außerordentlich clever ist!

Sie ist nicht nur clever, sondern auch mit bemerkenswert wenig Code umgesetzt. Um das zu verstehen, entfernen wir die weißen Hintergründe des Headers und das Pseudoelement auf dem Body, wodurch der verwendete linear-gradient enthüllt wird.

Ah ha! Ein diagonaler Verlauf mit einem harten Stopp. Wir können bereits sehen, was hier passiert. Wenn die Seite nach unten gescrollt wird, wird der sichtbare Teil dieses Verlaufs immer mehr blau. Der Trick besteht dann darin, alles außer einem kleinen Streifen dieses Verlaufs zu verbergen, daher die durchgezogenen Hintergründe des Headers und das Pseudoelement, die einige Pixel voneinander entfernt platziert sind.

Vielleicht ist das cleverste Detail, wie der Hintergrundverlauf dimensioniert ist. Man könnte denken, er bedeckt einfach den gesamten Hintergrund, aber nein. Wenn Sie das täten, würde die Scrollleiste nie vollständig gefüllt, da sie sich am oberen Rand der Seite befindet und der Verlauf am unteren Rand der Seite endet. Aufgrund der mittleren Platzierung dieses Demos muss der Verlauf fast eine volle Viewport-Höhe vor dem unteren Rand erreichen. Das würde so aussehen

background-size: 100% calc(100% - 100vh);

Außer dass die feste Headergröße auch berücksichtigt wird, also muss das abgezogen werden. Am Ende sieht der Code so aus, als hätte er ziemlich viele magische Zahlen. Aber sie sind nicht ganz magisch, da die meisten von ihnen genetisch miteinander verwandt sind. Hier ist ein Fork, der sie alle in benutzerdefinierte Eigenschaften umwandelt, damit Sie das sehen können.

Warum das tun?

Wenn Sie etwas wirklich Ausgefallenes tun möchten, wie z. B. den Prozentsatz anzeigen, wie weit Sie auf der Seite gescrollt haben, oder noch ausgefallener, eine geschätzte Lesezeit anzeigen, die programmatisch berechnet wird, nun, das ist alles machbar, aber Sie sind im JavaScript-Territorium.

Kapitel 10 Dreiecke aus Rändern

Stellen Sie sich ein Element mit einem dicken Rand vor

.triangle {
  width: 200px;
  height: 200px;
  border: 10px solid black;
}

Stellen Sie sich nun vor, alle vier Ränder haben unterschiedliche Farben

.triangle {
  ...

  border-left-color:    red;
  border-right-color:   yellowgreen;
  border-top-color:     orange;
  border-bottom-color:  rebeccapurple;
}

Beachten Sie, wie die Ränder sich an Winkeln treffen?

Sehen Sie, was passiert, wenn wir das Element auf null Breite und Höhe reduzieren

.triangle {
  ...

  width: 0;
  height: 0;
}

Wenn drei dieser Ränder transparent wären, hätten wir ein Dreieck!

.triangle {
  ...

  border-left-color: transparent;
  border-right-color: transparent;
  border-top-color: transparent;
  border-bottom-color: rebeccapurple;
}

Schön.

Das könnte bei etwas wie einer Sprechblase nützlich sein. In diesem Fall könnten Sie das Dreieck einem anderen Element über ein Pseudoelement hinzufügen. Hier ist ein vollständiges Beispiel

Kapitel 11 Flexible Gitter

CSS Grid hat, wie alles andere, eine Lernkurve, aber nach einer Weile hat es eine gewisse Klarheit. Sie richten ein Gitter ein (buchstäblich Spalten und Zeilen) und platzieren dann Dinge auf diesen Zeilen. Das mentale Modell ist meiner Meinung nach um ein kleines bisschen einfacher als das von Flexbox.

Hier richte ich ein Gitter ein

.grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 1rem;
}

Und jetzt, wenn ich drei Kinder hätte, die ich in dieses Gitter einfügen würde…

<div class="grid">
   <div></div>
   <div></div>
   <div></div>
</div>

Sie würden perfekt in dieses Gitter fallen. Das ist wunderbar einfach und bietet uns eine Menge Kontrolle. Diese 1fr-Einheit kann nach Bedarf angepasst werden. Wenn die erste 2fr wäre, würde sie doppelt so viel Platz einnehmen wie die anderen beiden. Wenn es 200px wäre, wäre es genau so breit. Der gap kann verbreitert und verengt werden. Es gibt alle Arten von Werkzeugen für die Ausrichtung und explizite Platzierung und Reihenfolge.

Denken wir jedoch für einen Moment über etwas anderes nach. Nehmen wir an, es gäbe nur 2 Kinder. Nun, sie würden automatisch in die 1. und 2. Spalte fallen, wenn wir nicht explizit anders angeben würden, wohin wir sie haben wollen. Nehmen wir an, es gäbe 5 Kinder. Nun, die 4. und 5. würden automatisch in eine neue Zeile rutschen. Ja, Zeilen! Unser bisheriges Raster hat die Zeilen völlig ignoriert, sie sind nur implizit. Das hat etwas Intuitives. Man muss sich nicht um Zeilen kümmern, sie können automatisch erstellt werden. Man kann sich explizit um sie kümmern, muss es aber nicht.

Hier ist der CSS-Trick: Wir können diesen Spaß am „man muss sich nicht kümmern“ auf Spalten zusätzlich zu den Zeilen erweitern.

Eine Möglichkeit, dies zu tun, ist durch…

  1. Kein Setzen von grid-template-columns
  2. Ändern des Auto-Flows von den Standard-Zeilen zu grid-auto-flow: column;

Jetzt wird es so viele Spalten geben, wie es Kindelemente gibt! Außerdem kann man immer noch gap verwenden, was gut ist.

Aber was wir hier verloren haben, ist das Umbrechen. Es wäre schön, wenn die Anzahl der Spalten davon abhängen würde, wie viele Elemente passen könnten, ohne die Breite des Elternelements zu beeinträchtigen, und dann dies für den Rest des Rasters zu tun.

Das führt uns zu vielleicht dem berühmtesten und nützlichsten Code in ganz CSS Grid

.grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

Es gibt auch ein auto-fill-Schlüsselwort, und sie unterscheiden sich ein wenig, wie Sara Soueidan erklärt.

Wenn Sie dieses Beispiel in der Größe ändern, werden Sie sehen, wie sich die Anzahl der Spalten anpasst

Beachten Sie auch, dass der hier verwendete Mindestwert 200px für jede Spalte beträgt. Das ist nur eine Zahl, die Sie wählen, die gut zu Ihren Inhalten passt. Wenn diese Zahl beispielsweise 400px wäre, könnten Sie eine Änderung in Betracht ziehen, die es ihr erlaubt, kleiner zu werden, wenn der Bildschirm selbst kleiner als das ist. Ich habe diesen Trick zuerst von Evan Minto gesehen

grid-template-columns: repeat(auto-fill, minmax(min(10rem, 100%), 1fr));

Das bedeutet, wenn 100% Breite weniger als 10rem ergibt (andernfalls das Minimum), dann wird dies stattdessen verwendet, was es für Layouts auf kleinen Bildschirmen sicherer macht.

Kapitel 12 Formen-Morphing

Es gibt viele Bewegungsmöglichkeiten im Web. Sie können die Eigenschaften opacity, color und transform (wie translate, scale und rotate) jedes Elements animieren, um nur einige zu nennen, alles ziemlich einfach. Zum Beispiel

.kitchen-sink {
  opacity: 0.5;
  background-color: orange;
  transform: translateX(-100px) scale(1.2) rotate(1deg);
}
.kitchen-sink:hover {
  opacity: 1;
  background-color: black;
  transform: translateX(0) scale(0) rotate(0);
}

Übrigens sind Animationen der Eigenschaften transform und opacity ideal, weil der Browser sie „günstig“ machen kann, wie man so schön sagt. Das bedeutet, dass der Browser viel weniger Arbeit hat, um die Bewegung zu erzeugen, und die „Hardwarebeschleunigung“ nutzen kann).

Weniger bekannt ist die Tatsache, dass Sie die tatsächliche Form von Elementen animieren können! Ich spreche nicht nur davon, border-radius zu animieren oder einige Pseudo-Elemente herumzuschieben (obwohl das sicherlich nützlich sein kann), ich meine buchstäblich die Vektorform eines Elements zu morphingieren.

Für unseren ersten Trick erstellen wir die Vektorform mithilfe von clip-path. Wir können Teile eines Elements bei %-Koordinaten wegschneiden, so:

.moving-arrow {
  width: 200px;
  height: 200px;
  background: red;
  clip-path: polygon(100% 0%, 75% 50%, 100% 100%, 25% 100%, 0% 50%, 25% 0%);
}

Clippy ist ein unglaubliches Werkzeug zum Generieren von polygon()-Formdaten. Firefox DevTools verfügt auch über ziemlich gute integrierte Werkzeuge zur Bearbeitung, sobald es angewendet wurde.

Dann können wir diesen clip-path bei einer Art Zustandsänderung ändern. Es könnte die Änderung einer Klasse sein, aber lassen Sie uns hier :hover verwenden. Während wir dabei sind, fügen wir eine Übergangszeit hinzu, damit wir die Formänderung sehen können!

.moving-arrow {
  ...
  transition: clip-path 0.2s;
  clip-path: polygon(100% 0%, 75% 50%, 100% 100%, 25% 100%, 0% 50%, 25% 0%);
}
.moving-arrow:hover {
  clip-path: polygon(75% 0%, 100% 50%, 75% 100%, 0% 100%, 25% 50%, 0% 0%);
}

Da das polygon() die exakt gleiche Anzahl von Koordinaten hat, funktioniert die Übergangszeit.

Die Verwendung von clip-path zum Zeichnen von Vektorformen ist in Ordnung, aber es ist vielleicht nicht das perfekte Werkzeug zum Zeichnen von Vektorformen. Das Zeichnen von Vektorformen ist eigentlich die Sprache von SVG. SVG-Elemente haben Attribute, die zum Zeichnen bestimmt sind. Das Kraftpaket ist das Element, das seine eigene spezielle Syntax zum Zeichnen hat.

Sie könnten einen Pfad wie diesen sehen

<svg viewBox="0 0 20 20">
  <path d="
     M 8 0
     L 12 0
     L 12 8
     L 20 8
     L 20 12
     L 12 12
     L 12 20
     L 8 20
     L 8 12
     L 0 12
     L 0 8
     L 8 8
     L 8 0
  "></path>
</svg>

Was eine „+“-Form zeichnet.

Dieser Wert für das d-Attribut mag wie Kauderwelsch aussehen, aber er steuert wirklich die Bewegung eines virtuellen Stifts. Bewegen Sie den Stift hierhin, zeichnen Sie eine Linie so weit in diese Richtung usw.

Im obigen Beispiel werden nur zwei Befehle verwendet, wie Sie an den Buchstaben erkennen können, die jeder Zeile vorangestellt sind

SVG selbst hat eine Sprache zur Änderung dieser Koordinaten, wenn wir wollten, einschließlich Animation. Sie heißt SMIL, aber das große Problem damit ist, dass sie alt ist und nie besonders gut unterstützt wurde.

Die gute Nachricht ist, dass einige Browser etwas von dem unterstützen, was SMIL kann, direkt in CSS. Wir können zum Beispiel den path bei :hover in CSS wie folgt ändern:

svg:hover path {
    d: path("
      M 10 0 
      L 10 0
      L 13 7
      L 20 10
      L 20 10
      L 13 13
      L 10 20
      L 10 20
      L 7 13
      L 0 10
      L 0 10
      L 7 7
      L 10 0
    ");
}
path {
  transition: 0.2s;
}

Das verwandelt unsere Plus-Form in eine Wurfstern-Form, und die Übergangszeit ist möglich, weil es die gleiche Anzahl von Punkten ist.

Wenn Sie ernsthaft an der Idee des Formen-Morphings interessiert sind und ein äußerst leistungsfähiges Werkzeug dafür benötigen, sollten Sie sich MorphSVG-Plugin von Greensock ansehen. Es ermöglicht eine große Kontrolle darüber, wie die Form morphingiert und ist nicht auf Übergänge mit gleicher Punktzahl beschränkt.

Kapitel 13 Gelber Blitz

Wir werden zum Gelben Blitz kommen, aber es hat alles mit der Scroll-Position auf der Seite und dem Verständnis, wo man sich befindet, zu tun. Heutzutage kann CSS allein die Scroll-Position auf einer Seite animieren. Es ist ein Einzeiler!

html {
  scroll-behavior: smooth;
}

Bis zu einem gewissen Grad ist dies eine ästhetische Wahl. Wenn eine Seite von einer Position zur nächsten scrollt (wegen z. B. eines „Sprunglinks“ zu einer anderen ID auf der Seite), anstatt sofort dorthin zu springen, scrollt die Seite sanft dorthin. Abgesehen von der Ästhetik kann der Sinn der Verwendung dies sein, dem Benutzer zu helfen, den Kontext zu verstehen. Oh, ich sehe, die Seite ist von hier nach dort gescrollt, und wo sie angehalten hat, repräsentiert, wohin ich verlinkt habe.

Aber ein sanftes Scrollen ist nicht die einzige Möglichkeit, die Betonung darauf zu legen, dass der Kontext des Verlinkens woanders auf derselben Seite liegt. Wir können dies auch mit einer visuellen Änderung am Zielbereich tun, und ich würde argumentieren, dass dies der klarste Weg ist.

Glücklicherweise gibt es eine CSS-Pseudo-Klasse, die perfekt für die Aufgabe geeignet ist, Elemente zu stylen, wenn sie durch einen Link auf der Seite angesprungen wurden. Der :target-Selektor, der auf jedes Element angewendet werden kann

section:target {
  background: yellow;
}

Das bedeutet: Wenn der #Hash in der URL mit der #ID dieses Elements übereinstimmt, stimmt dieser Selektor überein und stylt ihn wie folgt.

Wenn es also ein Element gibt wie…

<section id="footnotes">

</section>

Und die URL ist zufällig

https://website.com/#footnotes

Dieser Selektor stimmt überein und wir sehen, dass er einen gelben Hintergrund hat.

Diese URL würde auftreten, wenn ein Link angeklickt wird wie

<a href="/#footnotes">Jump to Footnotes</a>

Es gibt hier natürlich einen Trick. Ein gelber Hintergrund allein (oder jede andere statische Formatierung) schreit nicht gerade Sie haben gerade hierher verlinkt! Eine kleine Animation kann hier viel bewirken. Wenn Sie nicht nur den Hintergrund des verlinkten Elements auf gelb setzen, sondern stattdessen nur vorübergehend einen gelben Hintergrund aufblitzen lassen, reicht das aus, um das Auge zu fesseln und die Aktion sehr klar zu machen.

Hier ist ein Beispiel und eine Demo. Sagen wir, Sie haben einen Link zu einer Fußnote am Ende eines Artikels. Das ist besonders interessant, weil ein Link zum Ende einer Seite besonders schwer Aufmerksamkeit zu erregen ist (es gibt möglicherweise nicht genügend Scroll-Raum, um die Fußnote an den oberen Rand der Seite zu bringen).

<p>
  Lorem ipsum<sup class="footnote" id="footnote-top-1">
    <a href="#footnote-bottom-1">1</a></sup>
  dolor sit amet consectetur adipisicing elit.
</p>

Dann tatsächlich die Fußnote am Ende der Seite, auf die Sie verlinken

<div id="footnotes" class="footnotes">
  <ol>
    <li id="footnote-bottom-1">Lorem ipsum is Greek. 
      <a href="#footnote-top-1">
        <span class="screen-reader-text">Back to reference</span>
        ↥
      </a></li>
  </ol>
</div>

Beachten Sie, dass beide Ankerlinks Sprunglinks verwenden, footnote-bottom-1 und footnote-top-1 zu diesen jeweiligen IDs.

Wir können die Fußnote selbst beim Ankommen mit einer @keyframes-Animation aufblitzen lassen

.footnotes :target {
  animation: yellowflash-bg 2s;
}
@keyframes yellowflash-bg {
  from { background: yellow; }
  to   { background: transparent; }
}

In diesem Fall blitzt es sofort gelb auf und verblasst dann über 2 Sekunden zu einem transparenten Hintergrund.

Hier ist ein interaktives Beispiel

Das ist der Gelbe Blitz! Natürlich muss er nicht gelb sein und er muss nicht einmal blinken. Der Punkt ist, etwas zu tun, um visuell zu signalisieren, worauf verlinkt wird, um Klarheit zu schaffen.

Die obige Demo ist mit sanftem Scrollen gekoppelt, aber Sie möchten das vielleicht nicht tun, da Sie die Zeit des sanften Scrollens nicht steuern können, so dass die Gefahr besteht, dass der gelbe Blitz bereits vorbei ist, wenn Sie dort ankommen.

Hey, ein Schütteln könnte auch Spaß machen.

Kapitel 14 Scrollen am unteren Rand fixieren

Die overflow-anchor-Eigenschaft in CSS ist relativ neu und debütierte erstmals 2017 mit Chrome¹, 2019 mit Firefox und nun übernimmt Edge mit dem Chrome-Übergang im Jahr 2020. Glücklicherweise ist seine Verwendung größtenteils eine Verbesserung. Die Idee ist, dass Browser standardmäßig wirklich versuchen, Positionsverschiebungen zu vermeiden. Wenn es Ihnen dann nicht gefällt, wie es damit umgeht, können Sie es mit overflow-anchor ausschalten. Im Allgemeinen berühren Sie es also nie.

Aber wie Sie vielleicht vermuten, können wir diese kleine Schönheit für ein wenig CSS-Trickerei ausnutzen. Wir können ein scrollendes Element dazu zwingen, am unteren Rand fixiert zu bleiben, auch wenn wir neuen Inhalt anhängen.

Chat ist ein klassisches Beispiel für das Scrollen mit Fixierung am unteren Rand.

Wir erwarten dieses Verhalten in einer Benutzeroberfläche wie Slack, wo, wenn wir bis zu den neuesten Nachrichten in einem Kanal gescrollt haben, beim Eintreffen neuer Nachrichten diese sofort unten sichtbar sind, wir nicht manuell nach unten scrollen müssen, um sie zu sehen.

Diese Funktion kommt von Ryan Hunt, der auch Nicolas Chevobbe dankt.

Wie Ryan sagt

Haben Sie jemals versucht, ein scrollbares Element zu implementieren, dem neuer Inhalt hinzugefügt wird und Sie den Benutzer am unteren Rand fixieren möchten? Es ist nicht einfach, es richtig zu machen.

Sie müssen mindestens erkennen, wann neuer Inhalt mit JavaScript hinzugefügt wird, und das scrollende Element zum unteren Rand zwingen. Hier ist eine Technik, die MutationObserver in JavaScript verwendet, um auf neuen Inhalt zu warten und das Scrollen zu erzwingen

const scrollingElement = document.getElementById("scroller");

const config = { childList: true };

const callback = function (mutationsList, observer) {
  for (let mutation of mutationsList) {
    if (mutation.type === "childList") {
      window.scrollTo(0, document.body.scrollHeight);
    }
  }
};

const observer = new MutationObserver(callback);
observer.observe(scrollingElement, config);

Hier ist eine Demo davon.

Aber ich finde eine reine CSS-Lösung viel verlockender! Die obige Version hat einige UX-Fallstricke, die wir später behandeln werden.

Der Trick ist, dass Browser standardmäßig Scroll-Ankerung durchführen. Aber was Browser versuchen zu tun ist, die Seite nicht zu verschieben. Wenn also neuer Inhalt hinzugefügt wird, der die visuelle Position der Seite verschieben könnte, versuchen sie, dies zu verhindern. In diesem ungewöhnlichen Fall wollen wir eher das Gegenteil. Wir wollen, dass die Seite am unteren Rand der Seite klebt und die visuelle Seite sich visuell bewegt, weil sie gezwungen ist, am unteren Rand zu bleiben.

So funktioniert der Trick. Zuerst etwas HTML innerhalb eines scrollenden Elternelements

<div id="scroller">
  <!-- new content dynamically inserted here -->
  <div id="anchor"></div>
</div>

Alle Elemente haben von Natur aus overflow-anchor: auto;, was bedeutet, dass sie versuchen, diese Seitenverschiebung zu verhindern, wenn sie auf dem Bildschirm sind, aber wir können dies mit overflow-anchor: none; ausschalten. Der Trick besteht also darin, alle dynamisch eingefügten Inhalte anzusprechen und sie auszuschalten

#scroller * {
  overflow-anchor: none;
}

Dann zwingen Sie nur dieses Anker-Element, die Scroll-Ankerung zu haben, nichts anderes

#anchor {
  overflow-anchor: auto;
  height: 1px;
}

Sobald dieser Anker auf der Seite sichtbar ist, wird der Browser gezwungen, diese Scroll-Position daran zu fixieren, und da es das allerletzte in diesem scrollenden Element ist, bleibt er am unteren Rand fixiert.

Los geht's!

Es gibt hier zwei kleine Einschränkungen…

  1. Beachten Sie, dass der Anker eine gewisse Größe haben muss. Wir verwenden hier height, um sicherzustellen, dass es sich nicht um ein kollabiertes/leeres Element ohne Größe handelt, was dies verhindern würde.
  2. Damit die Scroll-Ankerung funktioniert, muss die Seite zunächst mindestens einmal gescrollt worden sein.

Die zweite ist schwieriger. Eine Möglichkeit ist, sich gar nicht damit zu befassen, Sie könnten einfach warten, bis der Benutzer zum unteren Rand scrollt, und der Effekt funktioniert von da an. Es ist eigentlich ganz nett, denn wenn er vom unteren Rand wegscrollt, hört der Effekt auf zu funktionieren, was das ist, was Sie wollen. In der obigen JavaScript-Version beachten Sie, wie sie Sie zum unteren Rand zwingt, auch wenn Sie versuchen, nach oben zu scrollen, das ist, was Ryan meinte, dass dies nicht einfach richtig zu machen ist.

Wenn Sie möchten, dass der Effekt sofort ausgelöst wird, besteht der Trick darin, dass das scrollende Element sofort scrollbar ist, zum Beispiel

body {
  height: 100.001vh;
}

Und dann lösen Sie sofort ein sehr leichtes Scrollen aus

document.scrollingElement.scroll(0, 1);

Und das sollte den Trick machen. Diese Zeilen sind in der obigen Demo verfügbar, um auskommentiert und ausprobiert zu werden.

  1. Apropos Chrome: Google nimmt dieses Thema der Layoutverschiebungen sehr ernst. Eines der Web Core Vitals ist der Cumulative Layout Shift (CLS), der die visuelle Stabilität misst. Wenn Sie einen schlechten CLS-Wert erhalten, wirkt sich das buchstäblich auf Ihr SEO aus.

Kapitel 15 Scroll-Animation

Lassen Sie uns das also aus dem Weg räumen. Mit einem JavaScript-Einzeiler können wir eine CSS-Benutzerdefinierte Eigenschaft setzen, die den Prozentsatz des gescrollten Seiteninhalts kennt

window.addEventListener('scroll', () => {
  document.body.style.setProperty('--scroll', window.pageYOffset / (document.body.offsetHeight - window.innerHeight));
}, false);

Jetzt haben wir --scroll als Wert, den wir in CSS verwenden können.

Dieser Trick stammt von Scott Kellum, der ein Meister der CSS-Trickkiste ist!

Richten wir zunächst eine Animation ein, ohne diesen Wert zu verwenden. Dies ist eine einfache Drehanimation für ein SVG-Element, das sich für immer dreht und dreht

svg {
  display: inline-block;
  animation: rotate 1s linear infinite;
}

@keyframes rotate {
  to {
    transform: rotate(360deg);
  }
}

Jetzt kommt der Trick! Lassen Sie uns diese Animation nun pausieren. Anstatt sie über einen Zeitraum zu animieren, animieren wir sie über die Scroll-Position, indem wir die animation-delay anpassen, während die Seite gescrollt wird. Wenn die animation-duration 1s beträgt, bedeutet dies, dass das Scrollen über die gesamte Länge der Seite einer Iteration der Animation entspricht.

svg {
  position: fixed; /* make sure it stays put so we can see it! */

  animation: rotate 1s linear infinite;
  animation-play-state: paused;
  animation-delay: calc(var(--scroll) * -1s);
}

Versuchen Sie, die animation-duration auf 0.5s zu ändern. Das ermöglicht zwei vollständige Animationszyklen, während die Seite mit der animation-delay-Mathematik nach unten gescrollt wird.

Scott bemerkte in seiner ursprünglichen Demo, dass auch das Setzen von…

animation-iteration-count: 1;
animation-fill-mode: both;

… für einige „Overshoot“-Eigenheiten verantwortlich war und ich kann bestätigen, dass ich sie auch gesehen habe, besonders auf kurzen Ansichtsfenstern, daher lohnt es sich, diese auch zu setzen.

Scott setzte die Scroll-bezogenen Animationseigenschaften auch auf dem :root {} selbst, was bedeutet, dass es alle Animationen auf der Seite gleichzeitig steuern konnte. Hier ist seine Demo, die drei Animationen gleichzeitig steuert


Das war's für diesen Band, Leute! Ich möchte sehr gerne neue Bände machen und habe natürlich schon einige Tricks im Auge. Aber wenn Sie welche haben, die hier verewigt werden sollten, lassen Sie es mich bitte wissen!