Responsive is nothing new — you build a page, it looks great on desktop, it has to look great on mobile as well. To achieve this we most often use media queries, but there is one other way – responsive containers
We should all know by now how to achieve that. You have media queries, you have relative values, you have grid systems and so forth.
If you’ve came across this article by googling how to build responsive containers , please read continue from here.
Let’s start with an example. We have a box on which we will set background image. It is dimensions are defined as 600x300px. It’s CSS could look like this:
.box {
height: 300px;
width: 600px;
background-image: url('image.png');
background-size: cover;
}
You can easily spot that this box is not something we consider responsive because of the fixed pixel values. When you change the viewport, the box will not follow it’s width, it will stick to 600px. So when you go under 600px like on mobile device, you will end up with a horizontal scroll.
The easiest fix for this and the most common approach would be to update the width property to present. That way it will be relative to the box parent’s width, which if not fixed will follow the viewport width.
But if we change width: 600px to width 100%, how will the browser know that we want to have no more than 600px width? It can’t so we will tell it:
.box {
height: 300px;
width: 100%;
max-width: 600px;
background-image: url('image.png');
background-size: cover;
}
Now when the viewport is more than 600px, the box will limit its width to 600px. When it’s smaller, it will change its width according to the viewport.
Great, now our box is responsive! Well… not exactly sadly. This is why this article exists actually. What problem remains? The height! Originally we had ratio 2:1 — two times width, one time height. In our case 600×300. If we reduced the width to 300px (due to viewport change) we end up with a square: 300x300px because of the fixed height we did.
How to create responsive boxes in CSS
We need to tie the height to the width. An easy way to achieve this is by adding height value that is bound to the width of the element. And what would that value be? Presents! (%)
The CSS data type represents a percentage value. It is often used to define a size as relative to an element’s parent object. Numerous properties can use percentages, such as width, height, margin, padding, and font-size.
<percentage>, MDN
This will take some very basic math: If we want 2:1 ratio, that means that the height is half of the width.
present = height / width * 100.
So if for example we want in a perfect case to have 768 height for an element and 432 width, we end up with this:
432 / 768 * 100 = 56.25% which just so happens to be 16:9 ratio!
But there is a problem. If you set these properties to a box nothing will change sadly. The height will remain 0 and the background image will not be visible. Why is that?
Because of this:
Height <percentage>: Defines the height as a percentage of the containing block’s height.
Height, MDN
And our containing block’s height is 0, because the background image we set to the empty div defines no height. + it is not tied to the width as we wanted. This is why we don’t set it to the height.
We will set it to the padding instead:
.box {
width: 100%;
max-width: 768px;
padding-bottom: 56.25%;
background-image: url('image.png');
background-size: cover;
}
For padding, we have this definition:
The size of the padding as a percentage, relative to the width of the containing block.
Padding, MDN
But once again, things will not work out because of the “parent” thingy. % values are a tricky bunch! The final change we have to do here is to make sure that when we say max-width for our .box class, it will be the one to which the % value is attached to.
To do so, we need to add a :before element like this:
/* Overflow hidden to reduce potential bugs */
.box {
overflow: hidden;
max-width: 768px;
background-image: url('image.png');
background-size: cover;
}
/* After so that the parent becomes the .box value */
.box:after {
content: '';
display: block;
padding-bottom: 56.25%;
}
The responsive containers trick is often used when we have a grid of images (or other type of content) for which we want to always have the same aspect ratio, no matter the content.
So if you have a grid of blog posts with featured images which are different in size, you want them all to stay responsive in a specific ratio without cutting/resizing or squishing them.
How to achieve it without background image?
This is a bit tricker but also often used: We will introduce absolute position for the <img> tag inside our responsive container.
<div class="box">
<img src="image.png" alt="A photo of a cat">
</div>
And with the structure above add the following style:
.box {
overflow: hidden;
max-width: 768px;
}
.box:after {
content: '';
display: block;
padding-bottom: 56.25%;
}
.box img {
position: absolute;
height: 100%;
width: 100%;
top: 0;
left: 0;
}
Now we have the same result as above, but with the benefit that the image URL is defined in the HTML code, not the CSS background property, which is generally better for A11y.
As front-end developers this is one of the many decisions we have to make on a daily basis in order to present the information to the readers in the best possible way without making it a hassle for the editors.