Czy istnieje odpowiednik srcset dla obrazu tła css?

89

imgz srcsetatrybutem wygląda na świetny sposób na tworzenie responsywnych obrazów. Czy istnieje równoważna składnia, która działa we background-imagewłaściwości CSS ?

HTML

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

CSS

.mycontainer {
    background: url(?something goes here?);
}
Martin Algesten
źródło

Odpowiedzi:

81

image-setjest równoważną funkcją CSS. Do specyfikacji powinniśmy dodać równoważną funkcjonalność srcset (definiowanie zasobów według ich wymiarów).

Obecnie jest zaimplementowany tylko w Safari, Chrome i Opera z -webkit-prefiksem i obsługuje tylko xdeskryptory.

Yoav Weiss
źródło
1
czy jest znana jakaś pełna wdzięku funkcja awaryjna lub polifill wspierający to?
Rachel Cantor
5
@RachelCantor Czy rozwiązanie awaryjne byłoby konieczne? Tylko nowoczesne urządzenia i tak będą miały ekrany siatkówkowe, pomyślałem?
James Kemp,
3
Tylko obsługa xdeskryptorów wydaje się bezcelowa, mam na myśli, że obraz tła może mieć pełną szerokość na pulpicie 2x 'Retina' (5120 W), co na telefonie komórkowym przy 2x (720 W) jest obrazem o absurdalnym rozmiarze dla dowolnego urządzenia mobilnego, aby nawet uznać go za stronę internetową tło. Nawet użycie zapytań o media o maksymalnej szerokości do obsługi kilku różnych rozmiarów nie jest tak pomocne, ponieważ nie jest to maksymalna szerokość kontenera tła, jego maksymalna szerokość ekranu.
Chris Seufert
1
więc jeśli przeglądarka nie obsługuje zestawu obrazów, jaka jest opcja zastępcza?
O. MeeKoh
22

Jestem prawie pewien, że:

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

działa w ten sam sposób. Przeglądarka sprawdzi obrazy, sprawdzi, który najlepiej pasuje i użyje tego.

SRing
źródło
2
W 2018 roku nadal nie jest to obsługiwane przez wszystkie przeglądarki. caniuse.com/#search=image-set
BadHorsie
14

Innym podejściem, które, szczerze mówiąc, jest bardziej niezawodne, byłoby dostosowanie cech i opcji obrazów tła do obrazu z atrybutem srcset.

Aby to zrobić, ustaw obraz na szerokość: 100%; wysokość: 100%; i dopasuj do obiektu: zakryj lub schowaj.

Oto przykład:

.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>

To może nie być najlepsze podejście dla wszystkich, ale wyobrażam sobie, że da najbardziej pożądane rezultaty bez żadnego obejścia javascript.

Parki
źródło
1
src-set nie bierze pod uwagę szerokości obrazu, tylko szerokość kontenera dla object-fit: cover. Oznacza to, że jeśli tag img kończy się, powiedzmy, szerokością 50 pikseli, ale wysokością 1000 pikseli, obraz, który spełnia szerokość 50 pikseli, jest ładowany i rozciągany w celu dopasowania, może być przeskalowany z szerokości 240 do 1500 pikseli, aby wyświetlić tylko wycinek 50 pikseli.
Chris Seufert,
11

W przypadku polyfill możesz użyć img z srcset jako mechanizmu pobierania obrazu o prawidłowym rozmiarze, a następnie użyć JS, aby go ukryć i ustawić obraz tła elementu nadrzędnego.

Oto skrzypce: http://jsbin.com/garetikubu/edit?html,output

Użycie onloadi umieszczenie JS jako skryptu blokującego w programie <head>jest ważne. Jeśli umieścisz skrypt później (powiedzmy na końcu <body>), możesz uzyskać warunek wyścigu, w którym img.currentSrc nie został jeszcze ustawiony przez przeglądarkę. Najlepiej poczekać, aż się załaduje.

Przykład pozwala zobaczyć, jak oryginalny plik img jest pobierany. Możesz to łatwo ukryć za pomocą CSS.

Weston
źródło
Ciekawy. Spodziewałbym się, że obraz załaduje się dwukrotnie podczas wykonywania tej czynności. Jednak nie wydaje się.
Perry
8

Zapytań o media możesz używać do swoich celów. To takie proste:

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

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

Myślę, że działa na każdej przeglądarce obsługującej zapytania o media;)

gtamborero
źródło
2
Jeśli obraz jest ustawiony na zakrywanie kontenera, nie uwzględnia to rozciągnięcia obrazu w celu dopasowania do wysokości, ramka może być 2 lub 3 razy większa niż szerokość obrazu natywnego i dlatego będzie wyglądać bardzo słabej jakości.
Chris Seufert,
3

Podobne rozwiązanie za pomocą <picture>elementu: Tutorial tutaj

Przypadek samouczka:

Wątpię, czy jeśli użyję tego samego obrazu na mniejszym ekranie, główny temat mojego obrazu może stać się zbyt mały. Chcę wyświetlić inny obraz (bardziej skupiony na głównym temacie) na innym rozmiarze ekranu, ale nadal chcę wyświetlać osobne zasoby tego samego obrazu na podstawie współczynnika pikseli urządzenia i chcę dostosować wysokość i szerokość obraz oparty na widocznym obszarze.

Przykładowy kod:

<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
źródło
Ustaw element „<picture>” jako „bezwzględny” lub „stały”. Ustaw poprawny indeks z + pozycja: względna dla kontenera, jeśli to konieczne
Piotr Ścigała
gdaniel: Gotowe rozwiązanie JS: github.com/code-mattclaffey/ ... Właśnie je przetestowałem i działa świetnie!
Piotr Ścigała
Rozwiązanie JS, ładowanie obrazu przez element <picture> i wyświetlanie go jako background-image: github.com/code-mattclaffey/…
Piotr Ścigała
2

Jeśli korzystasz z platformy Foundation ( https://foundation.zurb.com/ ), możesz użyć do tego wtyczki Interchange:

<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
źródło
Dzięki za to Martti. Mam to teraz ładnie połączone z pakietami internetowymi, responsive-loaderaby uzyskać całkiem słodkie rozwiązanie.
fredrivett
1

Bazując na odpowiedzi @Weston , stworzyłem bardziej ogólne rozwiązanie jQuery, możesz po prostu skopiować i wkleić JS i CSS i skupić się na części HTML;)

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

CSS

... aby upewnić się, że podczas ładowania obrazy będą prawie niewidoczne

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

JS / jQuery

Ten skrypt przejdzie przez wszystkie obrazy, które mają zdarzenie srcSetclass i bind load, które przyjmuje currentSrc(lub srcjeśli nie jest obsługiwane) i umieści je jako background-imageCSS najbliższemu rodzicowi z bgFromSrcSetklasą.

Samo to nie wystarczy! Dlatego umieszcza również sprawdzanie interwałów nawindow loadzdarzeniu, aby sprawdzić, czy zdarzenia obciążenia zostały zakończone, jeśli nie, wyzwala je. (img loadzdarzenie jest bardzo często wyzwalane tylko przy pierwszym załadowaniu , przy kolejnych ładowaniach źródło obrazu może zostać pobrane z pamięci podręcznej, co powoduje , że zdarzenie ładowania obrazu NIE jest uruchamiane! )

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

... może wyglądać tak:

<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>

Uwaga: klasa bgFromSrcSetmusi nie być ustawiony na imgsobie! Można go ustawić tylko dla elementów w imgdrzewie nadrzędnym DOM.

jave.web
źródło