Well, imagine this: You have website with a big background image, and you want it to work well across all screen sizes. That is, it should fill the whole viewport, no matter the screen size or aspect ratio. You also want to do this using CSS only.
In this post, we will first cover how to do this for background-image
, and at the end, I will extend the solution to <img>
tags.
TLDR – I just want the solution: Thats great! You can find the solution here.
If you’re interested in the details, read on!
Using background-size: cover
to auto-size the image
Our first attempt might be using just background-size: cover
to make the image always fill its container:
<div class="container">
</div>
.container {
background-image: url('/assets/img/posts/2024-02/pexels-pixabay-235990.jpg');
background-size: cover;
background-repeat: no-repeat;
}
The result will look something like below. Note the following:
- Good: The image always fills the whole container (due to
background-size: cover
) - Bad: We basically zoom in on the top left corner of the image. This lets the main motif of the image disappear in some cases, which is arguably not ideal.
Show additional boilerplate code
The following code is used throughout all examples to to allow playing around with the size of the image container.
.container {
width: 100%;
height: 100%;
}
.resizeable {
overflow: hidden;
resize: both;
border: 1px solid black;
}
.natural-size {
--image-aspect-ratio: calc(3848 / 2565);
--initial-width: 200px;
--initial-height: calc(var(--initial-width) / var(--image-aspect-ratio));
width: var(--initial-width);
height: var(--initial-height);
}
.half-width {
width: calc(0.5 * var(--initial-width));
}
.half-height {
height: calc(0.5 * var(--initial-height));
}
/* Arrange the samples in a row instead of in a column */
body {
display: flex;
flex-direction: row;
}
body > div {
margin-right: 1rem;
flex-shrink: 0;
}
/* Add a marker for the point where we zoom in on */
.show-focal-point {
position: relative;
}
.show-focal-point::after {
--focal-point-size: 10px;
position: absolute;
top: calc(var(--focal-point-y) - (var(--focal-point-size) / 2));
left: calc(var(--focal-point-x) - (var(--focal-point-size) / 2));
width: calc(var(--focal-point-size) + var(--focal-point-x) - var(--focal-point-x)); /* Hack to set `width: unset`` when --focal-point-x is not defined */
content: "";
background-color: red;
aspect-ratio: 1/1;
border-radius: 100%;
z-index: 1;
}
<div class="resizeable natural-size">
<div class="container">
</div>
</div>
<div class="natural-size">
<div class="container show-focal-point">
</div>
</div>
<div class="natural-size half-width">
<div class="container">
</div>
</div>
<div class="natural-size half-height">
<div class="container">
</div>
</div>
Centering with background-position
We can easily fix the latter problem by using background-position: 50% 50%
to zoom in
on the center of the image instead of the top left corner:
.container { /* ... */
background-position: 50% 50%;
}
As a bonus, here is the same solution using CSS variables:
.container { /* ... */
--focal-point-x: 50%;
--focal-point-y: 50%;
background-position: var(--focal-point-x) var(--focal-point-y);
}
Non-centered focal points
Nested heading
Nested heading
Okay, that works! But now you have an image where that focal point isn’t in the center?
Well, just set background-position
to the center, and call it a day:
.container {
--focal-point-x: 75%;
--focal-point-y: 23%;
background-position: var(--focal-point-x) var(--focal-point-y);
}
Final solution…
…for background images using background-image
Here is the full solution for background-image
so far:
.container {
background-image: url('/assets/img/posts/2024-02/pexels-pixabay-235990.jpg');
background-size: cover;
background-repeat: no-repeat;
--focal-point-x: 75%;
--focal-point-y: 23%;
background-position: var(--focal-point-x) var(--focal-point-y);
}
<div class="container">
</div>
Bonus: …for <img>
tags
We can use basically the same solution for <img>
tags, by using object-fit
/object-position
instead of background-size
/background-position
:
img.container {
--focal-point-x: 75%;
--focal-point-y: 23%;
object-position: var(--focal-point-x) var(--focal-point-y); /* object-position is analogous to background-position */
object-fit: cover; /* object-fit is analogous to background-size */
}
<img class="container" src="/assets/img/posts/2024-02/pexels-pixabay-235990.jpg">