Existe um equivalente srcset para imagem de fundo css

91

imgcom srcsetatributo parece uma ótima maneira de fazer imagens responsivas. Existe uma sintaxe equivalente que funciona na background-imagepropriedade css ?

HTML

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

CSS

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

Respostas:

83

image-seté o recurso CSS equivalente. Devemos adicionar funcionalidade srcset equivalente (definindo recursos de acordo com suas dimensões) para a especificação.

Atualmente, só é implementado no Safari, Chrome e Opera com o -webkit-prefixo, e suporta apenas os xdescritores.

Yoav Weiss
fonte
1
existe algum substituto elegante conhecido ou um polyfill apoiando isso?
Rachel Cantor
5
@RachelCantor Seria necessário um substituto? Só os dispositivos modernos teriam telas de retina, eu teria pensado?
James Kemp
3
Apenas apoiar os xdescritores parece inútil, quero dizer que uma imagem de fundo pode ser de largura total em um desktop 'retina' 2x (5120w), que em dispositivos móveis a 2x (720w) uma imagem de tamanho ridículo para qualquer dispositivo móvel até mesmo considerar como uma página da web fundo. Mesmo usar consultas de mídia de largura máxima para atender a alguns tamanhos diferentes não é tão útil, porque não é largura máxima do contêiner de fundo, mas largura máxima da tela.
Chris Seufert
1
portanto, se um navegador não oferece suporte ao conjunto de imagens, qual é o fallback?
O.MeeKoh
22

Tenho certeza de que:

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

funciona da mesma maneira. O navegador examinará as imagens, verá qual se encaixa melhor e usará aquela.

SRing
fonte
2
Em 2018, isso ainda não é compatível com todos os navegadores. caniuse.com/#search=image-set
BadHorsie
17

Outra abordagem, francamente mais robusta, seria adaptar as características e opções das imagens de fundo a uma imagem com o atributo srcset.

Para fazer isso, defina a largura da imagem: 100%; altura: 100%; e ajuste ao objeto: cobrir ou conter.

Aqui está um exemplo:

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

Esta pode não ser a melhor abordagem para todos, mas imagino que obterá mais os resultados desejados sem qualquer solução alternativa de javascript.

Parques
fonte
1
src-set não leva em consideração a largura da imagem, apenas a largura do contêiner para o ajuste do objeto: capa. Isso significa que se sua tag img terminar, digamos, 50px de largura, mas 1000px de altura, a imagem que satisfaz a largura de 50px é carregada e esticada para caber, talvez dimensionada de 240w a 1500px de largura, para exibir apenas uma fatia de 50px.
Chris Seufert
11

Para um polyfill, você pode usar um img com srcset como um mecanismo para baixar o tamanho correto da imagem, então usar JS para escondê-lo e definir a imagem de fundo de um elemento pai.

Aqui está um violino: http://jsbin.com/garetikubu/edit?html,output

É importante usar onloade colocar o JS como um script de bloqueio no <head>. Se você colocar o script mais tarde (digamos, no final de <body>), poderá obter uma condição de corrida em que img.currentSrc ainda não foi definido pelo navegador. É melhor esperar que seja carregado.

O exemplo permite que você veja o img original sendo baixado. Você pode facilmente ocultá-lo com algum CSS.

Weston
fonte
Interessante. Eu esperava que a imagem carregasse duas vezes ao fazer isso. No entanto, não parece.
Perry
9

Você pode usar consultas de mídia para seu propósito. É fácil assim:

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

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

E acho que funciona em todos os navegadores que oferecem suporte a consultas de mídia;)

gtamborero
fonte
2
Se sua imagem estiver configurada para cobrir um contêiner, isso não leva em consideração a imagem sendo esticada para caber na altura, a caixa pode ser 2 ou 3 vezes a altura da largura da imagem nativa e, portanto, terá uma qualidade muito baixa.
Chris Seufert
3

Solução semelhante usando o <picture>elemento: Tutorial aqui

Caso do tutorial:

Tenho dúvidas de que, se usar a mesma imagem para uma tela menor, o tema principal da minha imagem possa ficar muito pequeno. Quero exibir uma imagem diferente (mais focada no assunto principal) em um tamanho de tela diferente, mas ainda quero exibir ativos separados da mesma imagem com base na proporção de pixel do dispositivo e quero personalizar a altura e a largura do imagem baseada na janela de visualização.

Código de exemplo:

<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
fonte
Posicione o elemento '<picture>' como 'absoluto' ou 'fixo'. Defina a posição z-index + correta: relativa para seu contêiner, se necessário
Piotr Ścigała
gdaniel: Solução JS pronta: github.com/code-mattclaffey/… Acabei de testar e está funcionando muito bem!
Piotr Ścigała
Solução JS, carregando imagem por meio do elemento <picture> e exibindo-a como imagem de fundo: github.com/code-mattclaffey/…
Piotr Ścigała
2

Se você estiver usando a estrutura Foundation ( https://foundation.zurb.com/ ), poderá usar o plug-in Interchange para isso:

<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
fonte
Obrigado por este Martti. Eu tenho isso conectado muito bem agora ao lado do webpack responsive-loaderpara uma solução bem legal.
Fredrivett
1

Com base na resposta de @Weston , eu construí uma solução jQuery mais geral, você pode basicamente apenas copiar e colar o JS e CSS e se concentrar na parte HTML;)

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

CSS

... para garantir que as imagens dificilmente serão visíveis durante o carregamento

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

JS / jQuery

Este script irá percorrer todas as imagens que possuem srcSetclasse e loadevento de ligação que leva currentSrc(ou srcse não for compatível) e o coloca como um background-imageCSS para o pai mais próximo com bgFromSrcSetclasse.

Isso por si só não seria suficiente! Portanto, ele também coloca um verificador de intervalo nowindow loadevento para testar se os eventos de carregamento foram concluídos, caso contrário, ele os aciona. (oimg loadevento geralmente é disparado apenas no carregamento inicial , nos carregamentos seguintes, a origem da imagem pode ser recuperada do cache, resultando no evento img load NÃO sendo disparado! )

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

... poderia ser assim:

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

Nota: a classe nãobgFromSrcSet deve ser definida como o próprio! Ele só pode ser definido para os elementos na árvore pai do DOM.imgimg

jave.web
fonte