htmlcsscompasstypography

How to handle responsive images with vertical rhythm?


I'm developing an HTML page using Compass/SCSS and a vertical rhythm approach. I've set up a baseline and specified heights for paragraphs and headings in rem units. It works great and lays on a vertical rhythm grid nicely. However, I have a central image that takes 100% width of the column (I want it to be responsive and scale with the browser window).

The problem is that this image breaks vertical rhythm because it's height is calculated dynamically according to the browser width and image aspect ratio and is not respecting the baseline.

How do I handle this situation in order to have a perfect vertical rhythm?


Here's the screenshot to demonstrate the idea:


As you can see the text below the image breaks out of the VR grid.

I've tried to use Respond.js jQuery plugin, but looks like it's outdated and is not working correctly.


Solution

  • The Library

    Me and my colleague have created a library that solves this problem almost ideally with minimal image distortions.

    Feel free to look into it, test it and use in your projects: https://github.com/betsol/baseline-element


    Prior conceptual solution

    Here's the conceptual solution I've came up with in the end:

    $(function () {
    
      var baseline = 24;
    
      var $image = $('#sample-image');
      var imageAspectRatio = ($image.width() / $image.height());
    
      wrapImage($image);
    
      window.addEventListener('resize', resizeImage);
      resizeImage();
    
      function wrapImage ($image) {
        var $wrap = $('<div class="image-wrap">')
          .css('overflow', 'hidden')
        ;
        $image
          .css('width', 'auto')
          .css('display', 'block')
        ;
        $image.after($wrap);
        $wrap.append($image);
      }
    
      function resizeImage () {
        var newHeight = ($image.parent().width() / imageAspectRatio);
        var leftover = (newHeight % baseline);
        $image.css('height', newHeight + (baseline - leftover));
      }
    
    });
    

    It dynamically creates a container around image, set's image width to auto and uses resize event to manually calculate the image height with respect to baseline. That way image will be slightly cut by the right border, but it should work.


    And here's the result: