0

For a web app of mine, I want images served to the user to be responsive. Moreover, I'd also want to specify width and height attributes in the image tag, so that over slow mobile connection, there's no browser reflow.

Are both of these requirements achievable via using pure HTML?

If it's indeed possible, an illustrative answer that shows working examples is most welcome. Secondary pure JS (no libraries) answers are welcome too (but my primary focus is doing this via lightweight HTML).

Note: this accepted answer from a similar question relies on JQuery (something I'm not versed in), hence doesn't meet my requirement.


Background: for mobile-responsive design it's common to specify a width (or max-width), and define height as auto. That would clash with (and be antithetical to) width and height values. Hence my question.

Kunj
  • 1,980
  • 2
  • 22
  • 34
Hassan Baig
  • 15,055
  • 27
  • 102
  • 205
  • 1
    (The answer from that other question could easily be re-written to vanilla JS ...) – CBroe Mar 19 '18 at 11:41
  • @CBroe: I don't know JQuery, so I'm unable to translate that to vanilla JS. I'm primarily a server-side developer with rudimentary HTML, JS knowledge. – Hassan Baig Mar 19 '18 at 11:44
  • @CBroe: Yea I don't want to do this in JS either. I've tried something like `` to make the image responsive. Now if I tack on `width` and `height` attributes, I lose my responsiveness (but solve the problem of browser reflows). I want to enable *both* requirements, preferably in pure HTML. Are you suggesting I should try `width:auto`? Would be good to get an illustrative example. – Hassan Baig Mar 19 '18 at 11:54
  • https://css-tricks.com/video-screencasts/133-figuring-responsive-images/ – Jeremy Thille Mar 19 '18 at 13:52

1 Answers1

1

For what it's worth, here's a vanilla version of that jQuery answer.

// convert nodelist into array:
var imageList = Array.prototype.slice.call(
  document.getElementsByTagName('img')
);

imageList.forEach(function(img) {
  // only act on images with set w+h attributes:
  if (img.getAttribute("width") && img.getAttribute("height")) {
    // calculate the desired height (in pixels)
    var scaledHeight = img.getAttribute("height") * img.clientWidth / img.getAttribute("width");

    // wrap the image in an element with that height
    var wrapper = document.createElement('span');
    wrapper.setAttribute("style", "height: " + scaledHeight + "px; display: inline-block");
    img.parentNode.insertBefore(wrapper, img);
    wrapper.appendChild(img);
  }
});
img {
  max-width: 100%;
  height: auto;
}

/* Just so you can see what it's doing: */
span {border:1px solid}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img src="http://placehold.it/2500x100" width="2500" height="100">
<img src="http://placehold.it/1000x300" width="1000" height="300">
<img src="http://placehold.it/100x100" width="100" height="100">
<img src="http://placehold.it/100x100">

And for even more completeness, a jQuery version of the above, which unlike the original answer works correctly. (The older answer may depend on CSS not shown, or something else has changed since it was written, or it's just wrong; in any case it adds way too much padding.)

$('img').each(function() { 
    if ($(this).attr("width") && $(this).attr("height")) {
      var scaledHeight = $(this).attr("height") * $(this).width() / $(this).attr("width");
      $(this).wrap('<span style="height: '+scaledHeight+'px; display:inline-block">');
    }
});
img {
  max-width: 100%;
  height: auto;
}

/* Just so you can see what it's doing: */
span {border:1px solid}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img src="http://placehold.it/2500x100" width="2500" height="100">
<img src="http://placehold.it/1000x300" width="1000" height="300">
<img src="http://placehold.it/100x100" width="100" height="100">
<img src="http://placehold.it/100x100">
Daniel Beck
  • 20,653
  • 5
  • 38
  • 53
  • Thanks for this, I'll take it for a spin. I was hoping a pure HTML solution would be possible - I was thinking something maybe utilising `flex`. But fair enough. – Hassan Baig Mar 19 '18 at 15:44
  • 1
    I'm honestly not sure if there is a non-js approach, I'll be watching this question with interest to see if someone more knowledgeable than me comes along... It's a little mysterious to me that browsers don't do this automatically TBH. – Daniel Beck Mar 19 '18 at 15:47