Vor ein paar Tagen habe ich an einem Kundenprojekt gearbeitet und wollte einen bestimmten Effekt auf einem <img> erzielen. Hintergrundbilder können den gewünschten Effekt ziemlich einfach mit background-attachment: fixed; erzielen. Damit bleibt ein Hintergrundbild an seinem Platz – auch wenn die Seite gescrollt wird. Es wird nicht sehr oft verwendet, daher kann der Effekt ungewöhnlich und auffällig wirken, besonders wenn er sparsam eingesetzt wird.
Inhaltsverzeichnis
- Warum <img> anstelle von background-image verwenden?
- 1. CSS background-image verwenden
- 2. Den clip-path-Trick bei einem Inline-Bild verwenden
- Gibt es etwas Besseres?
Es hat einige Zeit gedauert, bis ich herausgefunden habe, wie man denselben Effekt nur mit einem Inline-Bild anstelle eines CSS-Hintergrundbilds erzielt. Dies ist ein Video des Effekts in Aktion
Der genaue Code für die obige Demo ist in diesem Git-Repo verfügbar. Beachten Sie nur, dass es sich um ein Next.js-Projekt handelt. Wir werden uns gleich einem CodePen-Beispiel mit rohem HTML zuwenden.
Warum <img> anstelle von background-image verwenden?
Es gibt eine Reihe von Gründen, warum ich das für mein Projekt wollte
- Es ist einfacher, Lazy Loading zu verwenden (z. B.
<img loading="lazy"… >). - Es bietet bessere SEO (ganz zu schweigen von Barrierefreiheit), dank des
alt-Textes. - Es ist möglich,
srcset/sizeszu verwenden, um die Ladeleistung zu verbessern. - Es ist möglich, das
<picture>-Tag zu verwenden, um die beste Bildgröße und das beste Format für den Browser des Benutzers auszuwählen. - Es ermöglicht Benutzern, das Bild herunterzuladen und zu speichern (ohne auf DevTools zurückgreifen zu müssen).
Insgesamt ist es besser, das Bild-Tag zu verwenden, wo immer es möglich ist, insbesondere wenn das Bild als Inhalt und nicht als Dekoration betrachtet werden kann. Daher landete ich bei einer Technik, die CSS clip-path verwendet. Wir werden uns dem gleich widmen, direkt nachdem wir uns die background-image-Methode angesehen haben, um beide Ansätze schön nebeneinander zu vergleichen.
1. CSS background-image verwenden
Dies ist der „originäre“ Weg, um einen festen Scroll-Effekt zu erzielen. Hier ist das CSS
.hero-section {
background-image: url("nice_bg_image.jpg");
background-repeat: no-repeat;
background-size: cover;
background-position: center;
background-attachment: fixed;
}
Aber wie wir gerade gesehen haben, ist dieser Ansatz für einige Situationen nicht ideal, da er auf der CSS-Eigenschaft background-image zum Aufrufen und Laden des Bildes beruht. Das bedeutet, dass das Bild technisch gesehen nicht als Inhalt betrachtet wird – und daher von Screenreadern nicht erkannt wird. Wenn wir mit einem Bild arbeiten, das Teil des Inhalts ist, sollten wir es zugänglich machen, damit es wie Inhalt und nicht wie Dekoration konsumiert wird.
Ansonsten funktioniert diese Technik gut, aber nur, *wenn das Bild die gesamte Breite des Viewports einnimmt und/oder zentriert ist*. Wenn Sie ein Bild auf der rechten oder linken Seite der Seite haben, wie im Beispiel, werden Sie auf eine ganze Reihe von Positionierungsproblemen stoßen, da background-position relativ zur Mitte des Viewports ist.
Die Korrektur erfordert einige Media Queries, um sicherzustellen, dass es auf allen Geräten richtig positioniert ist.
2. Den clip-path-Trick bei einem Inline-Bild verwenden
Jemand auf StackOverflow teilte diesen clip-path-Trick, und er erledigt die Arbeit gut. Sie können auch weiterhin das <img>-Tag verwenden, was, wie wir oben besprochen haben, in einigen Fällen vorteilhaft sein kann, insbesondere wenn ein Bild Teil des Inhalts und nicht reine Dekoration ist.
Hier ist der Trick
.image-container {
position: relative;
height: 200px;
clip-path: inset(0);
}
.image {
object-fit: cover;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
Schauen Sie es sich in Aktion an
Bevor wir nun losstürzen und diesen Snippet überall anbringen, hat er seine eigenen Nachteile. Zum Beispiel ist der Code meiner Meinung nach *etwas lang* für einen so einfachen Effekt. Aber noch wichtiger ist die Tatsache, dass die Arbeit mit clip-path auch einige Implikationen hat. Zum einen kann ich nicht einfach ein border-radius: 10px; wie im vorherigen Beispiel einfügen, um die Ecken des Bildes abzurunden. Das funktioniert nicht – es erfordert, abgerundete Ecken aus dem Clipping-Pfad selbst zu erstellen.
Ein weiteres Beispiel: Ich weiß nicht, wie ich das Bild *innerhalb* des clip-path positionieren soll. Wiederum mag das eine Frage des guten Wissens über clip-path sein und es dort zeichnen, wo Sie es brauchen, oder das Bild im Voraus zuschneiden, wie es nötig ist.
Gibt es etwas Besseres?
Persönlich habe ich auf die Verwendung des Fixed-Scrolling-Effekts bei Inline-Bildern verzichtet und bin wieder auf die Verwendung eines CSS-Hintergrundbilds zurückgekehrt – was, wie ich weiß, etwas einschränkend ist.
Haben Sie jemals versucht, dies zu bewerkstelligen, insbesondere mit einem Inline-Bild, und es gut hinbekommen? Ich würde es gerne erfahren!
Hallo,
Der erste Ansatz hat einen wirklich hässlichen Defekt (siehe: https://bit.ly/32Y61HX)
Der zweite Ansatz ist unlesbar (ich bin fortgeschrittener Benutzer, aber ich weiß wirklich nicht, was unset(0) … bedeutet)
Die Standardmethode mit BG-Bild ist lesbar und besser ;)
Inset ist eigentlich nicht so fortgeschritten.
Es ist ein CSS-Kurzschrift, anstatt top, bottom, left und right zu schreiben.
Sie können hier mehr darüber lesen
https://developer.mozilla.org/en-US/docs/Web/CSS/inset
Diesen Defekt hatten wir auch schon einmal, als ich den Artikel schrieb. Ich wette ehrlich gesagt, dass es sich um ein CodePen-bezogenes Problem handeln könnte. Ich hatte das Bild noch nie in einer realen Umgebung so verzerren sehen.
Übrigens – background-attachment:fixed funktioniert in Safari oder iOS aufgrund eines Fehlers nicht
Sie haben völlig Recht, @Thomas. Es funktioniert gut auf Mac Safari, aber es scheint, dass es auf iOS Safari nicht unterstützt wird. Das wusste ich tatsächlich nicht. Danke!
Es scheint ein billiger Weg (mit etwas zusätzlichem DOM) zu sein, das Tag in einen Div zu verpacken. Verwenden Sie
opacity, um das Bild zu verbergen, ohne Semantik/SEO zu ändern. Setzen Sie dann das Hintergrundbild auf den WrapperDas ist mir nicht eingefallen. Ich frage mich, ob es Nachteile hat?
Sie könnten es auch ohne Wrapper erledigen, indem Sie das Bild einfach außerhalb seiner Elementbox positionieren
mit
object-position.Ersetzen Sie den Div durch ein img, behalten Sie die Klasse bei und fügen Sie nur eine Zeile CSS hinzu.
Fixed Backgrounds sind fantastisch, ich benutze sie seit Jahrzehnten, aber man muss sich bewusst sein, dass die
background-image-Eigenschaft nur für dekorative Zwecke konzipiert wurde. Sie ist nicht dafür gedacht, wichtige Informationen auf die gleiche Weise wie ein Inline-Bild zu vermitteln. Sie können ein Hintergrundbild also nicht wirklich zugänglicher im Sinne von WCAG machen, aber Sie können es sicherlich weniger zugänglich machen (https://www.w3.org/TR/WCAG20-TECHS/F3.html).Obwohl es Hintergrundbilder nicht speziell abdeckt, könnte es sich lohnen, die Prinzipien unter https://www.w3.org/WAI/tutorials/images/ bezüglich dekorativer Bilder und so weiter zu lesen. Das hilft, einige der verschiedenen Gründe zu erklären, warum manche Bilder informativere Beschreibungen benötigen als andere.
In letzter Zeit spiele ich mit der Kombination von festen Farbverlauf-Hintergründen mit soliden und leicht transparenten Inhaltsmasken über verschiedenen Bereichen. Der feste Effekt kann großartig sein, wenn er gut gemacht ist, aber es kann schwierig sein, ihn genau richtig hinzubekommen. Aber es kann auch wie das Öffnen einer Büchse der Pandora in einer Dose voller Würmer sein, während man in einem Kaninchenbau ist. Sobald man die Möglichkeiten sieht, beginnt man, Komplexität zu schaffen, wo sie nicht benötigt wird. Mein einziger Rat ist also: Seien Sie vorsichtig, manchmal ist der einfachste Weg der einfachste aus gutem Grund.
Sie haben absolut Recht, dass es eine Büchse der Pandora sein kann. Wenn ich mich richtig erinnere, glaube ich, dass ich den Fixed-Background-Effekt für dieses Bild in der Produktionsversion der Website des Kunden am Ende nicht verwendet habe.
Es ist interessant, dass
clip-pathauch Fixed-Position-Elemente beeinflusst. Sowohloverflow: hidden;als auchoverflow: clip;beeinflussen es nicht. Fixed-Position-Elemente, sowie Fixed-Position-Hintergrundbilder, werden aus dem Seitenfluss genommen und nur relativ zum Viewport positioniert, sodass Sie sie nicht relativ zum Elternelement positionieren können. Sie müssen sie separat an denselben Punkt ausrichten – entweder durch Verwendung der Mitte, durch Berücksichtigung aller möglichen Layouts mit Media Queries oder durch Abrufen des Offsets mit JS.(Auch Ihr Hintergrundbild-Ansatz zeigt eine seltsame Verzerrung, wenn er auf einem schmalen Viewport gescrollt wird – entweder auf Mobilgeräten oder im eingebetteten Pen. Ich weiß nicht, warum das so ist)
Als Alternative – ich habe eine Abzweigung Ihres zweiten Ansatzes basierend auf
position: sticky;, einem zusätzlichen überlaufenden Container undoverflow: clip;gemacht. Sie können es sich ansehen: https://codepen.io/AnisMan/full/bGojraJMir ist das Verzerrungsproblem auch schon aufgefallen, bevor ich es gepostet habe, aber nur in einer Situation. Wir konnten nicht herausfinden, warum das manchmal passiert. Ich persönlich glaube, dass es ein Problem mit CodePen sein könnte? Aber ich bin mir wirklich nicht sicher.
Ich habe Ihre Abzweigung überprüft und sogar damit herumgespielt. Ich kann nicht ganz sehen, wie sie den Effekt erzielt, den ich angestrebt habe
(Meine vorherige Antwort scheint nicht durchgekommen zu sein)
Unter der Annahme, dass ich Ihren Punkt nicht ganz verfehlt habe, habe ich die Abzweigung nun korrigiert, um den Effekt eines an den Viewport angehängten Hintergrunds zu demonstrieren. Zuvor war es eher ein Proof of Concept.
Die Idee ist, dass
position:sticky;bei ausreichend Platz sich genauso verhält wieposition:fixed;, aber Sie können Richtungen wählen – vertikal am Viewport und horizontal am Elternelement befestigt.Hallo,
Ich habe ein wenig mit Ihrem Clip-Path-Ansatz gespielt.
clip-path: inset(0 round 25px);scheint die Arbeit in FF, Safari und Chrome recht gut zu erledigen.Abzweigung Ihres Codepens: hier
Trick für abgerundete Ecken gefunden: hier
Das ist eigentlich super nützlich. Das Beispiel und der Clip-Path-Generator. Vielen Dank!