# Images and assets

Pixels, vectors, formats and file sizes. Why your 8 MB photo kills your site and your logo turns blurry.

Multimedia & Creative Technology · 0.0 General · Self-study · version 1.0.0 · 2026-09-20

Tags: images, html

Slides: <https://slides.mctantwerp.be/en/general/06-images-and-assets>

Speaker notes: <https://slides.mctantwerp.be/en/general/06-images-and-assets.notes.md>

<!-- slide 2 -->

## Agenda

1. Pixels and vectors: Two ways to store an image
2. Formats: jpg, png, webp, avif, svg
3. Weight: What an image costs in bytes
4. On your page: srcset, lazy, alt
5. Video and sound: The minimum
6. Working files: Keeping source and export apart

<!-- slide 3 -->

## Self-study: How to work through this

*45 minutes, On your own*

Count on three quarters of an hour. Keep a project with images open so you can apply everything straight away.

1. The format lab and the drill sit halfway through
2. The guidelines at the end are the cheat sheet you come back to later
3. Finish with five images from your own project, exported again

<!-- slide 4 -->

## 1. Pixels and vectors

*Two completely different ways to store an image, and you use both.*

<!-- slide 5 -->

**A photo is a grid, a logo is a recipe.**

A raster is a table with one colour per pixel. A vector is a description: a circle here, a line there, in this colour. That second one scales forever.

<!-- slide 6 -->

### Raster and vector

#### Raster

- A grid of pixels, each with a colour
- Photos, screenshots, textures, anything with detail
- `jpg`, `png`, `webp`, `avif`, `heic`
- Scaling up gives you blocks or blur

#### Vector

- Shapes, lines and colours as instructions
- Logos, icons, illustrations, diagrams
- `svg`, `ai`, `pdf`
- As sharp on a billboard as on your watch

<!-- slide 7 -->

### What a resolution is

*Two numbers: how many pixels wide and how many high. Everything you see on a screen is that.*

| Example | Pixels | What for |
| --- | --- | --- |
| A full hd screen | 1920 × 1080 | The canvas of these slides |
| A photo from your phone | 4032 × 3024 | 12 megapixel, far too big for the web |
| An image across the full width | 1600 × 900 | Plenty for any laptop screen |
| A thumbnail in a card | 400 × 300 | More makes no difference in that spot |

> [!NOTE]
> Megapixels are width times height. Squeezing twelve million pixels into a card 400 pixels wide means downloading eleven and a half million pixels for nothing.

<!-- slide 8 -->

### DPI does not exist on the web

*That 72 or 300 in your export dialog does nothing online.*

#### Print

- DPI says how many dots of ink per inch of paper
- 300 dpi is the standard for print
- An A4 at 300 dpi is 2480 × 3508 pixels
- Here dpi decides how big your print comes out

#### Screen

- A browser only knows pixels
- The same 800 pixels at 72 or 300 dpi are identical
- What does count: `devicePixelRatio`, or retina
- Which is why you export at 2x and show at 1x

<!-- slide 9 -->

### Why 2x

*A retina screen puts four physical pixels on every css pixel. An image at actual size looks soft there.*

```html
<!-- Shows at 400 px, delivers 800 px of pixels -->
<img src="map-800.jpg" width="400" height="300" alt="Map of Antwerp">

<!-- Or let the browser choose -->
<img src="map-400.jpg"
     srcset="map-400.jpg 1x, map-800.jpg 2x"
     width="400" height="300" alt="Map of Antwerp">
```

> [!TIP]
> Exporting at three times makes little sense anymore. Almost nobody sees the difference between 2x and 3x, everybody feels the weight.

<!-- slide 10 -->

### You export an image at 300 dpi for a web page. What changes?

- A. Nothing, the browser only looks at the number of pixels
- B. The image gets sharper
- C. The image shows four times as big
- D. The colours get deeper

**Answer:** A. Nothing, the browser only looks at the number of pixels

Dpi is a number inside the file meant for print. A browser does nothing with it. If you want it sharper on retina, export more pixels, not a higher dpi number.

<!-- slide 11 -->

## 2. Formats

*Five you need and two you are better off avoiding.*

<!-- slide 12 -->

### The three for photos

*Anything with gradients and detail, from your camera or your render.*

| Format | What for | Watch out |
| --- | --- | --- |
| `jpg` | The safe choice for photos, supported everywhere | No transparency, every save costs quality |
| `webp` | Same image, about 30% smaller | Works in every browser of the last few years |
| `avif` | Smaller still, mostly on large flat areas | Slower to encode, support is good but not complete |

> [!TIP]
> Today webp is the default choice for a photo on the web. Keep jpg around for whatever has to pass through an old system.

<!-- slide 13 -->

### The rest

*Flat colours, transparency, motion and vectors.*

| Format | What for | Watch out |
| --- | --- | --- |
| `png` | Screenshots, text in an image, transparency | Loses nothing, but gets heavy fast with photos |
| `svg` | Logos, icons, illustrations | It is text, so scalable and styleable with css |
| `gif` | Nothing anymore, honestly | 256 colours and huge files, use mp4 or webp |
| `heic` | What your iPhone produces | Convert it before you use it, browsers will not show it |

<!-- slide 14 -->

### Transparency

*Your background only stays see-through when the format carries an alpha channel.*

- **Transparent**: `png`, `webp`, `avif` and `svg`. All four can make a pixel half see-through, so soft edges work too.
- **Not transparent**: `jpg` has no alpha channel. Export a logo on transparent as jpg and you get a white or black background back.

> [!WARNING]
> That black box around your logo on a dark site comes from here. The fix is not more erasing, it is the right format.

<!-- slide 15 -->

### An svg is just text

*Open one in VS Code and the shapes are right there. Which is why you can style and animate it.*

```html
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
  <circle cx="12" cy="12" r="9" />
  <path d="M12 7v5l3 3" />
</svg>
```

> [!NOTE]
> `currentColor` takes the colour of the text around it. One icon, any colour, without exporting a second file.

<!-- slide 16 -->

### Drill: which format

*Six cases you still run into this semester.*

**1. The logo of your portfolio, sharp on every screen and at every size.**

- **svg** ✓
- png
- jpg
- gif

A logo is made of shapes, so vector. An svg stays sharp from favicon to billboard and usually weighs a couple of kilobytes.

**2. A photo of your model, across the full width of your page.**

- png
- **webp** ✓
- svg
- gif

A photo with lots of detail: webp gives the same image as jpg at about two thirds of the weight. Png would be four times as heavy here.

**3. A screenshot of an interface, with small text in it.**

- jpg at 60%
- **png** ✓
- gif
- avif at 30%

Sharp edges and text smear under lossy compression. Png keeps every pixel. Lossless webp does the same thing in a smaller file.

**4. An icon that changes colour when you hover over it.**

- Two png files
- **svg** ✓
- A gif
- A jpg with a css filter

With an svg you put the colour in css and change it on hover. Keeping two files for two colours is work that never stops.

**5. An eight second screen recording showing off your app.**

- gif
- **mp4** ✓
- A series of png files
- webp

An eight second gif easily weighs 10 MB and looks bad. The same recording as mp4 is a few hundred kilobytes, with better colours.

**6. A cut-out product photo placed on a coloured background.**

- jpg
- **png** ✓
- It makes no difference
- pdf

You need transparency, and jpg cannot do it. Png works, webp with an alpha channel works just as well and is lighter.

<!-- slide 17 -->

## 3. Weight

*Every kilobyte you send is somebody waiting on mobile data.*

<!-- slide 18 -->

### Format lab

*The same photo, another width and another format. The bytes follow immediately.*

<!-- slide 19 -->

### With and without loss

*Two kinds of compression, and you use them for different things.*

#### Lossy

- Throws away detail your eye barely sees
- `jpg`, `webp`, `avif`, `mp4`
- Much smaller, and it never comes back
- Perfect for photos and video

#### Lossless

- Keeps every pixel exactly
- `png`, `webp lossless`, `zip`
- Bigger, but you lose nothing
- For screenshots, text and flat colour

<!-- slide 20 -->

### Generation loss

*Opening a jpg, editing it and saving it again compresses it again. Every round eats detail.*

1. **First export**: From your source file to jpg at 80%. Looks good, nobody notices anything.
2. **Fifth edit**: Every reopen and save stacks artefacts on artefacts. Edges get halos.
3. **The fix**: Always edit the source file and export again. An export is an end product, not a working file.

> [!WARNING]
> The same goes for a screenshot of a screenshot, and for an image that went through WhatsApp four times.

<!-- slide 21 -->

### Guidelines that work

*No laws, but you will rarely be wrong with these.*

| Where | Width | Weight |
| --- | --- | --- |
| Image across the full width | 1600 to 2000 px | Under 300 KB |
| Image in a column | 800 to 1200 px | Under 150 KB |
| Card or thumbnail | 400 to 600 px | Under 60 KB |
| A whole page together | As many images as needed | Preferably under 2 MB |

> [!NOTE]
> Ten images of 4 MB on one page is 40 MB. On 4G that is a minute of waiting, and half your visitors are gone by then.

<!-- slide 22 -->

### Tools

*Four ways to do the same thing, from dragging to scripting.*

- **[squoosh.app](https://squoosh.app)**: Drag an image in, compare formats side by side and watch the weight live. Runs in your browser.
- **[ImageOptim and TinyPNG](https://imageoptim.com)**: Squeezes png and jpg without a visible difference. Handy for a whole folder at once.
- **Your design tool**: Figma exports to png, jpg, svg and pdf, at 1x, 2x and 3x. Photoshop does the same under Export as.
- **The terminal**: For a folder full of images in one command, or in a script that runs on every build.

<!-- slide 23 -->

### In one command

*For anyone converting thirty images who does not want to spend an afternoon on it.*

```console
$ sips -Z 1600 *.jpg
macOS: scale everything down to 1600 px max
$ cwebp -q 80 photo.jpg -o photo.webp
photo.webp: 184 KB (was 612 KB)
$ ffmpeg -i recording.mov -vcodec h264 -crf 26 demo.mp4
video smaller without visible loss
$ npx @squoosh/cli --webp auto images/*.jpg
or a script that walks your folder
```

<!-- slide 24 -->

## 4. On your page

*The right image on the right screen, without your layout jumping.*

<!-- slide 25 -->

### Four attributes that matter

*These four sit on every image you put on a page.*

```html
<img
  src="model-800.webp"
  srcset="model-400.webp 400w, model-800.webp 800w, model-1600.webp 1600w"
  sizes="(max-width: 700px) 100vw, 700px"
  width="800" height="533"
  alt="Scale model of the station square, seen from the platforms"
  loading="lazy"
>
```

> [!TIP]
> `srcset` lets the browser pick the lightest file that is still sharp enough. On mobile that beats all your other optimisations together.

<!-- slide 26 -->

### Width, height and lazy loading

*Two attributes against jumping text, and one against downloading for nothing.*

| What | Why |
| --- | --- |
| `width` | Together with height the browser knows the ratio before the image arrives |
| `height` | Without those two your text jumps down the moment the image loads |
| `loading="lazy"` | Images below the fold are only fetched once you scroll there |
| `alt` | What there is to see, for screen readers and for when the image fails |

> [!WARNING]
> Never put `loading="lazy"` on your biggest image at the top. That is exactly the one that has to appear immediately.

<!-- slide 27 -->

### Alt text that says something

*Describe what there is to see, not that it is an image.*

| Not | Yes |
| --- | --- |
| `alt="image"` | `alt="Scale model of the station square"` |
| `alt="IMG_2043.jpg"` | `alt="Three students at a workbench"` |
| `alt="logo"` | `alt="Karel de Grote University College"` |
| `alt="decorative line"` | `alt=""` |

> [!NOTE]
> An empty alt attribute is a deliberate choice: this image is decoration, skip it. Leaving the attribute out entirely is not.

<!-- slide 28 -->

### Colour

*Your export looks dull or too vivid in the browser. Usually the colour profile is to blame.*

- The web assumes sRGB, which is the safe space
- Your camera and your Mac often work in Display P3, with more vivid colours
- Export without a profile and the browser guesses sRGB
- Set the profile to sRGB in your export dialog and embed it

> [!TIP]
> The same goes for your screen. An image that looks great on your laptop can land completely differently on a cheap monitor.

<!-- slide 29 -->

## 5. Video and sound

*Same logic, other numbers.*

<!-- slide 30 -->

### Video in short

*Four things you never go wrong with.*

| What | Why |
| --- | --- |
| mp4 with h.264 | Plays everywhere, older devices included |
| 1080p is plenty | 4K on a web page is four times the weight for nothing |
| `-crf 26` | The knob in ffmpeg that trades quality against size |
| `poster` | An image shown before the video has loaded |

> [!WARNING]
> Video does not belong in your git repo. Put it on a server or a service and point at it with a url.

<!-- slide 31 -->

### Sound

*Two formats are enough, and the difference is the same story as with images.*

#### wav

- Raw recording, nothing thrown away
- About 10 MB per minute
- What you keep and edit
- Never what you put on a page

#### mp3 or m4a

- Compressed, ready to share
- About 1 MB per minute
- 128 kbps for speech, 192 or higher for music
- What you export and publish

<!-- slide 32 -->

## 6. Working files

*The folder you work in, and the folder you hand over.*

<!-- slide 33 -->

### Source and export

*Two different things, and mixing them up costs you an afternoon.*

- **Your source file**: `.fig`, `.psd`, `.ai`, `.blend`. Every layer, every piece of text, still editable. You keep this, also after the deadline.
- **Your export**: `.webp`, `.png`, `.svg`, `.mp4`. Flattened and squeezed for one purpose. Deleting is fine, you make it again.

> [!WARNING]
> Editing an export means working on a copy that already lost information. Always go back to the source.

<!-- slide 34 -->

### Where they live

*The same naming rules as the rest of your files, and a separate folder for your sources.*

```bash
portfolio/
  src/
  public/
    img/
      model-station-square-800.webp
      model-station-square-1600.webp
      logo.svg
  design/                      # source files, kept out of the build
    model.fig
    posters.psd
```

> [!NOTE]
> Lowercase, no spaces, the width in the name when you have several versions. That way updating your srcset tells you which file you need.

<!-- slide 35 -->

### Why is a png usually a bad idea for a photo?

- A. Png throws nothing away, so a photo becomes enormous in it
- B. Png cannot show photographic colours
- C. Png does not work in every browser
- D. Png loses too much quality

**Answer:** A. Png throws nothing away, so a photo becomes enormous in it

Png keeps every pixel exactly. With a photo holding thousands of colour shades that gives you a file four to ten times heavier than the same photo as webp or jpg, with no visible difference.

<!-- slide 36 -->

### Cheat sheet

*What you check on every image.*

- **Format**: Photo: webp. Logo or icon: svg. Screenshot with text: png. Motion: mp4.
- **Width**: No bigger than the spot it sits in, times two for retina.
- **Weight**: Under 200 KB per image, under 2 MB for a whole page.
- **In html**: `width`, `height`, `alt`, and `loading="lazy"` except at the top.
- **Colour**: Export in sRGB and embed the profile.
- **Files**: Keep the source apart, export again instead of editing.

<!-- slide 37 -->

### Task: Five images again

*20 minutes, On your own*

Take a project with images in it. An exercise, your portfolio, anything that is online.

1. Check in the developer tools, Network tab, what each image weighs
2. Export the five heaviest again at the right width, in webp
3. Put width, height and alt on every image in your html
4. Measure again and note the difference in total page size

<!-- slide 38 -->

### Further

*Four sources you come back to later.*

- **[squoosh.app](https://squoosh.app)**: Compare formats side by side, with the weight included.
- **[web.dev images](https://web.dev/learn/images)**: The full story on images for the web, from formats to srcset.
- **[svgomg](https://jakearchibald.github.io/svgomg/)**: Cleans the junk out of an svg that came from Figma or Illustrator.
- **[caniuse.com](https://caniuse.com)**: Which browser supports which format, always up to date.

## Glossary

- **Raster**: An image stored as a grid of pixels, each with its own colour. Photos and screenshots are raster, and scaling up gives you blocks or blur. (slide 6)
- **Vector**: An image stored as instructions: shapes, lines and colours. Stays sharp at any size, which makes it the choice for logos, icons and illustrations. (slide 6)
- **Resolution**: How many pixels wide and high an image is, like 1920 × 1080. Width times height gives you the number of megapixels. (slide 7)
- **DPI**: How many dots of ink go on an inch of paper. Only matters for print (300 dpi is the standard), a browser only looks at the number of pixels. (slide 8)
- **Retina**: A screen with more physical pixels per css pixel, readable in JavaScript as devicePixelRatio. That is why you export at 2x and show at 1x, or your image looks soft. (slide 9)
- **jpg**: The safe format for photos, opens anywhere. No transparency, and every save costs quality. (slide 12)
- **webp**: The same image as jpg at roughly 30% less weight, with transparency when you need it. The default choice for a photo on the web today. (slide 12)
- **avif**: Even lighter than webp, especially with large flat areas. Slower to export, and browser support is good but not complete. (slide 12)
- **png**: A lossless format with transparency. Good for screenshots and text in an image, far too heavy for a photo. (slide 13)
- **svg**: A vector format that is plain text: open it and the shapes are right there. Scalable and styleable with css, which makes it ideal for logos and icons. (slide 15)
- **currentColor**: A css value that takes the colour of the text around it. One svg icon gets any colour that way, without a second file. (slide 15)
- **Alpha channel**: The part of an image that says per pixel how see-through it is. png, webp, avif and svg have one, jpg does not, so you get a white or black background instead. (slide 14)
- **Lossy**: Compression that throws away detail your eye barely sees. Much smaller, and it never comes back. jpg, webp, avif and mp4 work that way, fine for photos and video. (slide 19)
- **Lossless**: Compression that keeps every pixel exactly. Bigger, but you lose nothing: png, webp lossless and zip. For screenshots, text and flat colour. (slide 19)
- **Generation loss**: Quality you lose by opening and saving a jpg again and again, because every round compresses it again. So always edit your source file and export again. (slide 20)
- **srcset**: An attribute on <img> with several widths of the same image. The browser picks the lightest file that is sharp enough for the screen. (slide 25)
- **Lazy loading**: With loading="lazy" the browser only fetches an image once you scroll towards it. Never on the big image at the top, that one has to appear immediately. (slide 26)
- **Alt text**: Describes what there is to see in an image, for screen readers and for when it fails to load. An empty alt="" says on purpose: this is decoration, skip it. (slide 27)
- **sRGB**: The colour space the web assumes. Your camera and your Mac often work in the more vivid Display P3, so export in sRGB and embed the profile. (slide 28)
- **CRF**: The setting in ffmpeg (-crf) that trades the quality of a video against its size. At 26 an mp4 gets a lot smaller without visible loss. (slide 30)
- **Source file**: Your working file with every layer and piece of text still editable: .fig, .psd, .ai or .blend. You keep it, also after the deadline. (slide 33)
- **Export**: A flattened and compressed version of your source file, made for one purpose. It is an end product: to change something, go back to the source. (slide 33)

## Links and sources

### In the deck

- [squoosh.app](https://squoosh.app) (slide 22, slide 38)
- [ImageOptim and TinyPNG](https://imageoptim.com) (slide 22)
- [web.dev images](https://web.dev/learn/images) (slide 38)
- [svgomg](https://jakearchibald.github.io/svgomg/) (slide 38)
- [caniuse.com](https://caniuse.com) (slide 38)
