Responsive design: how to make your grids and images even smarter
Responsiveness in websites can be achieved in numerous ways. Using a few media queries to change your layout, based on screen width/height, is quite easy but there are other things to take into account as well. In this article I will briefly describe how we approach this process in our development team at Fabrique.
Designing and developing using a grid, a good practice in general, is key to creating and maintaining a responsive website without drowning in exceptions in your frontend code. We chose Susy as our main grid framework. Compared to others like Gridle or Neat, Susy gives us the most flexibility. With Susy we can recreate the same grid the designer used in Sketch (or any other decent design tool for that matter). Not only that, we can create different grids for each breakpoint, if needed.
Why should I use a grid?
If you haven’t used a grid in frontend styling before you’ve probably measured a lot of widths/heights of elements in a design and hardcoded them into your stylesheets or converted them to percentage based values so you could get it to work nicely. That’s all good, but then the design changed and you had to do it ALL over again. Think about it, designs are not static in a project, they tend to change. I will go even bolder and state they WILL change. This tendency is far less annoying when you implement the design with a grid system. It will give you fine grained control on how the page renders components from narrow devices to wider screens.
As you can see in the example above the images are not exactly the same, this is due to design changes. The pink grid is slightly off, you can ignore that since it has to do with browsers rounding percentages. The element widths are what matter and they are quite clear. The header is 8 of 12 columns wide, the 4 smaller blocks at the bottom are 3 of 12 each. These definitions can be set separately for each breakpoint, as illustrated below.
So, we have the grid in place. We can now start creating our css (or scss actually) which we do mobile first. A typical component could then be described like this:
We start at mobile, describing all properties we need for this element. For each subsequent breakpoint we modify properties where needed. In this example we don’t specify a width for mobile. The element will be full width in that case. Our portrait breakpoint has 8 columns, landscape 12 and desktop (really big screens) has 16 columns in total. If you want to read up on how grid systems work in general I would recommend any of the following:
- smarter grids with sass and susy
- build web layouts easily with susy
- creating a responsive grid system with susy and breakpoint
Last but not least, the mixins we include above are subclasses of susy-breakpoint, a mixin provided by susy which basically is a media query with the added extra of specific grid settings.
Changing layout of elements on different screen widths is trivial with the techniques outlined above. If you have a lot of images/illustrations in your design it’s another story altogether. Sure, bandwidth is a thing, but layout also requires extra attention. If you have not encountered this before, let me describe the ‘problem’ with images and responsiveness briefly.
Imagine a page design for a tablet (1024px) and there’s a banner-like element with a full width image. For argument’s sake, this image has a ratio of 2 wide and 1 high (in the design this image would be 512 pixels high). If we would build this (with or without grid) and look at the page on a 24" 1920 pixels wide screen the image would be 1920 pixels wide and 960 pixels high. In most cases however, this single image for all breakpoints won’t work. Typography and other elements don’t grow/shrink by a same fixed ratio as images. This will result in a complete lack of layout on your page or weird image-to-text ratio’s. The problem gets even bigger when you use images as a background (since background images don’t affect their containers’ dimensions).
Shrinking the page to a phone viewport (let’s say 340 pixels wide) will make our example image 340x170 pixels. Also nothing wrong with that, but what if the focus point of this image is a person? Their face would be 10x10 pixels big maybe? I think you get my point, using the same image for different screens is not gonna fly (not far at least).
The responsive image solution
The problem I outlined above is not new, and luckily the RICG (https://responsiveimages.org) was formed to get a solution INTO browsers that we can use to tackle this problem. We all know that the implementation of new techniques/standards takes too long, so we are still using a polyfill.
We use Picturefill2 to make our solution work, even if the user has an older browser. So far this has worked out perfectly for us. Our backend system (Django) has various media library solutions that we tweaked to fulfil our needs for responsive images. We can define multiple crops of the same image with an option to define a focus point (the center point of your crop). This usually results in a different crop for mobile images and for larger screens. Our thumbnailing system in turn takes care of ‘retinizing’ images (3x or 4x would also be possible, but we don’t feel the need for those images yet) so we only have to make sure the source image is big enough. A typical picture element would look like this (including prefixes for certain browsers):
It seems like a lot of markup for just one image, but in the end it’s worth it. After all, we have 3 breakpoints in our design and we want retina images since they look a lot better on mobile devices.
The image below nicely illustrates how we can affect the way images are being presented on mobile. The source image is the same, but the focus and crop of the used image is optimised for the device. On desktop we have a big wide visual. For mobile we created two versions, one with a custom crop and focus point (on the left) and a non responsive image on the right.
Hopefully this basic insight into responsive design techniques helps you out in creating your own setup. However, we’ve just scratched the surface in this article. In future posts I will elaborate more on specific problems faced when implementing designs and developing for a wide range of devices.