Existe-t-il un équivalent srcset pour l'image d'arrière-plan css

89

imgwith srcsetattribute ressemble à un excellent moyen de créer des images réactives. Existe-t-il une syntaxe équivalente qui fonctionne dans la background-imagepropriété css ?

HTML

<img src="small.jpg" srcset="medium.jpg 1000w, large.jpg 2000w" alt="yah">

CSS

.mycontainer {
    background: url(?something goes here?);
}
Martin Algesten
la source

Réponses:

81

image-setest la fonctionnalité CSS équivalente. Nous devrions ajouter une fonctionnalité srcset équivalente (définissant les ressources en fonction de leurs dimensions) à la spécification.

Actuellement, il n'est implémenté que dans Safari, Chrome et Opera avec le -webkit-préfixe, et il ne prend en charge que les xdescripteurs.

Yoav Weiss
la source
1
y a-t-il une solution de secours gracieuse connue ou un polyfill supportant cela?
Rachel Cantor
5
@RachelCantor Une solution de secours serait-elle nécessaire? Seuls les appareils modernes auraient de toute façon des écrans Retina, aurais-je pensé?
James Kemp
3
Seule la prise en charge des xdescripteurs semble inutile, je veux dire qu'une image d'arrière-plan pourrait être pleine largeur sur un bureau 2x `` retina '' (5120w), qui sur mobile à 2x (720w) une image de taille ridicule pour tout appareil mobile à considérer même comme une page Web Contexte. Même l'utilisation de requêtes multimédias de largeur maximale pour servir quelques tailles différentes n'est pas si utile, car ce n'est pas la largeur maximale du conteneur d'arrière-plan, sa largeur maximale de l'écran.
Chris Seufert
1
donc si un navigateur ne prend pas en charge l'ensemble d'images, quelle est la solution de secours?
O.MeeKoh
22

À peu près sûr que:

background: -webkit-image-set( url('path/to/image') 1x, url('path/to/high-res-image') 2x );

fonctionne de la même manière. Le navigateur examinera les images, verra celle qui convient le mieux et l'utilisera.

SRing
la source
2
En 2018, cela n'est toujours pas pris en charge par tous les navigateurs. caniuse.com/#search=image-set
BadHorsie
14

Une autre approche, franchement plus robuste, consisterait à adapter les caractéristiques et les options des images d'arrière-plan à une image avec l'attribut srcset.

Pour ce faire, définissez l'image sur la largeur: 100%; hauteur: 100%; et object-fit: couvrir ou contenir.

Voici un exemple:

.pseudo-background-img-container {
  position: relative;
  width:400px;
  height: 200px;
}
.pseudo-background-img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
<div class="pseudo-background-img-container">

<img class="pseudo-background-img" src="https://cdn3.tnwcdn.com/wp-content/blogs.dir/1/files/2016/12/Keep.jpg" srcset="https://cdn0.tnwcdn.com/wp-content/blogs.dir/1/files/2016/12/Keep.jpg 640w, https://cdn0.tnwcdn.com/wp-content/blogs.dir/1/files/2016/12/Keep-280x175.jpg 280w, https://cdn0.tnwcdn.com/wp-content/blogs.dir/1/files/2016/12/Keep-432x270.jpg 432w, https://cdn0.tnwcdn.com/wp-content/blogs.dir/1/files/2016/12/Keep-216x135.jpg 216w" sizes="(max-width: 640px) 100vw, 640px">

</div>

Ce n'est peut-être pas la meilleure approche pour tout le monde, mais j'imagine qu'elle obtiendra la plupart des résultats souhaités sans aucune solution de contournement javascript.

Parcs
la source
1
src-set ne prend pas en compte la largeur de l'image, seulement la largeur du conteneur pour object-fit: cover. Cela signifie que si votre balise img finit par dire 50px de large mais 1000px de haut, l'image qui satisfait la largeur de 50px est chargée et étirée pour s'adapter, peut-être mise à l'échelle de 240w à 1500px de largeur, pour n'afficher qu'une tranche de 50px.
Chris Seufert
11

Pour un polyfill, vous pouvez utiliser un img avec srcset comme mécanisme pour télécharger la taille d'image correcte, puis utiliser JS pour le masquer et définir l'image d'arrière-plan d'un élément parent.

Voici un violon: http://jsbin.com/garetikubu/edit?html,output

Il est important d'utiliser onloadet de placer le JS comme script de blocage dans le <head>. Si vous mettez le script plus tard (dites à la fin de<body> ), vous pouvez obtenir une condition de concurrence où img.currentSrc n'a pas encore été défini par le navigateur. Il est préférable d'attendre qu'il soit chargé.

L'exemple vous permet de voir l'img originale en cours de téléchargement. Vous pouvez facilement le cacher avec du CSS.

Weston
la source
Intéressant. Je me serais attendu à ce que l'image se charge deux fois en faisant cela. Cependant, cela ne semble pas.
Perry
8

Vous pouvez utiliser les requêtes multimédias à vos fins. C'est aussi simple que ça:

.mycontainer {    
    background-image:url("img/image-big.jpg"); // big image   
}

@media(max-width: 768px){
   .mycontainer {
        background-image:url("img/image-sm.jpg"); // small image  
    }
}

Et je pense que cela fonctionne sur tous les navigateurs prenant en charge les requêtes multimédias;)

gtamborero
la source
2
Si votre image est définie pour couvrir un conteneur, cela ne prend pas en compte l'image étirée pour s'adapter à la hauteur, la boîte peut être 2 ou 3 fois la hauteur de la largeur de l'image native et sera donc de très mauvaise qualité.
Chris Seufert
3

Solution similaire utilisant l' <picture>élément: Tutoriel ici

Cas du tutoriel:

Je doute que si j'utilise la même image pour une taille d'écran plus petite, le sujet principal de mon image risque de devenir trop petit. Je souhaite afficher une image différente (plus concentrée sur le sujet principal) dans une taille d'écran différente, mais je souhaite toujours afficher des éléments distincts de la même image en fonction du rapport appareil-pixel, et je souhaite personnaliser la hauteur et la largeur du image basée sur la fenêtre.

Exemple de code:

<picture>

<source media="(max-width: 20em)" srcset="images/small/space-needle.jpg 1x,
images/small/space-needle-2x.jpg 2x, images/small/space-needle-hd.jpg 3x">

<source media="(max-width: 40em)" srcset="images/medium/space-needle.jpg 1x,
images/medium/space-needle-2x.jpg 2x, images/medium/space-needle-hd.jpg 3x">

<img src="space-needle.jpg" alt="Space Needle">

</picture>
Piotr Ścigała
la source
Positionnez l'élément '<picture>' comme 'absolu' ou 'fixe'. Définir le bon z-index + position: relatif pour son conteneur si nécessaire
Piotr Ścigała
gdaniel: Solution JS Ready: github.com/code-mattclaffey / ... Je viens de le tester et ça marche très bien!
Piotr Ścigała
Solution JS, chargement de l'image via l'élément <picture> et l'afficher comme image d'arrière-plan: github.com/code-mattclaffey/…
Piotr Ścigała
2

Si vous utilisez le framework Foundation ( https://foundation.zurb.com/ ), vous pouvez utiliser le plugin Interchange pour cela:

<div data-interchange="[assets/img/interchange/small.jpg, small], 
                       [assets/img/interchange/medium.jpg, medium], 
                       [assets/img/interchange/large.jpg, large]">
</div>

https://foundation.zurb.com/sites/docs/interchange.html#use-with-background-images

Martti Hyvönen
la source
Merci pour ce Martti. Je l'ai bien câblé maintenant aux côtés de Webpack responsive-loaderpour une solution plutôt douce.
fredrivett
1

Sur la base de la réponse de @Weston , j'ai construit une solution jQuery plus générale, vous pouvez simplement copier et coller le JS et le CSS et vous concentrer sur la partie HTML;)

TL; DR - violon: https://jsfiddle.net/dpaa7oz6/

CSS

... pour garantir que les images seront à peine visibles lors du chargement

.srcSet{
  position: fixed;
  z-index: 0;
  z-index: -1;
  z-index: -100;
  /* you could probably also add visibility: hidden; */
}

JS / jQuery

Ce script parcourra toutes les images qui ont srcSetun loadévénement de classe et de liaison qui prend currentSrc(ou srcs'il n'est pas pris en charge) et le place en tant que background-imageCSS au parent le plus proche avec la bgFromSrcSetclasse.

Cela ne suffirait pas en soi! Donc, il met également un vérificateur d'intervalle sur l'window loadévénement pour tester si les événements de chargement sont terminés, sinon, il les déclenche. (l'img loadévénement est très souvent déclenché uniquement lors du premier chargement , lors des chargements suivants, la source de l'image peut être récupérée du cache, ce qui fait que l'événement de chargement img n'est PAS déclenché! )

jQuery(function($){ //ON DOCUMENT READY
  var $window = $(window); //prepare window as jQuery object

  var $srcSets = $('.srcSet'); //get all images with srcSet clas
  $srcSets.each(function(){ //for each .srcSet do...
    var $currImg = $(this); //prepare current srcSet as jQuery object

    $currImg
      .load(function(){ //bind the load event
          var img = $currImg.get(0); //retrieve DOM element from $currImg

          //test currentSrc support, if not supported, use the old src
          var src = img.currentSrc ? img.currentSrc : img.src;

          //To the closest parent with bgFromSrcSet class,
          //set the final src as a background-image CSS
          $currImg.closest('.bgFromSrcSet').css('background-image', "url('"+src+"')");

          //remove processed image from the jQuery set
          //(to update $srcSets.length that is checked in the loadChecker)
          $srcSets = $srcSets.not($currImg);

          $currImg.remove(); //remove the <img ...> itself 
      })
    ;      

  });

  //window's load event is called even on following loads...
  $window.load(function(){    
    //prepare the checker
    var loadChecker = setInterval(function(){
        if( $srcSets.length > 0 ) //if there is still work to do...
            $srcSets.load(); //...do it!
        else
            clearInterval(loadChecker); //if there is nothing to do - stop the checker
    }, 150);  
  });

});

HTML

... pourrait ressembler à ceci:

<div class="bgFromSrcSet">
  <img class="srcSet"
       alt=""
       src="http://example.com/something.jpeg" 
       srcset="http://example.com/something.jpeg 5760w, http://example.com/something-300x200.jpeg 300w, http://example.com/something-768x512.jpeg 768w, http://example.com/something-1024x683.jpeg 1024w, http://example.com/something-1000x667.jpeg 1000w"
       sizes="(max-width: 2000px) 100vw, 2000px"
  >
  Something else...
</div>

Remarque: la classe nebgFromSrcSet doit pas être définie sur imgelle - même! Il ne peut être défini que sur les éléments de l' imgarborescence parent DOM.

jave.web
la source