Core 1 Interaction

Working with Images

We kind of breezed past this, so let’s look at some more specifics around using images on the web.

Remember that images weren’t a part of the early web, and so like CSS, feel somewhat “bolted on” and are still somewhat tricky to work with. It has gotten much better recently, though!

I'd like to propose a new, optional HTML tag:

IMG

Required argument is SRC=″url″.

This names a bitmap or pixmap file for the browser to attempt to pull over the network and interpret as an image, to be embedded in the text at the point of the tag's occurrence. An example is:

<IMG SRC=″file://foobar.com/foo/bar/blargh.xbm″>

Marc Andreessen

Image formats

.gif

There are several commonly used image formats on the web, each with their own purpose:

.GIF Graphics Interchange Format

An early raster/bitmap format, heavily compressed with reduced palettes. It survives now because it does animations! This is the only reason to use this format, nowadays.

GIF compression is primitive and so they can quickly have huge file-sizes—and can still slow down computers (downloading and rendering) even now. Be careful with these.

.jpg

.JPG / .JPEG Joint Photographic [Experts] Group

Ancient-but-timeless raster/bitmap format that is good for photos. JPGs can compress images down to much smaller file sizes with adjustable, lossy compression ratios.

The busyness of photos tends to hide the resulting compression artifacts better than simple illustrations/graphics, so JPG lives on as a common, widely-used image format.

.png

.PNG Portable Network Graphics

Still raster/bitmap, but much better than GIFs (if you don’t need animation) as they can use lossless compression and have alpha-channel transparency.

Use PNGs for illustrations and graphics—things with large areas of repeated colors—or where you need exact color accuracy. (But many of these should be SVGs, up next.)

.svg

.SVG Scaleable Vector Graphics

Finally, a vector format! SVGs should be used for any icons, logos, or illustrations—provided you have access to the original source artwork for the vectors (shapes).

They store the vectors in code (a bit like HTML, we’ll see), and can be scaled cleanly for different sizes/resolutions. You can also target them with CSS, if they are inlined (embedded) into your DOM.

When targeting (or editing) SVG contents, note they have slightly different syntax than HTML CSS—using fill and stroke instead of color and border, for example. Also remember that width and height attributes will fix the SVG size (just like <img>); use the viewBox attribute if you want them to scale.

Sizing and containers

If you remember way back to our HTML intro, images are a special HTML element:

<img src="tim.jpg" alt="Tim Berners-Lee at a computer.">

A JPG in the same folder as the HTML (relative path/URL). Always write an alt text for accessibility.

By default, images will scale to their intrinsic size—the (1x) pixel dimensions—and are inline elements:

<section>
	<img src="../../images/lecture-11/tim.jpg" alt="Tim Berners-Lee at a computer.">
</section>
body { padding: 20px; }

section { background-color: gold; }

This image file is 250 pixels wide. Note the extra space at the bottom, from display: inline;

Most resets (like ours) include a max-width: 100% for images—otherwise they would poke out of their containers!

This intrinsic/inline behavior is rarely what you want—more often your image should be sized from your design, not vice-versa. Also by default the image is scaled to CSS pixels, so it is blurry on modern HiDPI (a.k.a. retina, 2x, 3x) screens—which is most of us, these days.

In the past, you would manually set an image size within your HTML via special width and height attributes:

<img src="tim.jpg" alt="Tim Berners-Lee at a computer." width="230" height="150">

No units, even.

But this forces the image into a fixed size, which doesn’t work well in our modern, responsive, many-device-width context. We don’t do this much anymore.

So often you’ll want to set images to display: block;, and then control their size/positioning via CSS, just like any other elements. Make sure your actual actual image dimensions are (at least) roughly twice their displayed, CSS pixel size, so nothing is blurry:

	<section>
		<img src="../../images/lecture-11/tim.jpg" alt="Tim Berners-Lee at a computer.">
	</section>
body, section { padding: 20px; }

section {
	background-color: gold;
	display: flex;
	justify-content: center;
}

img {
	display: block;
	width: 60%;
}

This image file is 1600 pixels wide. Drag that divider.'

Object-fit

CSS also added the object-fit and object-position properties for sizing images within their containers—as if the image file is a child of <img>. This is usually when setting an <img> to fill a container:

		<section>
			<img src="../../images/lecture-11/tim.jpg" alt="Tim Berners-Lee at a computer.">
		</section>
		<section>
			<img src="../../images/lecture-11/tim.jpg" alt="Tim Berners-Lee at a computer.">
		</section>
body, section { padding: 20px; }

section {
	background-color: gold;
	height: 40vh;
}

section:not(:first-child) { margin-top: 20px;}

img {
	background-color: orange;
	height: 100%; /* Fill the parent. */
	width: 100%;
}

section:first-child img {
	object-fit: contain; /* Fit the image. */
	object-position: left top; /* Corner. */
}

section:last-child img {
	object-fit: cover; /* Cover the parent. */
	object-position: right center; /* Side. */
}

Note the height on the section, otherwise the container would still resize to the image. Adjust the divider to see the behavior!

Aspect-ratio

Recently (just last year) CSS also added an aspect-ratio property, to control the width-to-height ratio of an element—maintaining this relationship as an element scales. (This used to be unnecessarily hard to achieve. CSS heights are always weird!)

This is not just for images (you can use it on anything!), but commonly comes up when using them:

<section>
	<img src="../../images/lecture-11/tim.jpg" alt="Tim Berners-Lee at a computer.">
</section>
body, section { padding: 20px; }

section { background-color: gold; }

img {
	aspect-ratio: 1 / 1; /* Width / height. */
	object-fit: cover;
	width: 60%;
}

Note that without the object-fit: cover;, Tim would be distorted to the ratio! Don’t distort Tim (or generally, most images) unless you really mean to.

Background-image

You can also use images as backgrounds on elements with the background-image, background-size, and background-origin properties—particularly if you want to put something in front of them, like text.

However this isn’t very semantic, as it blurs the content/presentation boundaries—since the image paths are moved into your CSS, and there is no alt text description for screen-readers. So you should only use this for contextual or decorative images—not your actual content:

<section>
	<h1>This is a heading</h1>
	<p>And a paragraph, to have some text over the image and also to define the size of the section/parent.</p>
</section>
body { font-family: sans-serif; }

body, section { padding: 20px; }

section {
	background-image: url("../../images/lecture-11/tim.jpg");
	background-size: cover;
}

h1 { font-size: 400%; }

I wouldn’t use something like this as a background. Mind your legibility!

Think, “would this page make sense if I couldn’t see this image?” If the answer is “no,” then use an <img> with an alt, instead. Use the alt text to convey the meaning.

Figure / figcaption

Speaking of semantics—HTML also has a figure element that you can use to associate an image (or other visual) with a visible figcaption description or legend. These containers formally link the meaning/context of the elements together.

<figure>
	<img src="../../tim.jpg" alt="Tim Berners-Lee at a computer.">
	<figcaption>Tim Berners-Lee at a computer.</figcaption>
</figure>
body, figure { padding: 20px; }

figure { background-color: gold; }

figcaption {
	font-family: sans-serif;
	margin-top: 10px;
}

These can also be used to group things like videos, illustrations, and diagrams with their captions.

Including visible captions/descriptions is a good example of the “curb-cut” approach/philosophy towards accessibility—your alt text description could be useful for more than just people using screen readers! Strive for this broad benefit in all your accessibility work.

Picture, source, and responsive images

With regards to their layout, you make images responsive in the same way you make all your page structure responsive—by writing mobile-first front-end for their containers. You can change their flow, size, shape, and so-on.

But images introduce some additional considerations, going across breakpoints. You might want to serve/show different images at different sizes—whether for dimensional (file-size, bandwidth, performance) or art-direction (scale, crop) reasons. The exact same image src file is rarely ideal at both 375px and 2560px.

Our venerable <img> element added some control for this with the addition of the srcset and sizes attributes. But I think it is much easier, at least ergonomically, to skip right into using the modern picture element.

The <picture> element is a wrapper/container for an <img>, giving it alternate <source> tags that offer different image files for different scenarios. They use media-query-like syntax to change what image is loaded and displayed:

<section>
	<picture>
		<source media="(max-width: 428px)" srcset="../../images/lecture-11/tim.jpg">
		<source media="(max-width: 640px)" srcset="../../images/lecture-11/tim--md.jpg">
		<img alt="Tim Berners-Lee at a computer." src="../../images/lecture-11/tim--lg.jpg">
	</picture>
</section>
body, section { padding: 20px; }

section { background-color: gold; }

This is all in the HTML; there is no (relevant) CSS. Adjust the divider to see the swaps!

Note that you still include the <img> as a fallback—put your largest size there. I find it helpful to follow the same mobile-first philosophy here as you do in the rest of your code—putting your smaller images first, and your larger lower. You can have as many <source> elements as you need—for image sizing or content.

Responsive images (like the rest of this) can get very complicated, very quickly—so always start with the basics (and mobile) first, like in the example here.