- Images fit together precisely with thin gutters.
- The size of images is based on each image’s aspect ratio, with height constrained to a maximum and width dependent on height.
- Markup is relatively straightforward to write, with grids generated automatically from image metadata.
- On the smallest screen sizes, the layout is a single column instead of a grid.
Each row is a grid
Grids are stacked
Making a fluid grid like this requires CSS flexbox. Flexbox specifies a container-based layout system which causes elements inside the container to resize flexibly, either filling available space or shrinking to fit the box. Elements inside a flexbox container can be proportionally resized based on the container’s size and also based on the size of the elements inside the container.
I found part of the solution in Kartik Prabhu’s “Equal height images with flexbox”, which shows a neat trick with the
flex-grow property. If
flex-grow is set to the calculated aspect ratio of the image (with a common ratio like 3:2 written as
1.5), images that have the same
flex-basis (initial width) will maintain the same height while adjusting their width proportionally.
flex-grow work this way? The number is a factor which determines the amount of space the element should take up in the flexbox container. If each image in the same flexbox also is set to its own factor, the result is that every image scales not only based on width, but based on width and ratio.
Using Jekyll collections
For our photo site, I used Jekyll collections to generate the markup and lay out 78 photos in 9 posts (each post being a grid of selected images). This would be a lot of markup to write by hand, which is why Liquid templating in Jekyll is essential. The same principles would apply for any other template system, but the examples here use Liquid and Jekyll collection variables to generate HTML.
Each photo in the
_photos directory would be named with the scheme
yyyy-mm-dd-photo-name.md and include YAML front matter for the content’s metadata like this:
Additionally each image is placed in a separate image directory with the same naming scheme
A Liquid loop that builds the grid row by row. In the
for loop, the group number determines the row, and each row is stacked on top of one another other in that numerical order.
For exach image in the group, there can be multiple images per group, but no explicit minimum or maximum is set. If there is only one item in a group, the image will take up 100% of the grid’s width, while if there are three items, the images will divide the grid’s width proportionally based on each images’s calculated width.
Gutters are calcuated as proportional values as well, so they will always make up the same proportion of the grid regardless of how many images are in the containing row grid. Vertical gutters between rows are set with top margins.
As for what’s in the
block/grid-image.html file that is looped, let’s take a closer look at the needs of a high performance responsive image pattern.
Extending grids with responsive images
Since I use
srcset responsive images for photos to make sure that the right size images are served, a new problem arises. For
sizes to work properly, we need to know the approximate size of the image ahead of time, and a variable flexbox grid prevents this. We can’t even guess if an image is supposed to be 50% of the viewport or 100% of the viewport, since its neighbor determines its size. The fluidity built into the design of the grid takes away some control we would otherwise exert over the exact dimensions of a given image.
A solution for implementing responsive images: lazysizes
sizes attribute for an image. Instead of creating a complex pattern of media queries that state the likely dimensions of an image (or our best guess), we can use the auto-sizing feature of lazysizes to accurately measure the width of the image element before the image has loaded.
Putting it all together with imgix and Jekyll
I am building a file that holds the markup for responsive images (mainly an
img element with
alt attributes, contained in a
figure with an optional
figcaption). There is a lot going on here, but the important thing to note is that the variables like the
src and the caption are set by the front matter of the image. This is where we assign the CSS class determining the aspect ratio for every single image. Using the Jekyll plugin for imgix, all of the desired image sizes are generated with a Liquid loop.
Principles of a fluid grid
The aspect ratio of images is maintained at all widths of the grid. The images in the grid resize in a fluid manner so that the grid maintains the relationship of the images to each other at any size. The grid’s form is static while its contents shift dynamically yet harmoniously.
The relationship between items in the grid is based on constraints that allow for an image of any size to be placed next to another image, automatically resizing and reflowing based on the size of both images.