nextjs images - fill parent container while preserving original aspect ratio
using typescript and styled components
next/image
is a powerful component that handles compression and caching for you.
that means - faster load times with smaller payloads.
getting the image to fill the parent container while preserving the original aspect ratio is a bit complicated, so here's a quick guide to help you with that!
the simplest case
by simply adding a parent component and setting the position
to relative
, the image will fill the space of the width and height set on the parent component.
const ImageContainer = styled.div`
position: relative;
width: 100px;
height: 100px;
`;
<ImageContainer>
<Image
src="placeholder.png"
layout="fill"
alt="placeholder image"
/>
</ImageContainer>
Rendering multiple images with different aspect ratios
this is where things get a bit complicated. in our blog site, we have a lot of images of different sizes. the ideal solution is to update all the images to unify the aspect ratio, but when you have a lot of content this can be difficult.
for this to work, you need to know the width and height of the original image. thankfully, in our case, our CMS contentful provides these.
the solution noted below allows us to have the images fill the height of the container while dynamically setting the width. the same pattern can be used to fill the width and have the height overflow and be hidden.
const CONTAINER_HEIGHT = 100;
const ImageContainer = styled.div`
position: relative;
width: 100px;
height: ${CONTAINER_HEIGHT}px;
overflow: hidden;
`;
const renderBlogImages = (articles: Article) => {
articles.map((article) => {
const imageWidth = article.image.width;
const imageHeight = article.image.height;
const ratio = (imageHeight) / CONTAINER_HEIGHT;
return (
<ImageContainer>
<Image
src="placeholder.png"
layout="fixed"
width={imageWidth / ratio}
height={CONTAINER_HEIGHT}
alt="placeholder image"
/>
</ImageContainer>
);
});
}
const blog = () => {
return (
<FlexRow>
{renderBlogImages(articles)}
</FlexRow>
)
}
Center images that overflow
Using the implementation above allows you to overflow either the width or height of an image to properly fill the container. This will cause images to be cut off and seem off-center.
By adding this css to the ImageContainer
we can ensure the image stays centered
const ImageContainer = styled.div`
position: relative;
width: 100px;
height: 100px;
overflow: hidden;
& span {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
`;
the next/image
component renders a span
wrapping the img
tag, so we target the span
in the ImageContainer
with these styles, which ensure the image is centered.