The goal of this post is to create a responsive hero image that maintains it's aspect ratio on any viewport without cropping the image. Let's begin by looking at two of the more straight forward, but inferior, implementations. Or skip ahead to the solution.
Method 1: Add Text with Image Editor
This execution is so ham-handed. I see this done by graphic designers dabbling in web design. It is scalable without cropping. But while it does what I'm looking for, rasterizing type looks like garbage. My philosophy is to keep every aspect of a website design as sharp as possible, so rendering text browser side is always preferable to rasterizing type to an image in Photoshop/Illustrator.
It's also static! To alter the hero text you need to find the original image, go back into your image editor, change the text, then rasterize all over. A major pain and impossible to incorporate into a CMS. I will never create a website design this way... except for the above example!
Method 2: Use the CSS Background Property
This is a popular method. I often see web designers use this with full bleed heroe images and in it can look great. But given the varying heights and widths of a viewport cropping will occur. So the image has to look cool when cropped.
Example is in this codepen.
Even if the standard allows an image to be specified by a CSS property, I am not down with putting content in CSS. Web designers should place content in the HTML side of a design, and let CSS handle just the styles. I think the
background property is better suited for a repeatable image, something that adds a texture and feel but not content. A hero image is content. It also works well in situations where the aspect ratio is suppose to be dynamic, like with a full bleed hero, content vs styles be damned.
Another drawback of this method is the fixed
font-size. The example above crops on mobile devices. To scale the text you need to create media queries to adjust the
font-size for each viewport. Which is doable, but one might as well use the superior solution we use that follows.
Method 3: Overlay and CSS Unit vw
The two tricks we use are an overlay, and the CSS unit vw. The overlay is a bit of a hack, while vw is a css standard.
Meet the Viewport Unit: vw
The vw unit is a simple and quick tool for responsive designs with robust browser support. A responsive design styles elements depending on the width of a visitors viewpoint, and the unit vw (+ the other viewport units), give the clever web designer an easy way to scale responsive elements in their design. A single vw unit represents a 1/100th of a viewport width. So if an image's width is set to set to 50vw, and a visitor's viewport is 960px the 50vw will compute as 480px.
Example is in this codepen.
HTML Structure of Overlay
In this method we will create two
<div>s, one for our overlay and the other for the image. We'll start with a
.hero wrapper that will contain both our elements,
Next we'll code our web design's overlay. We are overlaying a
<h1> tag, but this overlay will work for any element including buttons. Many web designs overlay a
"ghost" button in their hero. It looks cool. We'll start by getting the overlay and image to overlap then we'll apply a CSS transform to precisely place our text.
CSS for Overlay
position:relative to keep the overlay from shifting slightly to the right. For
position: absolute to make the overlay exactly on top of the image, otherwise the overlay's
div will display empty space above the hero image. Set
z-index:0 to place the overlay above the image. For
.hero-image I set
margin-right:auto to horizontally center the image. Horizontally align the image how you desire. Then set
z-index:-1 to make the image display below the text.
The overlay is setup, but the text is sized wrong and placed at the top of the hero image. We will make it responsive and extra special with our much built up vw unit. Pick a small number, say 10 and set
font-size: 10vw, see how that looks, then alter the number to get the size you desire in your web design. Now we will shift it, in this example I want it vertically centered, but one can place it where ever using the transform property. I want my text centered so I added
transform: translate(9vw) to bring it down to the center. I had to experiment with the number to get the text vertically centered, but it's not a laborious task.
Our responsive hero image is good to go. It's coded in pure CSS and HTML and has kick-butt browser suport. Because our
transform are set with a viewport unit, the hero image will scale perfectly as the browswer window changes.