Responsive layout beyond width media queries

When thinking of responsive layouts, the first thing that comes to mind is probably width based media queries: (@media (min-width:...) or @media(max-width:...). CSS provides other means to adjust your designs to the screen size. Viewport units, calc, height and aspect-ratio media queries… these are just a few of them. Let’s see how they can be of help following the enhancement of a page I’ve recently been working on.

Starting point

The page in question is the artwork page of my (soon to be)updated portfolio. Content-wise, there’s nothing too fancy. It’ll obviously show a picture of the artwork. And provide a few additional things to complement it:

a small caption (with a date of publication)

links to related pages (shop, project the artwork was for…)

a few other artworks to encourage discovery of content

social media share buttons.

To navigate through the artworks, the page also features previous/next buttons. And that’s it. Like I said, nothing crazy, which leads to the no crazier HTML markup:

With nothing more to control the layout, each block of content will just be stacked under the previous one and expand as the viewport’s width grow. Here’s how it looks. Let’s see how we can improve on that!

Viewport units (and calc)

First, we’ll make some adjustments to the image. People get to this specific page to look at a picture. As the picture grows with the width, a limited height might come and crop it, only revealing the top part of the image at first.

Not an ideal first impression of the artwork, so let’s remedy to that and make sure the image is always visible in full. This means adapting its size to the height of the viewport, rather than the width, which is where viewport units come handy.

Viewport units are CSS length units that represent one percent of a size of the viewport:

vw for the width

vh for the height

vmin for the smallest of these dimensions

vmax for the largest

Using vh, we can now limit the size of the image so it fits the screen perfectly. We need to account for the header at the top though, which steals some space (`3em`) from the full height (which would be 100vh). calc to the rescue! It’ll do the computation using the different units to account for that. While we’re reducing the size we might as well shave a bit more height to make sure the caption starts showing and entices the user to scroll and read it.

Good! Now whatever the screen, the image is always visible in full to start with. Let’s remember to add a link to a zoomed in version to let people look at the details too (but this part is not really about responsiveness, so let’s leave it out for now). Here’s the result.

Height media queries

As the height grows now, so will the image, and if the width of the screen allows it, it’ll take the whole viewport if it can. This works well on small screens but feels a bit cramped past a certain width. Not to mention the line length of the caption growing past what’s comfortable for reading. Let’s improve that!

Playing with the width of the viewport (resizing the browser or using its responsive design dev tools), we can decide past which width things are breaking.

Then, usually, that’ll be dealt with using a width media query: past a certain viewport width, set the max-width of the element to a fixed value. Our image size is adjusted to the height of the screen this time. This means we’ll need to use a height media query (and not forget to add back the length we’re removing in the calc).

Aspect ratio media queries

That last adjustment gained us quite a bit of space (when available) on the sides of the content. This would be a much-improved place for the previous/next links, promoting navigation through the series of artworks.

The question is… when is that space available? We’ve got space when the overall width is more than the sum of the image width and the necessary width to put the two buttons: min-width: <image-width> + 2 * <button-width>.

Like earlier, though, the viewport’s height is at play here, because of it’s relation to the content width. Our minimum width is actually: min-width: (<full-height> - <reserved-spacing>) + 2 * <button-width>.

It looks like another job for calc… except media queries do not support calced values 🙁 Fortunately, they do support a media feature that expresses a relation between the width and height: aspect-ratio. Rounding the previous sum into a ratio will not make things as precise, but will be enough to guarantee the space for small width.

Great! When there’s enough space, people now get a quicker access to the navigation! Check it out.

Combining media queries

Past the “fixed width” breakpoint, the positioning of the navigation buttons breaks a bit. The buttons are displayed, but they grow further and further from the content as the height grows.

For large heights, also, the aspect-ratio query shows its limitations. As the height gets bigger, the query requires a larger and larger viewport width to be triggered. This makes viewports where there’d obviously been space for the arrows miss out on the enhancement.

At that point, the image size is set. We can just combine a “classic” min-width query to the min-height one to ensure the arrows will get displayed on screens with enough space, but not fitting the previous aspect-ratio.

And now that’s better! No more missing navigation when there’s space for it. And there we are.

Conclusion

Further improvements could be made to the design (that unique column makes things look a bit empty at large width, for example). They wouldn’t rely on different mechanisms than the ones already described so let’s leave it there. Plus, that would spoil the surprise of unveiling the new design 😉

These 4 CSS features have allowed us to get finer control on how the content would adapt to different viewports. I hope you’ll find them useful if min-width or max-width don’t solve your layout problem. I’d be happy to hear how they worked for you, or if you use other features too to adapt your designs.