Có srcset tương đương cho ảnh nền css không


89

imgvới srcsetthuộc tính trông giống như một cách tuyệt vời để thực hiện hình ảnh đáp ứng. Có một cú pháp tương đương hoạt động trong thuộc tính css background-imagekhông?

HTML

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

CSS

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

Câu trả lời:


81

image-setlà tính năng CSS tương đương. Chúng ta nên thêm chức năng srcset tương đương (xác định tài nguyên theo kích thước của chúng) vào thông số kỹ thuật.

Hiện tại, nó chỉ được triển khai trong Safari, Chrome và Opera với -webkit-tiền tố và nó chỉ hỗ trợ các bộ xmô tả.


1
có bất kỳ dự phòng duyên dáng nào được biết đến hoặc một polyfill hỗ trợ điều này không?
Rachel Cantor

5
@RachelCantor Có cần dự phòng không? Dù sao thì chỉ có các thiết bị hiện đại mới có màn hình retina, tôi nghĩ vậy?
James Kemp,

3
Chỉ hỗ trợ các bộ xmô tả có vẻ vô nghĩa, ý tôi là hình nền có thể có chiều rộng đầy đủ trên máy tính để bàn 'retina' 2x (5120w), trên thiết bị di động ở 2x (720w) là một hình ảnh có kích thước vô lý cho bất kỳ thiết bị di động nào thậm chí có thể coi là một trang web lý lịch. Ngay cả khi sử dụng các truy vấn phương tiện có chiều rộng tối đa để phân phát một vài kích thước khác nhau cũng không hữu ích, bởi vì chiều rộng tối đa của vùng chứa nền không phải là chiều rộng tối đa của màn hình.
Chris Seufert

1
vậy nếu trình duyệt không hỗ trợ thiết lập hình ảnh thì dự phòng là gì?
O.MeeKoh

22

Khá chắc chắn rằng:

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

hoạt động theo cùng một cách. Trình duyệt sẽ kiểm tra hình ảnh, xem hình ảnh nào phù hợp nhất và sẽ sử dụng hình ảnh đó.


2
Trong năm 2018, điều này vẫn chưa được hỗ trợ bởi tất cả các trình duyệt. caniuse.com/#search=image-set
BadHorsie

14

Một cách tiếp cận khác, khá thẳng thắn là mạnh mẽ hơn, sẽ là điều chỉnh các đặc điểm và tùy chọn của hình nền thành hình ảnh có thuộc tính srcset.

Để thực hiện việc này, hãy đặt hình ảnh có chiều rộng: 100%; chiều cao: 100%; và object-fit: che hoặc chứa.

Đây là một ví dụ:

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

Đây có thể không phải là cách tiếp cận tốt nhất cho tất cả mọi người nhưng tôi tưởng tượng nó sẽ nhận được hầu hết các kết quả mong muốn mà không cần bất kỳ giải pháp javascript nào.


1
src-set không tính đến chiều rộng hình ảnh, chỉ tính đến chiều rộng vùng chứa cho object-fit: cover. Điều này có nghĩa là nếu thẻ img của bạn kết thúc bằng chiều rộng 50px nhưng cao 1000px, hình ảnh đáp ứng chiều rộng 50px sẽ được tải và kéo dài cho vừa vặn, có thể được chia tỷ lệ từ chiều rộng 240w đến 1500px, để chỉ hiển thị một lát 50px.
Chris Seufert

11

Đối với polyfill, bạn có thể sử dụng img với srcset làm cơ chế để tải xuống kích thước hình ảnh chính xác, sau đó sử dụng JS để ẩn nó và đặt hình nền của phần tử mẹ.

Đây là một trò chơi: http://jsbin.com/garetikubu/edit?html,output

Việc sử dụng onloadvà đặt JS làm tập lệnh chặn trong <head>là quan trọng. Nếu bạn đặt tập lệnh muộn hơn (giả sử ở cuối <body>), bạn có thể nhận được điều kiện đua mà img.currentSrc chưa được trình duyệt đặt. Tốt nhất bạn nên đợi nó được tải.

Ví dụ này cho phép bạn xem img gốc đang được tải xuống. Bạn có thể dễ dàng ẩn nó bằng một số CSS.


Hấp dẫn. Tôi đã mong đợi hình ảnh tải hai lần khi làm điều này. Tuy nhiên, nó dường như không.
Perry

8

Bạn có thể sử dụng các truy vấn phương tiện cho mục đích của mình. Thật dễ dàng như sau:

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

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

Và tôi nghĩ nó hoạt động trên mọi trình duyệt hỗ trợ truy vấn phương tiện;)


2
Nếu hình ảnh của bạn được đặt để che một vùng chứa, điều này không tính đến việc hình ảnh được kéo dài để vừa với chiều cao, hộp có thể gấp 2 hoặc 3 lần chiều cao của chiều rộng hình ảnh gốc và do đó chất lượng sẽ rất kém.
Chris Seufert

3

Giải pháp tương tự sử dụng <picture>phần tử: Hướng dẫn tại đây

Trường hợp của hướng dẫn:

Tôi nghi ngờ rằng nếu tôi sử dụng cùng một hình ảnh cho kích thước màn hình nhỏ hơn, đối tượng chính của hình ảnh của tôi có thể trở nên quá nhỏ. Tôi muốn hiển thị một hình ảnh khác (tập trung hơn vào chủ thể chính) ở một kích thước màn hình khác, nhưng tôi vẫn muốn hiển thị các phần tử riêng biệt của cùng một hình ảnh dựa trên tỷ lệ pixel thiết bị và tôi muốn tùy chỉnh chiều cao và chiều rộng của hình ảnh dựa trên khung nhìn.

Mã ví dụ:

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

Định vị phần tử '<picture>' là 'tuyệt đối' hoặc 'cố định'. Set đúng z-index + position: relative cho container của nó nếu cần thiết
Piotr Ścigała

gdaniel: Giải pháp JS sẵn sàng: github.com/code-mattclaffey/… Tôi vừa thử nghiệm nó và nó hoạt động rất tốt!
Piotr Ścigała

Giải pháp JS, tải hình ảnh qua <picture> phần tử và hiển thị nó như một background-image: github.com/code-mattclaffey/...
Piotr Ścigała

2

Nếu bạn đang sử dụng khuôn khổ Foundation ( https://foundation.zurb.com/ ), bạn có thể sử dụng plugin Interchange cho điều đó:

<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


Cảm ơn vì Martti này. Tôi đã kết nối nó một cách tuyệt vời ngay bây giờ cùng với webpack responsive-loaderđể có một giải pháp khá thú vị.
fredrivett

1

Dựa trên câu trả lời của @Weston , tôi đã xây dựng một giải pháp jQuery tổng quát hơn, về cơ bản bạn có thể chỉ cần sao chép & dán JS và CSS và tập trung vào phần HTML;)

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

CSS

... để đảm bảo hình ảnh sẽ khó được nhìn thấy trong khi tải

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

JS / jQuery

Tập lệnh này sẽ đi qua tất cả các hình ảnh có srcSetlớp và loadsự kiện ràng buộc nhận currentSrc(hoặc srcnếu không được hỗ trợ) và đặt nó dưới dạng background-imageCSS cho cha mẹ gần nhất với bgFromSrcSetlớp.

Chính điều đó sẽ không đủ! Vì vậy, nó cũng đặt một trình kiểm tra khoảng thời gian trênwindow loadsự kiện để kiểm tra xem các sự kiện tải đã được hoàn thành hay chưa, nếu chưa, nó sẽ kích hoạt chúng. (img loadsự kiện rất thường chỉ được kích hoạt khi tải lần đầu , ở những lần tải sau, nguồn hình ảnh có thể được truy xuất từ ​​bộ nhớ đệm, dẫn đến sự kiện tải img KHÔNG được kích hoạt! )

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

... có thể trông như thế này:

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

Lưu ý: lớp bgFromSrcSetphải không được thiết lập để imgchính nó! Nó chỉ có thể được đặt thành các phần tử trong imgcây mẹ DOM.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.