Das Erstellen von Seiteninhalten, die beim Scrollen am Viewport haften bleiben, wie z. B. ein Sprungzielmenü oder Abschnittsüberschriften, war noch nie einfacher. Verwenden Sie position: sticky in Ihrer CSS-Regel, legen Sie den Richtungsabstand fest (z. B. top: 0) und schon sind Sie bereit, Ihre Teamkollegen mit minimalem Aufwand zu beeindrucken. Schauen Sie sich diesen CSS-Tricks-Artikel an, um einige wirklich ausgefallene Anwendungsfälle für die Positionierung von sticky zu sehen.
Aber die sticky-Positionierung kann etwas knifflig werden, insbesondere wenn es um die Höhe und die gefährliche Situation geht, Inhalte an einer Position zu verstecken, die nicht gescrollt werden kann. Lassen Sie mich die Bühne bereiten und Ihnen das Problem und meine Lösung zeigen.
Ich habe kürzlich an einem Desktop-Layout gearbeitet, das uns allen vertraut ist: ein Hauptinhaltsbereich mit einer Seitenleiste daneben. Diese spezielle Seitenleiste enthält Aktionsschaltflächen und Filter, die für den Hauptinhalt relevant sind. Wenn der Seitenabschnitt gescrollt wird, bleibt diese Komponente fest am Viewport und ist kontextbezogen zugänglich.
Das Layout-Styling war so einfach zu implementieren, wie ich es bereits erwähnt hatte. Aber es gab einen Haken: Die Höhe der Komponente würde je nach Inhalt variieren. Ich hätte sie mit max-height begrenzen und overflow-y: auto setzen können, um den Inhalt der Komponente scrollbar zu machen. Das funktionierte gut auf meinem Laptop-Bildschirm und meiner typischen Viewporthöhe, aber in einem kleineren Viewport mit weniger vertikalem Platz würde die Höhe der Seitenleiste den Viewport überschreiten.
Hier wurde es knifflig.
Lösungsansätze
Ich habe zunächst über eine Media-Query nachgedacht. Vielleicht könnte ich eine Media-Query verwenden, um die sticky-Positionierung zu entfernen und die Komponente relativ zur Oberseite des Seitenleisten-Containers zu positionieren. Dies würde den Zugriff auf den gesamten Inhalt ermöglichen. Andernfalls wird beim Scrollen der Seite der Inhalt der sticky-Komponente am unteren Rand des Viewports abgeschnitten, bis ich das Ende ihres übergeordneten Abschnitts erreiche.
Dann erinnerte ich mich, dass die Höhe der sticky-Komponente dynamisch ist.
Welchen magischen Wert könnte ich für meine Media-Query verwenden, um so etwas zu handhaben? Vielleicht könnte ich stattdessen eine JavaScript-Funktion schreiben, um zu prüfen, ob die Komponente beim Laden der Seite über die Viewport-Grenzen hinausfließt? Dann könnte ich die Höhe der Komponente aktualisieren…
Das war eine Möglichkeit.
Aber was ist, wenn der Benutzer sein Fenster verkleinert? Sollte ich dieselbe Funktion in einem resize-Event-Handler verwenden? Das fühlt sich nicht richtig an. Es muss einen besseren Weg geben, dies zu tun.
Es stellte sich heraus, dass es einen gab und er beinhaltete einige CSS-Tricks, um die Aufgabe zu erledigen!
Einrichtung des Seitenabschnitts
Ich begann mit einer flex-Anzeige auf dem Hauptelement. Ein flex-basis-Wert wurde der Seitenleiste für eine feste Desktop-Breite zugewiesen. Dann füllte das Artikel-Element den Rest des verfügbaren horizontalen Viewport-Platzes aus.
Wenn Sie neugierig sind, wie ich die beiden Container für kleinere Viewports ohne Media-Query gestapelt habe, schauen Sie sich The Flexbox Holy Albatross an.
Ich habe align-self: start zur Seitenleiste hinzugefügt, damit ihre Höhe nicht mit dem Hauptartikel gestreckt wird (stretch ist der Standardwert). Dies gab meinen Positionierungseigenschaften die Möglichkeit, ihre Magie zu wirken.
.sidebar {
--offset: var(--space);
/* ... */
position: sticky;
top: var(--offset);
}
Schauen Sie sich das an! Mit diesen beiden CSS-Eigenschaften haftet das Seitenleisten-Element oben am Viewport mit einem Abstand, um ihm etwas Luft zum Atmen zu geben. Beachten Sie, dass der top-Wert auf eine bereichsspezifische CSS-Custom-Property gesetzt ist. Die Variable --offset kann nun auf jedem untergeordneten Element innerhalb der Seitenleiste wiederverwendet werden. Dies wird sich später als nützlich erweisen, wenn die maximale Höhe der sticky-Seitenleistenkomponente eingestellt wird.
Eine Liste globaler CSS-Variablen-Deklarationen finden Sie in der CodePen Demo, einschließlich der --space-Variable, die für den Offset-Wert in der :root-Regel verwendet wird.
Die feste Seitenleiste
Denken Sie daran, dass die Komponente selbst nicht sticky ist; es ist die Seitenleiste selbst. Allgemeine Layout- und Positionierungsaufgaben sollten normalerweise vom übergeordneten Element übernommen werden. Dies gibt der Komponente mehr Flexibilität und macht sie modularer für die Verwendung in anderen Bereichen der Anwendung.
Tauchen wir in die Anatomie dieser Komponente ein. In der Demo habe ich die dekorativen Eigenschaften unten entfernt, um mich auf die Layout-Stile zu konzentrieren.
.component {
display: grid;
grid-template-rows: auto 1fr auto;
}
.component .content {
max-height: 500px;
overflow-y: auto;
}
- Diese Komponente verwendet CSS Grid und die Pancake Stack-Idee von 1-Line Layouts, um die Zeilen dieses Templates zu konfigurieren. Sowohl der Header als auch der Footer (
auto) passen sich der Höhe ihrer Kinder an, während der Inhalt (1fr, oder eine Brucheinheit) den Rest des freien vertikalen Platzes ausfüllt. - Ein
max-heightfür den Inhalt begrenzt das Wachstum der Komponente auf größeren Bildschirmen. Dies ist unnötig, wenn es bevorzugt wird, dass die Komponente sich dehnt, um die Viewporthöhe auszufüllen. overflow-y: autoermöglicht das Scrollen des Inhalts, wenn nötig.
Wenn die Komponente in der Seitenleiste verwendet wird, ist ein max-height erforderlich, damit sie die Viewporthöhe nicht überschreitet. Der --offset, der zuvor für die .sidebar-Klasse galt, wird verdoppelt, um einen unteren Rand des Elements zu erzeugen, der dem oberen Abstand der sticky-Seitenleiste entspricht.
.sidebar .component {
max-height: calc(100vh - var(--offset) * 2);
}
Das schließt die Montage dieser sticky-Seitenleistenkomponente ab! Nach dem Anbringen einiger dekorativer Stile wurde dieser Prototyp für Tests und Überprüfungen bereit. Probieren Sie es aus! Öffnen Sie die Demo in CodePen und klicken Sie auf die Rasterelemente, um sie zur Seitenleiste hinzuzufügen. Ändern Sie die Größe Ihres Browserfensters, um zu sehen, wie sich die Komponente mit dem Viewport mitbewegt und gleichzeitig sichtbar bleibt, während Sie den Hauptinhaltsbereich scrollen.
Dieses Layout funktioniert möglicherweise gut in einem Desktop-Browser, ist aber für kleinere Geräte oder Viewport-Breiten nicht ideal. Der Code hier bietet jedoch eine solide Grundlage, die es einfach macht, Verbesserungen an der Benutzeroberfläche vorzunehmen.
Eine einfache Idee: Eine Schaltfläche könnte am Viewport-Fenster befestigt werden, die beim Klicken die Seite zum Seitenleisten-Inhalt nach unten springen lässt. Eine andere Idee: Die Seitenleiste könnte außerhalb des Bildschirms versteckt werden und eine Umschalt-Schaltfläche könnte sie von links oder rechts herein schieben. Iteration und Benutzer-Tests werden helfen, diese Erfahrung in die richtige Richtung zu lenken.
Soll sie auch auf dem Handy haften?
Wenn ja, funktioniert sie möglicherweise nicht wie erwartet – habe es gerade auf Chrome / Pixel 3a :/
Perfektes Timing für mich! Das ist genau die Lösung für das Problem, das mir gestern eingefallen ist.
Und ich wollte tatsächlich eine Umschalt-Funktion für Handys, wie im Artikel vorgeschlagen. Danke für den Artikel!
Also ja, das funktioniert gut auf Handys ;)
Nur es funktioniert nur innerhalb des Desktop-Layouts (wie man es auf Landschafts-Handys direkt in CodePen sehen kann)
Schön schön :)
Ich forke und speichere in Gist, damit ich es in meinem Projekt implementieren kann!
Ich verstehe die Verwendung von
align-self: start, das Offset auf der Oberseite der Seitenleiste und dann die Berechnung der Höhe der Komponente nicht. Warum nichtmax-height: 100%auf der Komponente setzen und dannmax-height: 100vhauf der Seitenleiste setzen und--spacefür oberen und unteren Abstand verwenden? Sind beides gültige Wege, dies zu tun, oder gibt es etwas Besonderes an Ihrer Methode?Die Verwendung der
top-Eigenschaft anstelle des Anwendens von Padding oder Margin auf die Seitenleiste richtet die Oberseite der Komponente korrekt an der Oberseite des Hauptartikels aus. Wenn Sie diese Demo auf CodePen forken und Ihre vorgeschlagenen Änderungen vornehmen würden, würden Sie auch feststellen, dass die Komponente, wenn die Viewporthöhe ziemlich groß wird, stoppt, bevor sie das Ende des Hauptabschnitts erreicht. Ich denke, ich habe eine ähnliche Iteration durchlaufen, während ich mit diesem Layout experimentiert habe.Großartiger Artikel, Ryan! Ich liebe diese Video-Demo wirklich.
Können Sie einen Facebook-Fall in den Artikel aufnehmen? Zum Beispiel auf der Facebook-Profilseite im Desktop-Modus.
Tolles und einfaches Lösung, Ryan! Danke, dass Sie das geteilt haben.
Es gibt noch einen weiteren Weg, das Problem der dynamisch skalierbaren Seitenleiste zu lösen, ohne einen inneren Scrollbereich zu erstellen, aber es wird JavaScript verwendet.
https://github.com/vursen/FloatSidebar.js (meine Bibliothek, 2kb im gzip)
https://abouolia.github.io/sticky-sidebar/
Sehr schöner Artikel und tolles Layout! Aber eine schnelle Frage: Wenn Sie einen festen Header haben, der seine Höhe ändern kann (basierend auf Benutzereingaben, daher kann kein Margin verwendet werden), gibt es eine Möglichkeit, trotzdem dasselbe mit CSS zu implementieren?
Ich kann keine Lösung finden, die kein JS verwendet…
Danke
Danke!! Dieser Artikel hat meinen Tag wirklich gerettet.. Gut erklärt und auf den Punkt !! :)