When an HTML document is rendered, it becomes an assembly of rectangles. The content has some influence over these rectangles. A long paragraph, for example, will have a taller rectangle than a terse paragraph. By and large, however, the sizes and locations of the rectangles are shaped by style rules. The locations are determined by a layout algorithm, a topic for another day. For now, you will focus on sizing these rectangles.
Consider this image of Ziggy Stardust, the alter ego of musician David Bowie:
The image is too big. You use the width
and height
properties to adjust the size. Both are set to lengths. Here the image's width and height are set using px
units:
Ziggy is now distorted. The web is full of criminals who naively stretch people out of proportion by setting both dimensions without maintaining an image's aspect ratio. You must not do this. Ever.
In technical terms, Ziggy's aspect ratio, or width-to-height ratio, has been violated. The original image has an aspect ratio of 936:1213, which means the width is about 77% of the height. The distorted image has an aspect ratio of 400:300 or 4:3, which means the width is about 133% of the height.
You could try to maintain the aspect ratio manually with some math. But don't. The browser will maintain the ratio automatically if you set only one of the dimensions. Here only the height is set:
Try changing this so that only the width is set.
Sometimes you really do need to set both the width and height to achieve a uniform appearance, as in a grid of images or a row of buttons. You can still avoid distortion by using the object-fit
property. If you want to ensure that every single pixel of the image is visible, set this to the value contain
:
The overall footprint of the image is 300x300. The pixels don't fill the whole width, however. The sides are vacant, revealing the image's background color. Try changing the dimensions to produce a letterbox effect, with vacancies on the top and bottom.
If you want neither distortion nor vacancies, set object-fit
to cover
:
The entire rectangle is covered by Ziggy's pixels, with no background color popping through. Some of the pixels have been cut off. To control which of the pixels are clipped, you use the object-position
property. Try adding this property and settings its value to center top
. The two terms set the horizontal and vertical alignments of the content, respectively. Try showing the bottom of the image. What do you suppose the default alignment is?
In the examples above, the size was set in pixels. As you saw with fonts, pixels are absolute units. There are occasions where you will want to size an element in relative terms. For that you can use the unit %
:
When you express a length as a percentage, the browser applies the percentage to the corresponding value of the parent element. In this case, the parent is the body element, and the image's width is set to be half of the body's width. This relationship is live. As the parent's width changes, so does the image's. Try resizing your browser window and you will see this.
Something similar should happen if you set the height to 50%, right?
That image is definitely not 50% of the height. The issue here is something that all web developers must come to embrace: the body has no height. Really, the height is just too hard—or impossible—to calculate. In this example, the height of the body depends on the height of the image, but the CSS says that the height of the image depends on the height of the body. To avoid this circular dependency, the browser just ignores heights expressed as percentages of the body and uses some other value.
If the parent element has a fixed height, then heights based on percentages work as you'd expect:
Try changing the height of the div
and see what happens to the image.
The height of the body can be fixed too, which will make percentages behave as expected. However, read on for a better solution.
The body height problem usually manifests itself when a web developer is trying to make an element that fills a certain portion of the browser window. If that's your goal, then you can use vw
and vh
units. These are like percentages, but they are relative to the browser viewport instead of the parent element. The viewport is the rendering area inside the browser window. The length 50vh
means 50% of the viewport height. This image looks like it fills half the viewport, doesn't it?
Notice how the image breaks out of the parent element's rectangle. This is called overflow. Try adding some content after the div
. Where does it appear?