Die CSS-Funktion image-set() wird in Chromium-basierten Browsern seit 2012 und in Safari seit Version 6 unterstützt. Kürzlich erfolgte die Unterstützung auch in Firefox 88. Tauchen wir ein und sehen wir, was wir heute mit image-set() tun können und was nicht.
Mehrere Auflösungen desselben Bildes
Das sagt die CSS-Spezifikation über image-set():
Die Bereitstellung der am besten geeigneten Bildauflösung für das Gerät eines Benutzers kann eine schwierige Aufgabe sein. Idealerweise sollten Bilder die gleiche Auflösung wie die Geräte haben, auf denen sie angezeigt werden, was von Benutzer zu Benutzer variieren kann. Andere Faktoren können jedoch in die Entscheidung einfließen, welches Bild gesendet werden soll. Wenn ein Benutzer beispielsweise eine langsame mobile Verbindung hat, bevorzugt er möglicherweise niedrigere Auflösungsbilder, anstatt auf ein großes Bild mit richtiger Auflösung zu warten.
Dies ist im Grunde ein CSS-Hintergrund-Äquivalent zum HTML-Attribut srcset für img-Tags. Durch die Verwendung von image-set können wir mehrere Auflösungen eines Bildes bereitstellen und dem Browser vertrauen, die beste Entscheidung darüber zu treffen, welches verwendet werden soll. Dies kann verwendet werden, um einen Wert für drei verschiedene CSS-Eigenschaften anzugeben: content, cursor und, am nützlichsten von allen, background-image.
.hero {
background-image: image-set("platypus.png" 1x, "platypus-2x.png" 2x);
}
1x wird verwendet, um das Bild mit niedriger Auflösung zu identifizieren, während 2x verwendet wird, um das Bild mit hoher Auflösung zu definieren. x ist ein Alias von dppx, was für **dots per pixel unit** (Punkte pro Pixeleinheit) steht.
Chrome/Edge/Opera/Samsung Internet benötigen derzeit ein -webkit--Präfix. Wenn Sie Autoprefixer verwenden, wird dies automatisch gehandhabt. Safari benötigt das Präfix nicht mehr, verwendet aber eine ältere Syntax, die eine url()-Funktion zum Angeben des Bildpfads erfordert. Wir könnten auch ein normales background-image: url() einfügen, um Browser zu unterstützen, die image-set nicht unterstützen.
.hero {
/* Fallback */
background-image: url("platypus.png");
/* Chrome/Edge/Opera/Samsung, Safari will fallback to this as well */
background-image: -webkit-image-set(url("platypus.png") 1x, url("platypus-2x.png") 2x);
/* Standard use */
background-image: image-set("platypus.png" 1x, "platypus-2x.png" 2x);
}
Jetzt werden Benutzer auf teuren, schicken Geräten ein gestochen scharfes Bild sehen. Die Leistung wird für Benutzer mit langsamen Verbindungen oder günstigeren Bildschirmen verbessert, da ihr Browser automatisch das Bild mit niedrigerer Auflösung anfordert. Wenn Sie sicherstellen wollten, dass das Bild mit hoher Auflösung auf Geräten mit hoher Auflösung auch bei langsamen Verbindungen verwendet wird, könnten Sie stattdessen die Medienabfrage min-resolution anstelle von image-set verwenden. Mehr über das Ausliefern von scharfen Bildern für hochauflösende Bildschirme erfahren Sie in Jake Archibalds aktuellem Beitrag auf seinem Blog.
Das ist ziemlich cool, aber was ich wirklich will, ist die Möglichkeit, die neuesten Bildformate in CSS zu übernehmen und gleichzeitig ältere Browser zu berücksichtigen…
Neue Bildformate
Safari 14 hat die Unterstützung für WebP eingeführt. Es war der letzte moderne Browser, der dies tat, was bedeutet, dass das Bildformat jetzt überall unterstützt wird (außer im Internet Explorer). WebP ist nützlich, da es Bilder erzeugen kann, die oft kleiner sind als (aber die gleiche Qualität wie) JPG, PNG oder GIF.
Es tauchen auch eine ganze Reihe noch neuerer Bildformate auf. AVIF-Bilder sind schockierend klein. Chrome, Opera und Samsung Internet haben die Unterstützung für AVIF bereits eingeführt. In Firefox ist es bereits hinter einem Flag. Dieses Bildformat wird noch von vielen Design-Tools nicht unterstützt, aber Sie können Bilder mit der Squoosh-App, die vom Chrome-Team bei Google entwickelt wurde, in AVIF konvertieren. WebP 2, HEIF und JPEG XL könnten schließlich auch in Browsern landen. Das ist alles ziemlich aufregend, aber wir möchten, dass Browser, die diese neueren Formate nicht unterstützen, trotzdem einige Bilder erhalten. Glücklicherweise hat image-set() eine Syntax dafür.
Neue Bildformate durch Angabe eines Typs verwenden
Hinweis zur Browserunterstützung: Das Feature von image-set, über das ich gleich sprechen werde, hat derzeit eine ziemlich schlechte Browserunterstützung. Derzeit wird es nur in Firefox 89 unterstützt.
HTML unterstützt das <picture>-Element seit Jahren.
<picture>
<source srcset="./kitten.avif" type="image/avif">
<img src="./kitten.jpg" alt="a small kitten">
</picture>
image-set bietet das CSS-Äquivalent und ermöglicht die Verwendung von Next-Gen-Bildformaten durch Angabe des MIME-Typs des Bildes.
.div1 {
background-image: image-set(
"kitten.avif" type("image/avif"),
"kitten.jpg" type("image/jpeg")
);
}
Das Next-Gen-Bild steht zuerst, während das Fallback-Bild für ältere Browser an zweiter Stelle steht. Nur ein Bild wird heruntergeladen. Wenn der Browser AVIF nicht unterstützt, ignoriert er es und lädt nur das zweite von Ihnen angegebene Bild herunter. Wenn AVIF unterstützt wird, wird das Fallback-Bild ignoriert.
Im obigen Beispiel haben wir ein AVIF-Bild verwendet und ein JPEG als Fallback bereitgestellt, aber das Fallback könnte jedes weit verbreitete Bildformat sein. Hier ist ein Beispiel mit einem PNG.
.div2 {
background-image: image-set(
"puppy.webp" type("image/webp"),
"puppy.png" type("image/png")
);
}
In Chrome und Safari wird die Angabe des type noch nicht unterstützt. Das bedeutet, dass Sie image-set heute nur verwenden können, um verschiedene Auflösungen von weit verbreiteten Bildformaten anzugeben, aber nicht, um Rückwärtskompatibilität hinzuzufügen, wenn Sie WebP oder AVIF in diesen Browsern verwenden. Es sollte möglich sein, sowohl mehrere Auflösungen als auch mehrere Bildformate bereitzustellen, wenn Sie dazu geneigt sind.
.div2 {
background-image: image-set(
"puppy.webp" type("image/webp") 1x,
"puppy2x.webp" type("image/webp") 2x,
"puppy.png" type("image/png") 1x,
"puppy2x.png" type("image/png") 2x
);
}
Hoffentlich verbessert sich die Browserunterstützung bald.
Verwendung von <picture> stattdessen für Hintergründe
Vielleicht brauchen Sie background-image gar nicht mehr. Wenn Sie moderne Bildformate verwenden möchten, können Sie möglicherweise das <picture>-Element verwenden, das eine bessere Browserunterstützung hat. Wenn Sie das Bild auf position: absolute setzen, ist es einfach, andere Elemente darüber anzuzeigen.
Als Alternative zur Verwendung von position: absolute ist CSS Grid eine weitere einfache Möglichkeit, HTML-Elemente zu überlagern.
Hier ist ein Link zum Chrome-Bug für das Entfernen des Präfixes bei image-set(). Bitte stimmen Sie dafür, damit das Chrome-Team weiß, dass Sie es wollen: https://bugs.chromium.org/p/chromium/issues/detail?id=630597&q=css%20image-set&can=2
Danke für den Link.
Das war super hilfreich. Danke!
Danke, aber wie kann ich Hintergrundbilder noch lazy laden?
Lazysizes hat ein bgset-Plugin dafür: https://github.com/aFarkas/lazysizes/tree/gh-pages/plugins/bgset
Das ist alles gut und schön, aber ich frage mich, wie viele Websites die Ressourcen und die Zeit haben, Bildersets für all ihre Inhaltsbilder zu erstellen?
Ich glaube, ein beträchtlicher Prozentsatz kann es sich nur leisten, mit einem Bildformat und einer Auflösung auszukommen.
Ja, wahrscheinlich wahr. Aber hey, jetzt können wir CSS nicht dafür verantwortlich machen, dass es keine Option dafür gibt.
Nun, wenn Sie ein CDN verwenden, um Ihre Mediendateien zu hosten, haben diese möglicherweise eine Konvertierung im laufenden Betrieb. Zum Beispiel: `https://uploadcare.com/`. Sie müssen nur das größte Bild hochladen und können jede Größe/Qualität im laufenden Betrieb anfordern.
Ich persönlich ziehe es mittlerweile vor, Hintergründe aus Gründen der Barrierefreiheit nicht mehr zu verwenden, da man immer noch keine SEO-relevanten Metadaten auf ein Hintergrundbild legen kann. Für das, wofür die meisten Leute Hintergrundbilder verwenden, kann man heutzutage leicht object-fit + object-position verwenden.
Der einzig wirkliche Anwendungsfall sind heutzutage wiederholende Hintergründe, meiner Meinung nach.
Aber es ist trotzdem gut zu wissen, dass es endlich eine Lösung für das Performance-Problem gibt, das damit lange verbunden war.
Laut Can I Use wird die type()-Funktion von allen wichtigen Browsern unterstützt, mit Ausnahme von Safari (Desktop & iOS). Siehe https://caniuse.com/css-image-set
Wenn ich die type()-Funktion verwende, wird ein nicht unterstützender Browser (d.h. Safari) den Rest der Regel trotzdem beachten? Oder muss ich separate Regeln für Safari schreiben, z.B.
.div1 {background-image: image-set(
"kitten.avif" type("image/avif") 1x,
"kitten.jpg" type("image/jpeg") 1x,
"kitten2x.avif" type("image/avif") 2x,
"kitten2x.jpg" type("image/jpeg") 2x,
"kitten.jpg" 1x, // für Safari
"kitten2x.jpg" 2x // für Safari
);
}
Ich habe diese Lösung ausprobiert, aber sie funktioniert nicht. Egal was passiert, die jpg-Datei wird geladen.
background-image: url("../../assets/images/banner2.jpg");background-image: linear-gradient(to top, rgba(black, 0.6), rgba(black, 0.6)),-webkit-image-set(url("../../assets/images/banner2.webp") 1x);
background-image: linear-gradient(to top, rgba(black, 0.6), rgba(black, 0.6)),image-set(url("../../assets/images/banner2.webp") 1x);
Das ist mein Code. Ich habe sogar versucht, type() hinzuzufügen.
Danke Ollie
Es funktioniert perfekt
Wie können wir Media Queries inline verwenden? Die 1x und 2x tun das nicht.
Der einzige Weg, den ich herausfinden kann, ist, eine Klasse zu erstellen und sie dann innerhalb dedizierter Media Queries hinzuzufügen – aber ich kann keinen Weg finden, dies inline zu tun.
Ich habe ein neues MacBook mit Chrome Version 102.0.5005.61, was in Ordnung sein sollte. Allerdings erhalte ich 'ungültiger Eigenschaftswert' und es wird die Fallback-Option verwendet. Selbst wenn ich hier das Beispiel mit den absoluten Bild-URLs einfüge. Irgendwelche Ideen, warum das sein könnte?
Ich habe in den MDN-Dokumenten bemerkt, dass manchmal verwendet wird
background-image: image-set(
url("large-balloons.avif") type("image/avif"),
und manchmal
background-image: image-set(
"large-balloons.avif" type("image/avif"),
Beides versucht, kein Erfolg. Irgendwelche Ideen?
Hallo Ben. Der Artikel ist etwas irreführend, da Ollie sagt, dass Sie
type()mit Chrome nicht verwenden können, was korrekt ist, aber dann ein Beispiel folgt, dastype()verwendet, was nicht funktionieren wird.image-setin Chrome (zum Zeitpunkt der Erstellung dieses Textes)muss ein Präfix haben,
muss die URL in die url()-Funktion einpacken
muss einen dppx-Wert haben, z.B. 1x, 2x.
und darf kein type() haben
Jede andere Kombination ist in meinen Tests fehlgeschlagen.
Das bedeutet, dass image-set() derzeit nur zum Festlegen der Pixeldichte des zu verwendenden Bildes nützlich ist, außer bei Firefox.
Um sein Beispiel neu zu schreiben, müsste es eher so aussehen:
Realistisch gesehen ist für eine rein statische Website WEBP das einzig lohnenswerte Format, das wir derzeit mit Chrome und image-set() verwenden können. Der Grund dafür ist, dass Edge -webkit-image-set unterstützt (da es ein Chromium-basierter Browser ist), aber AVIF noch nicht unterstützt. Da die Syntax korrekt wäre, der Dateityp aber nicht unterstützt wird, würde Edge das Hintergrundbild einfach ignorieren und nicht auf das JPG in Zeile 6 zurückgreifen. (Ich habe es nicht direkt getestet, aber das ist im Allgemeinen das, was passiert, wenn die Syntax stimmt, aber mit der Datei selbst etwas nicht stimmt, z. B. Beschädigung oder eine 404, aber ich lasse mich gerne korrigieren.)
Zusätzlich, ohne die type()-Funktion, um dem Browser mitzuteilen, welche anderen MIME-Typen verfügbar sind, hat es keinen Sinn, andere Optionen bereitzustellen. Die gute Nachricht ist, dass WEBP jetzt sehr gut unterstützt wird, aber wenn der Browser es nicht tut, wird er wahrscheinlich auch image-set() nicht unterstützen, sodass er in diesem Fall auf das JPG zurückgreift.
Alles in allem, wenn Sie ein
<picture>-Element verwenden können, wie Ollie vorschlägt, oder ein Bild-CDN, können Sie all dies umgehen.Hilft das?