1

I have a section with a fullscreen background image that is loaded via a JavaScript data-attribute. As this is a responsive site, the same background image (1920 x 1080px) is scaled up and down depending on the screen size, which is not very performance-friendly, e.g. on mobile phones with smaller screen sizes.

HTML:

<!-- BEGIN PAGE TITLE -->
<section id="page-title" class="page-title-lg" data-bg-img="nature/full-20.jpg">
  <div class="container">
    <div class="page-title-wrapper">
      <div class="page-title-txt">
        <h1>Large Page Title</h1>
      </div>
    </div>
  </div>
</section>
<!-- END PAGE TITLE -->

JS:

// Image Background 
$('[data-bg-img]').each(function() {
      var dataImg = $(this).attr('data-bg-img');
      $(this).css('background-image', 'url(assets/img/' + dataImg + ')');
 });

Is there a way to dynamically detect the window size and load the appropriate image via different data-attributes (e.g. 2560 x 1440, 1920 x 1440, 1280 x 800, 640 x 960, etc.) ?

  • 1
    Yes, there is. You haven't searched. – nicael Jun 16 '16 at 19:39
  • Why no CSS? `height: 100vh; width: 100vw;` – mferly Jun 16 '16 at 19:40
  • Use CSS Media Queries. http://getbootstrap.com/css/#grid-media-queries – Dan Weber Jun 16 '16 at 19:41
  • CSS media queries are not possible in this case. Unfortunately, this has to be a JS-solution. –  Jun 16 '16 at 19:41
  • Look into [.resize()](https://api.jquery.com/resize/) for jQuery. Offers a callback when the "*size of the browser*" has changed, to which you can fire your code to manipulate the background image. – mferly Jun 16 '16 at 19:42
  • $(window).width() with jquery. Then add a resize listener as comment above pointed out if you want to reload on resize, but it's already been loaded at that point and you may as well let the responsiveness work for you at that point. – Dan Weber Jun 16 '16 at 19:43
  • I dont think that what the commenter suggest may lead you to your unswer.. the thing is that no matter the width and the height I think the image imformation is not changing.. you sould check [this](http://stackoverflow.com/questions/8785643/what-exactly-is-device-pixel-ratio) question.. and learn about pixel ratio – prieston Jun 16 '16 at 20:59
  • @mrapsogos Device pixel ratio is a valid point for devices with retina displays. The question is how to effectively combine this with width without having to server 10 different images or more. The whole solution needs to be manageable... –  Jun 16 '16 at 22:08
  • you could also use the canvas element.. http://stackoverflow.com/questions/32608933/is-it-possible-to-change-the-dpi-of-a-canvas-image-in-html5 – prieston Jun 16 '16 at 23:05

3 Answers3

3

If have three different images for say tablet, desktop, and mobile devices you could create a simple system to automatically choose the correct image to load.

<section id="page-title" class="page-title-lg" data-bg data-bg-img-desktop="nature/full-20.jpg" data-bg-img-tablet="nature/full-20.jpg" data-bg-img-mobile="nature/full-20.jpg"></section>

Notice the four attributes: data-bg data-bg-img-desktop, data-bg-img-tablet, data-bg-img-mobile.

When the page loads, get the screen width and load the image that is closest to the screen size:

<script type="text/javascript">

var imageBgs = document.querySelectorAll('[data-bg]');
var screenWidth = window.innerWidth;

for(var i=0; i<imageBgs.length; i++) {
    if( screenWidth < 768 ){
        // Load mobile image
        imageBgs[i].style.backgroundImage = 'url('+imageBgs[i].getAttribute('data-bg-img-mobile')+')';
    } else if( screenWidth >= 768 && screenWidth <= 1024 ) {
        // Ipad
        imageBgs[i].style.backgroundImage = 'url('+imageBgs[i].getAttribute('data-bg-img-tablet')+')';
    } else {
        // desktop image
        imageBgs[i].style.backgroundImage = 'url('+imageBgs[i].getAttribute('data-bg-img-desktop')+')';
    }
}

</script>
Richard
  • 2,396
  • 23
  • 23
  • That is actually the closest to what I was looking for. I see that you used window.innerWidth opposed to width? Also, a user mentioned device pixel width in the comments for retina displays. I am just trying to figure out the required screen resolutions to keep the whole thing manageable... –  Jun 16 '16 at 22:09
  • I think the window.innerWidth accounts for the scrollbar in IE. Don't quote me on that. I have found that it works best as long as you don't need IE8 support. I really cannot say much about retina displays. I have never run any tests on those devices. – Richard Jun 17 '16 at 17:34
  • Ok. With the increasing number of retina display devices, would be interesting to know how to combine width with high pixel density and serve different images accordingly. –  Jun 17 '16 at 19:26
2

Is there a reason you can't change the CSS directly?

There are a few ways you could go about this. One way would be to listen to the resize event, and update all images accordingly. However, you can also use jquery to create your media queries for each element during page load, and just let the browser handle switching everything out.

Here's a fiddle illustrating how to do that: https://jsfiddle.net/czr41bqp/

Essentially you would add a style in for each screen size you want to switch at and create your style element here and append it to your header. Of course, this requires that you have pre-generated all versions of the images and that the sizes are consistent with each image.

$(function() {
  //define a template with all media queries we want to target
  var mediaQueryTemplate = '\
    @media screen and (min-width:350px) { \
        #{{ID}} { background-image: url({{BASE_URL}}/350x150) } \
    } \
    @media screen and (min-width:640px) { \
        #{{ID}} { background-image: url({{BASE_URL}}/640x960) } \
    } \
    @media screen and (min-width:1280px) { \
        #{{ID}} { background-image: url({{BASE_URL}}/1280x800) } \
    } \
    @media screen and (min-width:1280px) { \
        #{{ID}} { background-image: url({{BASE_URL}}/1280x800) } \
    } \
    @media screen and (min-width:1920px) { \
        #{{ID}} { background-image: url({{BASE_URL}}/1920x1440) } \
    } \
    @media screen and (min-width:2560px) { \
        #{{ID}} { background-image: url({{BASE_URL}}/2560x1440) } \
    } \
  ';

  var $style = $('<style>');
  $style.appendTo('head');

  $('[data-bg-img]').each(function() {
    //generate all media queries from the template for each image and add them to the style tag

    var dataImg = $(this).attr('data-bg-img');
    var mediaQueries = mediaQueryTemplate.replace(/{{ID}}/g, this.id).replace(/{{BASE_URL}}/g, dataImg);

    $style.text($style.text() + mediaQueries);
  });
});
Joel
  • 2,227
  • 1
  • 17
  • 23
1

One approach would be to leave the "src" attribute blank and then assign it depending on the screen width.

windowSize = $("window").width();

if(windowSize >= 1000){
$("img").attr("src","bigFile.png")
}
if(windowSize <= 999 && windowSize >= 500){
$("img").attr("src","mediumFile.png")
}
if(windowSize < 499){
$("img").attr("src","mobileFile.png")
}

Alternatively you could use something like:

if(windowSize >= 1000){
    $("imageContainer").html("<img src="bigFile">);
}
Ned Hulton
  • 477
  • 3
  • 12
  • 27