Breaking the Box: Images Beyond the Margins
This page has a bit of a margin on narrow screens, a medium-sized margin on my desktop (even in a constrained window), and a large margin on the widest screens. I’ve always thought I could make use of the extra space in that last scenario, so I recently did just that by pulling the images outside the box of the main content.
I first implemented a two-phase ‘outdent’: a tiny amount on narrow screens and a larger amount on wider screens. I didn’t like how cramped the second step looked, though. I could have solved it by tweaking the numbers, but I theorized I could do it in a continuous manner where the images started with a minimal outdent on narrow screens and gradually moved further based on the available space until they lay completely outside the box. The constraints were that I wanted a gutter between the content and the images in all cases, as well as a margin between the images and the edge of the viewport. It turned out to indeed be possible:
I pulled this off with a veritable tower of Custom Properties:
Sass.float
max-width: var(--width)
// I use `--spacing-unit` to establish consistent sizing throughout the site. Set to taste.
--min-outdent: calc(var(--spacing-unit) / 2)
// Images should be 400px wide at most.
--width: min(50%, 400px)
// Completely displace image if possible.
--max-outdent: var(--width)
// At most, maintain this much space on the content side.
--max-content-gutter: calc(var(--spacing-unit) * 1)
// `--ideal-width` is my desired text width (`38rem`).
// `--padding` is the desired space around it.
--available-space: calc(100vw - var(--ideal-width) - var(--padding))
// Set the gutter according to the available space.
--content-gutter: clamp(0px, var(--available-space) / 2, var(--max-content-gutter))
// `var(--padding) * 4` is my ideal gutter; let it grow from the minimum of `var(--padding * 3)` by subtracting half the available space.
--viewport-gutter: calc(var(--padding) * 4 - clamp(0px, var(--available-space) / 2, var(--padding)))
// Finally, the outdent is ideally half the available space less the viewport gutter, but it should never be less than the minimum outdent or more than the maximum plus the content gutter. Multiply by -1 to move it out instead of in.
--outdent: calc(clamp(var(--min-outdent), var(--available-space) / 2 - var(--viewport-gutter), var(--max-outdent) + var(--content-gutter)) * -1)
// When floated to the left, pull to the left, add a gutter to the right, and anchor `transform` to the left side so scaling doesn’t make it disappear offscreen.
&--left
float: left
margin-left: var(--outdent)
transform-origin: center left
margin-right: var(--max-content-gutter)
// Vice versa when floated to the right.
&--right
float: right
margin-right: var(--outdent)
transform-origin: center right
margin-left: var(--max-content-gutter)
It might be easier to understand with an interactive example:
However, as proud as I was of my ingenuity, after a day or two, I had to admit I didn’t like the awkward intermediate positions of the images. I reverted to a two-step value, and then added a third step to completely pull out the images on the widest screens.