Image layout test page

I want to experiment with wider layouts, so want to have HTML/CSS formulas for breaking out of the normal content flow.

House styles

Permalink to “House styles”

Copy-paste-able snippets for image arrangements.

One image

Permalink to “One image”

Two images

Permalink to “Two images”

Three images

Permalink to “Three images”

Multiple rows

Permalink to “Multiple rows”

Specify Height

Permalink to “Specify Height”

Blur stretch singles

Permalink to “Blur stretch singles”

Blur stretch doubles

Permalink to “Blur stretch doubles”

This is possible, but didn’t always look that good, and would require more tweaking for images to resize aspect ratio-ally appropriately. See notes in .eleventy.js @ the twoBigImages function.


Permalink to “Workbook”

My process of working through getting the house styles.

Small, centered

Permalink to “Small, centered”

This image should be smaller than the main page flow, so should be centered.


The next one should also be smaller and centered.


Pixel density

Permalink to “Pixel density”

This image should display at 256. The source is 768. For displays that use higher pixel densities (e.g., retina displays, most phones), it should be crisp.


To compare two side-by-side, the following images are both displayed at 256 x 256 pixels, but their source images are:

  1. 256 x 256 pixels
  2. 768 x 768 pixels (i.e., exported @3x)

I use 3x for all higher-pixel-density images on this page simply because that’s best for my own devices. But devices should render any source / display ratio. E.g., here’s 0.5x, 2x, and 4x.







Text width image, pixel density

Permalink to “Text width image, pixel density”

Even without manually specifying a width (as we did in the above pixel density test), we expect the page width clamping to have the same effect, and higher pixel count images to be crisper.

The current full width of the layout is 704px.

The following image is 704 x 704 px, rendered at that size on the page.


The following image is 2112 x 2112 px, rendered at 704 x 704 px on the page.



We could go to 4x for future-proofing, but I think there is diminishing returns, even with devices.

Real image, pixel density

Permalink to “Real image, pixel density”

Deep dive into this in Image size test page

Full-width image

Permalink to “Full-width image”

This image will take up the full width of the page no matter what size the image or the page is. (My screen only goes up to 1680px width.) It will have no horizontal margins.


Full-width image, with horizontal margins

Permalink to “Full-width image, with horizontal margins”

See next section for technique notes. (These images aren’t width-limited, so they may go past 1500px width.)







Wider-than-text width centered image

Permalink to “Wider-than-text width centered image”

While the page width is ≤ the image width, this image will take up the full width of the page with no horizontal margin. Once the page is wider than the image, it will be centered in the page with equal horizontal margins.


We achieve the breakout by using the .full-width CSS class designed for full-width images, but we instead put it on a parent <div> to the image. This <div> then takes up the full screen width, and the image is free to position inside it.

For a desired 3x pixel density (width px: src 3k, disp 1k), its width needs to be manually limited, or it will, by default, be displayed at its true “size” and a lower pixel density. This can be accomplished with the attribute width="1000" or style="width: 1000px;"

Wider-than-text width centered image, horizontal margins

Permalink to “Wider-than-text width centered image, horizontal margins”

… as needed as the page shrinks.



Max-width (centered) wider img, horizontal margins only on ~m+ sizes

Permalink to “Max-width (centered) wider img, horizontal margins only on ~m+ sizes”

Desired behavior:

  • small (phone): no H margins (want to see as much of photo as possible)
  • medium: some H margins
  • large: bigger than photo, so margins don’t matter

ph1-m ph3-l

Three images arranged wider than text

Permalink to “Three images arranged wider than text”

These each take up exactly 1/3:

512x683 512x683 512x683

We can add a horizontal page margin:

512x683 512x683 512x683

⅓, ph3

If we make them each take 33%, they distribute the remaining 1% of available width between them.

512x683 512x683 512x683

33%, ph3

We can set their max-width CSS so they are spaced more evenly when space is available.

512x683 512x683 512x683

⅓, ph3, max-width imgs

This effect—using available spacing—is more readily visible with smaller images.

300x400 300x400 300x400

⅓, ph3, max-width imgs

To get the images to stay closer to the center, you make the images bare and add justify-center flex. However, they then have no margin. Adding padding or margins works until the page shrinks so their widths are shrinking; then they balloon out past the page width with their extra margins/padding. To fix, I had to wrap them in <div>s, then control the padding on the outside. Making the images proper (max) widths then involves a calc() on the <div>. Quite complex.


justify-center + ph2; divs w/ ⅓, ph1, max-width (on divs); imgs bare

Turning up the padding is fine. Be careful going down the rabbit hole of trying to get consistent horizontal page margins, though. Because of symmetric padding on the image <div>s (which we need so the images are the same size and they aren’t shifted L or R on the page), combined with overall padding, we end up in 0.5 Tachyon units (I think). LOL went down rabbit hole. Turns out switching to margins makes this somehow all work beautifully, and don’t even need calc() in the max-widths, because we’re not affecting the image sizes now. (Next example still uses padding; house style uses margins.)


justify-center + ph3; divs w/ ⅓, ph2, max-width (on divs); imgs bare

Regardless, we now have something that looks and works fine for 3 max-width’d imgs w/ some margins.

Seeking a “house style” below:


Margin 1 between images always. Page border is: nothing (small), 1 (m), 3 (l).

Testing this third house-style w/ larger images


Margin 1 between images always. Page border is: nothing (small), 1 (m), 3 (l).

Simplifying from later findings; I think we don’t need w-third at all.

Portrait and landscape w/ “house style”

Permalink to “Portrait and landscape w/ “house style””

The following isn’t working:


Broken portrait & landscape (first image shrinks before & too much). Margin 1 between images always. Page border is: nothing (small), 1 (m), 3 (l).

While margins are fine, and the heights all match up at full size, but the height of the first image is shrinking before the second.

Wild enough, removing the <div> third/two-third widths fixed.


Fixed portrait & landscape. Margin 1 between images always. Page border is: nothing (small), 1 (m), 3 (l).

Mixed sizes with house style

Permalink to “Mixed sizes with house style”

Incredibly, this just works as well. My takeaway is to export things to be the same height and then let flexbox’s basic layout take it away.

Other little tricks

Permalink to “Other little tricks”
  • make images db (i.e., display: block) so that divs don’t leave little bits of extra space apparently for descender elements

  • accordingly, then add mv1 when doing grids for vertical spacing

  • … and relatedly, don’t forget to add novmargin to the images so that the margins can be controlled with the containing <div>s


Permalink to “Rewrapping”

Simply adding flex-wrap to the container gives us a simple wrap, where elements are wrapped as soon as the row can’t fit both at full size. We can add novmargin to the images and fig to the container if we want them to wrap closely (moving the vertical margin to the overall block).


Rewrapping w/ house style, but doing immediate when smaller than full size.

Ideally, I’d want to be able to choose to wrap only when they’ve shrunk to a certain size. In other words, we don’t need the photos to be full size, but there might be a significantly smaller display size (like if it would only be 200px wide or something) for which we’d rather wrap.

This might be possible using display: grid and grid-template-columns: ..., but TBD still. A couple resources:

… or, wait, maybe we can just use a media query to only add flex-wrap! Going from the house style below. Also needed to do margin adjustments: inter-pic margin is right only when not wrapped, and bottom when wrapped.

This isn’t perfect, because I think once the page width is less than even 600px or so, the photo get a bit too small, and this only wraps < 480px. But realistically, this will fix the other major viewing use case (phones), and all the media queries work exactly together, so I think it’s worth it.

Doing for 3 imgs too:

Height limits

Permalink to “Height limits”

I can’t ignore it: I probably implicitly designed for image heights that fit my viewport. Let’s think about limiting them.

Capping @ view height. Should we also set another max height? It actually seems to look pretty good everywhere.

Does this work for 2 imgs?

Wow, yes, it does beautifully… I guess I should just go for this? Only potential downside would be over-stretching for bigger screen devices. But honestly, being > CSSpx but < PHYSpx isn’t the end of the world, it’s already better than most photo displays people are going to encounter.

One more test: 1 img portrait.

Capping @ view height, portrait.

I think the answer here is that “it depends on the design.” For almost all layouts, a portrait photo isn’t going to get that big. For laptop/desktop/ipad-in-landscape, the height caps the img, leaving lots of space in the width, and it goes with the flow. For a phone, the width caps it, since they’re so tall, and the photo only takes up ~1/2 of the screen. BUT, the one exception is the iPad in portrait mode. It’s exactly portrait-photo-size, so a big portrait photo will fill the whole thing.

That’s where the design part comes in. If it’s a nice photo, it could be really cool. If it’s kinda crummy, yeah, it’ll be a huge crummy photo. If you want to design around that for iPad users in portrait mode, then throw in a min(100vh, 939px) or something. Otherwise, just keep 100vh and roll with it.

Determination for max-height:

  • min(100vh, 939px) — general purposes. let images be seen in full, and also keep things at least @2x. wider displays will have photo sets nicely centered in the middle
  • 939px — portrait images we want as bigger/establishing. this way smaller desktops will have it display larger (than the viewport height), and we’re keeping things crisp for ipads rather than having them blow up huge.

Varying Widths: Region Filling

Permalink to “Varying Widths: Region Filling”

Ugh, the thing I didn’t want to address.

In some situations, this will happen inevitably as long as we’re limiting photo heights to viewport heights, and are unwilling to make surrounding photos more narrow (width-limited). Examples:

  1. a portrait photo, then a landscape one

  2. a landscape photo (height-limited), then two side-by-side photos (width-limited)

I’m still torn philosophically on limiting photos to viewport heights. I think I like it, at least for landscapes. For portraits where the aim is more establishing footage, I’m not so sure; they’d be so tiny on a poorly-dimensioned landscape-oriented screen.

I am pretty confident limiting side-by-side images to narrower widths is bad, though. They are already nearly too small at full-screen with full width access; much smaller and it’s basically pointless to have them.

Assuming I do end up with consecutive varying photo row widths, the main thing I can try is some background. Below contains a graveyard (in comments) of approaches, with one that finally worked:

  • ❌ SVG-generated fractal noise (colors too random)
  • ❌ BG gradient (manual + didn’t look good)
  • ❌ BG gradient + alpha (manual, still didn’t look good)
  • ❌ BG image, as addl. element, CSS blurred (could not get horizontal edges crisp)
  • ❌ BG image, as parent. element, opacity w/ background-blend-mode (could not get blurring, didn’t look good without)
  • BG image, as addl., element, blurred w/ SVG filter (hat-tip) (looks good, can re-use image, crisp edges). Implemented below:

However, now a new challenge arises: it’s too wide.

Varying Widths: Width Matching [draft]

Permalink to “Varying Widths: Width Matching [draft]”

Because the photos are now all viewport height-limited, it’s possible for even side-by-side images to not take up the full width. This means that our new burred image background gets 100% page width when it shouldn’t.

Reading a bit about CSS Flexbox, it seems like it really only thinks row-by-row. When there’s a new flex row, it doesn’t know about the content above it. This seems to be a problem because I explicitly want my rows to be of equal width. CSS Grid is recommended for 2D layouts.

However, thinking a bit more, my constraints are kind of odd:

  • the target width should be determined dynamically by the contents of the rows
  • the target width will be the largest combined content width
  • all rows will achieve this target width
  • for rows whose content fills less than the target width
    • the columns inside should spread to fill the remaining space proportionally
    • the content should be centered
    • the backgrounds will have blurred/semi-transparent versions of the images
  • all items become 1 per row for smaller displays
  • ideally, none of this uses JavaScript
  • ideally, this is achieved with minimal manual markup

… phew.

I can see why you’d want to simply design on a fixed-width grid.

Explicit image sizes: basics

Permalink to “Explicit image sizes: basics”

An age-old confusion of mine. Learning in the hopes I can use this to get lazy loading to work.

Takeaway: CSS instructions take priority over attribute dimensions with both are given.

NB: Here I’m using “pixels” to mean (a) CSS pixels when referring to the display, (b) true image pixels when referring to the image size.

No dimensions given; displays at original size:

<img src="/assets/garage/image-test-pages/256x256.png">

Attribute dimensions match image dimensions; same:

<img width="256" height="256" src="/assets/garage/image-test-pages/256x256.png">

Attribute dimensions do not match image dimensions; displays attribute dimensions:

<img width="100" height="100" src="/assets/garage/image-test-pages/256x256.png">

Attribute dimensions do not match image dimensions, and do not match aspect ratio; displays attribute dimensions:

<img width="150" height="100" src="/assets/garage/image-test-pages/256x256.png">

Attribute dimensions do not match image dimensions, but CSS style does; displays CSS style dimensions:

<img style="width: 256px; height: 256px;" width="100" height="100" src="/assets/garage/image-test-pages/256x256.png">

Attribute dimensions match neither image dimensions nor aspect ratio, but CSS style matches original (both dimensions and aspect ratio); displays CSS style dimensions:

<img style="width: 256px; height: 256px;" width="150" height="100" src="/assets/garage/image-test-pages/256x256.png">

Both attribute dimensions and CSS styles are different than original; displays CSS style dimensions:

<img style="width: 400px; height: 400px;" width="100" height="100" src="/assets/garage/image-test-pages/256x256.png">

CSS styles are different than original, but attribute dimensions match original; displays CSS style dimensions:

<img style="width: 400px; height: 400px;" width="256" height="256" src="/assets/garage/image-test-pages/256x256.png">

CSS style specifies non-pixel width (100%) and no height, while attribute dimensions match original; displays CSS width, but attribute height:

<img style="width: 100%;" width="256" height="256" src="/assets/garage/image-test-pages/256x256.png">

CSS style specifies non-pixel width (100%) auto height, while attribute dimensions match original; displays CSS width, and height to match correct aspect ratio:

<img style="width: 100%; height: auto" width="256" height="256" src="/assets/garage/image-test-pages/256x256.png">

Explicit image sizes: into house styles

Permalink to “Explicit image sizes: into house styles”

Now, to go more flexible. This uses the house style, which breaks out of the normal margins using the following container.

<div class="full-width flex justify-center ph1-m ph3-l fig">
<!-- image goes here -->

Here’s a normal house-style image, whose dimensions are 2,718 x 2,718.

<img class="db bare novmargin" src="/assets/garage/image-test-pages/[email protected]" style="max-height: min(100vh, 939px);">

But if we add the size attributes with the true image size, it goes too wide or too narrow, always taking up 100% width!

<img class="db bare novmargin" src="/assets/garage/image-test-pages/[email protected]" style="max-height: min(100vh, 939px);" width="2718" height="2718">

Can we fix it? If we add width: auto to the CSS, it fixes the case of it going too wide, but it will still go too narrow. In other words, when the image is width-limited, it won’t then shrink the height.

<img class="db bare novmargin" src="/assets/garage/image-test-pages/[email protected]" style="max-height: min(100vh, 939px); width: auto;" width="2718" height="2718">


  • aspect-ratio alone (w/o width spec) doesn’t fix anything vs original
  • width: auto and aspect-ratio doesn’t improve over width: auto
  • object-fit: contain almost works, ugh so close. it adds vertical whitespace above and below the image when it’s small (e.g., try 1/3 screen size). i guess it’s maintaining some kind of “box” that’s full size while resizing the image in it.
    • also can’t get rid of 100vh in the max-height though, even though object-fit: contain should height limit as well (?)
  • width: auto; height: auto works! but… is this really going to allow lazy loading now?