diff --git a/content/blog/2024/zoomies.md b/content/blog/2024/zoomies.md
new file mode 100644
index 000000000..975527f7e
--- /dev/null
+++ b/content/blog/2024/zoomies.md
@@ -0,0 +1,553 @@
+---
+title: Zoom, zoom, and zoom
+sub: The three types of browser (and CSS!) magnification
+author: miriam
+date: 2024-07-09
+image:
+ src: blog/2024/zoomies.jpg
+ alt: >
+ A dog zooming by the camera, up-close,
+ body twisted and eyes wide
+ as it circles a grass yard
+ position: top
+summary: >
+ I'm working on an article
+ about fluid typography,
+ and relative units.
+ But instead, I fell down this rabbit hole --
+ _or a cleverly-disguised trap?_ --
+ trying to understand 'zoom' in the browser
+ (not Zoom™️ the software).
+ Since I couldn't find any up-to-date articles
+ on the subject,
+ I thought I should write one.
+tags:
+ - Article
+ - CSS
+ - Layout
+---
+
+{% import 'embed.macros.njk' as embed %}
+{% import "quotes.macros.njk" as quotes %}
+
+In brief:
+there is wide support for
+three different types of 'zoom' --
+available both to site visitors
+and (to some extent) CSS authors:
+
+- **Page zoom**
+ is the default with a handy keyboard shortcut,
+ and roughly matches behavior of
+ the CSS `zoom` property.
+- **Scale factor** (or '_pinch zoom_')
+ was introduced by early versions of mobile Safari,
+ and may only be available through
+ trackpad or touch interfaces --
+ roughly matching the behavior of
+ the CSS `scale` transform.
+- **Text-only zoom** is also provided
+ by Firefox and Safari.
+ While not directly available in CSS,
+ the behavior is similar
+ to changing default font size
+ on a site that uses entirely
+ relative text sizing with `rem` units.
+
+## What's a (CSS) pixel?
+
+To understand these different zoom behaviors,
+it's helpful to understand
+that a `pixel` is not a completely fixed unit --
+at least not the CSS pixels
+we access through the `px` unit.
+
+**Device Pixels** are specific to an output device,
+and are physically determined by the hardware.
+To quote the [CSS Values & Units Specification](https://drafts.csswg.org/css-values/#device-pixel):
+
+{% set devicePixelQuote %}
+A _device pixel_
+is the smallest unit of area on the device output
+capable of displaying its full range of colors.
+For typical color screens,
+it’s a square or somewhat rectangular region
+containing a red, green, and blue subpixel.
+{% endset %}
+
+{{ quotes.blockquote({
+ 'text': devicePixelQuote,
+ 'name': 'CSS Values & Units Specification',
+ 'url': 'https://drafts.csswg.org/css-values/#device-pixel'
+}) }}
+
+These can range in size dramatically.
+Printers can generally fit more dots
+in a tighter space (more _pixels per inch_)
+than a screen can,
+and modern screens have smaller pixels
+than ever before.
+If we relied on those
+physical device pixels for design,
+all our interfaces would become
+too small to read or interact with
+on higher-resolution devices!
+
+Operating systems often provide one
+layer of device-pixel abstraction --
+allowing us to set a screen 'resolution'
+that is different from the physical potential
+of the hardware.
+I have a 4k monitor here
+with `3840 x 2160` physical pixels,
+but to make the interface more legible
+it renders at a `1920 x 1080`
+resolution by default.
+
+That means we have twice the _pixel density_ --
+we can now fit multiple physical pixels
+inside a single resolution 'pixel'!
+That ratio of rendered pixels to physical pixels
+is called the _device pixel ratio_.
+For my screen, at the default settings,
+I have a device pixel ratio
+(what CSS calls a 'resolution')
+of `2x` or `2dppx` (_dots per `px` unit_).
+
+{{ embed.codepen(
+ id='oNRrLLy',
+ title='What is a pixel?',
+ user='miriamsuzanne'
+) }}
+
+To phrase it differently,
+the entire operating system is
+_zoomed in 200% by default_
+on this monitor.
+
+CSS adds another layer of pixel abstraction.
+While the CSS `px` unit is generally
+equivalent to a single OS-provided 'pixel' by default,
+there are several ways they can diverge --
+including the zoom/scale options
+that we'll discuss below.
+
+But also,
+rather than having fixed
+real-world dimensions,
+the _CSS pixel_ (`1px`) and _CSS inch_ (`1in`)
+have a fixed _relationship to each other_.
+There are always `96` CSS pixels for every CSS inch.
+But depending on the output media (screen vs print),
+their actual sizes might vary:
+
+- On screens,
+ the `px` acts as an '[anchor unit](https://drafts.csswg.org/css-values/#anchor-unit)',
+ and physical units (like `in`, `cm`, `mm`)
+ are determined relative to that.
+ It might not match a real-word inch,
+ but you can count on the relationship: `1in == 96px`.
+- In print,
+ where physical measurements are more reliable,
+ the 'physical' units act as our anchor --
+ and the CSS pixel unit becomes relative instead
+ (`1px == 1/96in`).
+
+On screens,
+the actual size of a CSS inch
+depends on the screen resolution --
+and may not be anywhere close to a physical inch.
+But once you hit 'print',
+the inch becomes reliable,
+and pixels will resize to fit.
+
+No matter the medium,
+that `1:96` inch-to-px relationship
+(determined by
+[the arm-length of Håkon Wium Lie](https://drafts.csswg.org/css-values/#reference-pixel))
+is always the same.
+We only change which unit is anchored to the media,
+and which one is adjusting to maintain the ratio.
+
+Elika Etemad
+(aka Fantasai)
+covered this in her recent talk at CSS Day:
+[_Standardization Stories_](https://www.youtube.com/watch?v=krh_nb9PdVk).
+
+## Why are there two viewports?
+
+You might have heard about
+_the browser viewport_,
+or even used _viewport units_
+(`vw`/`vi`/etc).
+But browsers actually provide
+_two viewports_:
+
+- The **layout viewport**
+ is the box that we put our web pages in.
+ You can think of it like
+ the parent element of the `` tag.
+ It might overflow (and have scrollbars),
+ but it still has a fixed size
+ based on your browser window.
+ When we make that layout viewport larger,
+ we can fit more things on the page
+ without overflowing.
+- The **visual viewport**
+ is the window we look through
+ to see the page.
+ When we make the visual viewport larger,
+ we can see more of the layout at once.
+
+Those might sound the same,
+because they usually are!
+Both are based on
+the size of your browser window,
+or the size of the page we print on.
+
+Even when we have enough content
+to overflow the layout viewport,
+it stays attached to the visual viewport.
+The box isn't growing,
+it's _overflowing_.
+Viewport units
+(based on the layout viewport)
+don't change their value
+when we create longer pages.
+
+So there's a difference between
+_overflowing the box_
+(when our content grows)
+and _only seeing part of the box_
+(when we scale one viewport
+in relation to the other).
+
+Imagine a photo-editing tool.
+The image itself has a 'canvas size'.
+We can enlarge elements of the image
+so that they overflow the canvas
+(and usually get cropped).
+That's like the relationship
+between content and the layout viewport.
+But we can also zoom the entire canvas
+in or out.
+That doesn't change the relationship
+between content and canvas,
+but it can change how much of the canvas
+we see in our editing interface.
+That interface window
+is like the visual viewport.
+
+Sometimes we can't see
+all the content inside the canvas,
+and sometimes we can't see
+the entire canvas in our browser window.
+
+Since I'm old,
+I'm drawn to microfiche
+as a visual analogy:
+
+{{ embed.figure(
+ data=[{
+ img: 'https://media1.giphy.com/media/SxFW9rZbk3mdvlTFNN/giphy.webp',
+ alt: 'A young man moving a plate of microfiche under a lens,
+ so the content pans across an old monitor'
+ }],
+ caption="Moving the layout viewport inside the visual viewport,
+ on a TV show I haven't seen (_Snowfall_)"
+) }}
+
+In most situations,
+the two viewports
+are the same size --
+the size of your browser window,
+or what's left of it after drawing
+the tabs and toolbars.
+But (as we'll see)
+there are some zoomed-in situations
+where the visual viewport
+can end up smaller (but never larger)
+than the layout viewport.
+
+It gets confusing
+(to me at least)
+because both viewports can overflow
+in different ways.
+When we add more content,
+we can overflow the layout viewport.
+In order to overflow
+the visual viewport,
+we need to make the layout viewport larger!
+And we can only do that
+with help from the browser.
+
+In researching this article,
+I also came across
+an old two-part QuirksMode post by PPK --
+[_A tale of two viewports_](https://www.quirksmode.org/mobile/viewports.html) --
+which covers this in depth.
+
+## Getting the zoomies
+
+To _zoom_ or _scale_ a page,
+we have to manipulate either the
+size of a CSS pixel
+in relation to the layout viewport,
+or the relationships _between_ the two viewports.
+Each approach gives a different result.
+
+This behavior is defined in
+the CSS [View Module specification](https://drafts.csswg.org/cssom-view-1/#zooming).
+
+### Page zoom: CSS pixels vs. the layout viewport
+
+Browsers all provide
+a _page zoom_ feature for us
+as we surf the web.
+I use it all the time.
+By default,
+pages load at `100%` page zoom,
+but we can zoom in or out from there.
+Generally,
+browsers will remember our zoom settings
+for each domain we visit.
+(I used to have Wikipedia load at 150%,
+but now they provide built-in tools
+for scaling the font size.
+Thanks, Wikipedia!)
+
+This is the most common form
+of zoom available to us web surfers.
+I use the Ctrl+/-
+(Cmd+/- on Mac)
+keyboard shortcuts quite often,
+but these controls are also available
+in a browser menu.
+
+Page zoom is similar
+to the resolution setting in your operating system.
+Adjusting the page zoom
+will change the ratio of
+_CSS pixels_ vs _device pixels_.
+In fact,
+browsers combine the operating system and page zoom
+to provide an overall _device pixel ratio_ --
+the relationship between a (physical) pixel
+and a rendered (CSS) pixel.
+
+Pixels on my 4k monitor are already zoomed `2x`/`200%`
+by the operating system,
+before the browser gets involved.
+If I also zoom a web page by `2x`/`200%` in the browser,
+the result is a `4x`/`400%` overall zoom --
+and a _device pixel ratio_ of `4:1`.
+
+This _zoom_ is applied to the size of a CSS pixel,
+_before the page is rendered_.
+By zooming in,
+we make each 'pixel' larger.
+But our layout viewport isn't growing at all,
+so our layout now contains _fewer_ `px`
+in each dimension.
+In effect, we've made
+the layout viewport _smaller_
+in relation to our pixels.
+
+**Page Zoom** is adjusting
+_the size of a CSS pixel in relation to the layout viewport_.
+Since that happens before rendering,
+it impacts the layout of the page.
+It's then reflected by media queries,
+which query a 'smaller' viewport
+when we zoom in --
+or a larger viewport zoomed out.
+
+As far as the browser is concerned,
+there's very little difference
+between _making the window smaller_
+or _making the pixels bigger_.
+The result is the same:
+_fewer pixels fit in the viewport_.
+
+### Scale factor: viewport vs. viewport
+
+The _scale factor_
+is also available in all browsers,
+but you're most likely to notice it
+on touch-screen devices.
+As far as I can tell,
+this was implemented originally
+for mobile Safari,
+and later added to the spec,
+and adopted by desktop browsers.
+In fact, the published spec
+mentions a previous name for it --
+_pinch zoom_ --
+and the Editor's Draft
+includes a brief explanation:
+
+{% set scaleFactorQuote %}
+The "scale factor" is often referred to as "pinch-zoom";
+however, it can be affected through means other than pinch-zooming.
+e.g. The user agent may zooms [sic] in
+on a focused input element to make it legible.
+{% endset %}
+
+{{ quotes.blockquote({
+ 'text': scaleFactorQuote,
+ 'name': "CSSOM View Module, Editor's Draft",
+ 'url': 'https://drafts.csswg.org/cssom-view-1/#zooming'
+}) }}
+
+I know I've experienced that.
+On Safari for iOS you can also double-tap
+elements in the page to 'zoom in'
+so that element fills the viewport.
+Testing here on a MacBook laptop with a trackpad,
+both the pinch and double-tap interactions
+work for me now in macOS Vivaldi (Chromium).
+
+If you play with this,
+you'll notice that it's quite different
+from the behavior of page zoom above.
+First: _we can only zoom in, not out_.
+There is no way to scale the page
+so that it is smaller than 100%
+of the visual viewport.
+And when we do 'scale' the page up,
+_the layout doesn't change,
+but we can see less of it_.
+
+Everything on the web page
+stays exactly where it was
+relative to everything else --
+even the media-queries remain untouched --
+we're just looking at a smaller area
+of the overall page.
+
+**Scale factor** is adjusting
+_the size of one viewport in relation to the other_.
+Specifically, the layout viewport
+can be scaled up larger (but not smaller)
+than the visual viewport.
+Since that happens _after rendering_,
+it has no impact on our page layout,
+or the available pixels,
+or any media queries.
+
+You might also notice a lack of scrollbars.
+We're not overflowing the box,
+we're zoomed in to view
+one smaller part of the box --
+and browsers handle that differently.
+
+{{ embed.codepen(
+ id='pomXRxP',
+ title='Zoom vs Scale',
+ user='miriamsuzanne'
+) }}
+
+### CSS `zoom` and `scale` properties
+
+There's an old CSS browser hack
+using `zoom: 1` to trigger `hasLayout`
+on Internet Explorer --
+an internal IE concept
+that's roughly equivalent
+to a modern
+[Block Formatting Context](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_display/Block_formatting_context).
+You can see it used
+in Jay Hoffmann's excellent
+[evolution of the clearfix](https://css-tricks.com/clearfix-a-lesson-in-web-development-evolution/).
+Other than that,
+I don't think I've ever
+paid much attention to the `zoom` property
+in 20-some years of writing CSS.
+
+It turns out there's a good reason for that.
+CSS `zoom` was initially IE-only.
+I believe it pre-dates IE6,
+released in 2001
+(MDN and CanIUse don't have data farther back),
+but it wasn't available in Firefox
+until **May 2024**.
+Zoom (the CSS property)
+[just became available](https://caniuse.com/css-zoom)
+in all browsers
+_this year!_
+
+The `zoom` property
+is similar to _page zoom_.
+Zoom changes the relative size of a CSS pixel
+in relation to its layout box,
+before rendering.
+Now we can apply that behavior to
+individual elements inside the page.
+
+We also have
+the much more commonly-used
+`scale()` transform,
+[available (with a prefix)](https://caniuse.com/transforms2d)
+since ~2010.
+[Over the last couple years](https://caniuse.com/mdn-css_properties_scale),
+a number of transforms
+(including `scale`)
+have become
+stand-alone properties.
+But the function and the property work the same --
+both of them behaving like
+the page _scale factor_.
+The entire element is scaled
+(up or down!)
+as a cohesive rendered unit,
+in relation to the things around.
+
+Or,
+as CanIUse explains the difference:
+
+> If e.g. `transform: scale(0.6)` is used on the `html` or `body` element
+> then it resizes the entire page,
+> showing a minified page with huge white margins around it,
+> whereas `zoom: 0.6` scales the elements on the page,
+> but not the page itself on which the elements are drawn.
+
+Note that
+only the browser can zoom or scale
+in a way that impacts our
+two viewports.
+But when we zoom or scale in CSS,
+we're applying the same concepts
+to elements on the page:
+
+{{ embed.codepen(
+ id='Exzzwgy',
+ title='Zoom/scale, viewport vs elements',
+ user='miriamsuzanne'
+) }}
+
+### Text-only zoom
+
+[Firefox](https://support.mozilla.org/en-US/kb/font-size-and-zoom-increase-size-of-web-pages)
+and [Safari](https://support.apple.com/guide/safari/zoom-in-on-webpages-ibrw1068/mac)
+provide an additional option to
+_zoom text only_.
+This is generally available
+as an alternative of _page zoom_.
+I'm still working on that article --
+all about font-sizing --
+so I'll save the details for later.
+
+In brief: it does exactly what it says.
+Text gets bigger,
+and nothing else changes.
+If you've ever wanted to zoom the text
+without _zooming_ or _scaling_
+anything else on the page,
+there it is!
+
+---
+
+Header image
+of a zooming dog
+by [Eric Sontroem](https://www.flickr.com/photos/96964826@N05/30947098457),
+[some rights reserved](https://creativecommons.org/licenses/by/2.0/)
diff --git a/src/images/blog/2024/zoomies.jpg b/src/images/blog/2024/zoomies.jpg
new file mode 100644
index 000000000..e8dc7ca54
Binary files /dev/null and b/src/images/blog/2024/zoomies.jpg differ