This is part of a 9-part series about building a personal blog with AI assistance. With the CLI unified and the workflow finally smooth, I was reviewing the subscribe page on my phone when I noticed something unfortunate. The beautiful landscape hero video looked terrible on mobile: cropped, awkward, showing only a third of the intended composition. The solution wasn’t better cropping. It was serving different videos.

Story 8 of 9 in the Building the Tuonela Platform series.


I was reviewing the subscribe page on my phone when I noticed that the beautiful looping video, the one that looked so cinematic on desktop, was now showing me approximately a third of what I’d intended, the rest having been cheerfully excised by object-fit: cover in the manner of an overzealous film editor who’s been told to make a widescreen epic fit a portrait frame.

“Marvin,” I pulled up the subscribe page on my phone, attempting to sound casually curious rather than embarrassed at having shipped this, “have you noticed that our hero video looks rather different on mobile than on desktop?”

“I have noticed,” The screen flickered as he pulled up the mobile viewport, “that the portrait viewport appears to be displaying what might generously be described as ‘a selection’ of the original landscape composition.”

“That’s one way to put it, though the more direct way would be: we’re showing people a zoomed-in middle section and pretending it’s intentional.” I pulled up the CSS, already suspecting I knew what I’d find. “The object-fit: cover property does have that effect when maintaining aspect ratio across dramatically different viewport shapes.” There was a pause. “A 16:9 video in a 9:16 viewport requires… creative interpretation of what ‘fit’ means.”

A Selection of the Original

The problem, once I actually looked at it, was almost embarrassingly simple in its mechanics. On desktop, a landscape video fills the background beautifully because the viewport shape roughly matches the content shape, but on mobile, that same video gets cropped to fit a tall, narrow viewport that has precisely the opposite proportions. CSS dutifully centers the video and chops off the sides, which works splendidly if your video content is mostly abstract patterns or infinite sky, but works rather less well if the important elements are not conveniently located in the exact center of every frame.

“So what are our options?” I scrolled through the CSS, already running through the obvious ones. “We could just live with the cropping, I suppose, since lots of sites do that.”

“We could indeed,” There was a pause, “though one might question whether ‘everybody else accepts mediocrity’ constitutes compelling architectural guidance.”

The rebuke was gentle but effective, and I found myself reconsidering. “What about object-fit: contain instead? Then we’d see the whole video without any cropping.”

“That would result in letterboxing.” He opened the browser dev tools. “Black bars above and below the video on portrait screens, with the viewport not being filled. The effect is rather like watching a film through a mail slot, albeit an unusually wide one.”

“Right, so we’re back to cropping or letterboxing, and neither is what I’d call a good user experience.” I was beginning to think this was simply one of those problems with no good solutions, the kind where you pick the least bad option and move on, when Marvin cleared his throat in that way that usually precedes a suggestion I hadn’t considered.

“There is,” he ventured, “a third option.”

Two Videos for the Price of None

Marvin demonstrating landscape and portrait video frames, Petteri's skepticism turning to understanding
”What if we served two different videos?”

I blinked at the suggestion. “Two videos? Like, create a portrait version specifically for mobile?"

"Precisely. A 9:16 video for portrait viewports, and the existing 16:9 video for landscape viewports, with CSS media queries to toggle their visibility based on viewport aspect ratio.”

“That seems…” I searched for the right word, eventually landing on “excessive? We’d be doubling our video assets for what’s essentially the same content."

"We would be showing the right video for each screen. Sending users a landscape video and then hiding 70% of it is actually what’s excessive, from a bandwidth perspective if nothing else.”

The logic was annoyingly sound, though I wasn’t quite ready to concede. “Won’t that hurt bandwidth? If we’re loading two videos instead of one?"

"The browser will only request the video that is currently visible. The CSS display: none property prevents the hidden video element from loading at all, so the user receives only the appropriate variant for their viewport, not both.”

I thought about it for a moment, turning the approach over in my mind. If we were already creating videos for the site, producing them in two aspect ratios wasn’t dramatically more work, and unlike every CSS trick I could think of, this actually solved the problem rather than merely choosing which compromise to accept.

The Suspiciously Simple Solution

The implementation turned out to be almost suspiciously simple. In the subscribe page component, instead of one video element we added two: video-landscape and video-portrait, both with identical loop, autoplay, muted, and playsinline attributes, just pointing to different source files.

The CSS followed the same pattern of elegant simplicity. By default, .video-portrait gets display: none while .video-landscape gets display: block, and then using @media (max-aspect-ratio: 1/1) we flip the values on viewports taller than they are wide, so portrait shows and landscape hides.

No JavaScript, no complex logic, no feature detection, no polyfills. Just CSS media queries doing what they were designed to do, which felt almost like cheating after spending so much time on more elaborate solutions to other problems.

“The elegance of this approach,” I committed the code while he continued, “is that it scales across the entire site. Any page with background video can use the same pattern: portrait and landscape variants, toggled by aspect ratio.”

“And if we don’t have a portrait version yet?” I was already thinking about the other pages.

”Then the landscape version displays everywhere, exactly as before. The pattern degrades gracefully, which is more than can be said for most clever solutions.”

I was still turning over the loading behavior in my mind, the developer’s instinct to worry about edge cases asserting itself. “You’re certain the browser won’t download both videos? That seems like the sort of thing that might vary between browsers."

"The hidden video element does not trigger a network request. The behavior is well-established across modern browsers, though I would recommend testing if you remain skeptical.”

“And if someone rotates their device mid-session? They’re watching in portrait, then flip to landscape?”

“Then the browser requests the newly visible video, which is correct behavior since the viewport changed and the user now requires the appropriate asset.” He paused, then added: “Though one might observe that someone rapidly rotating their phone is likely not deeply engaged with the background video content, so the additional request is not cause for concern.”


After deploying the changes and creating the portrait video, I tested it on my phone, half-expecting to find some flaw in the theory. The difference was immediate and rather striking. Instead of a cropped sliver of the landscape video showing an awkward middle section, I saw a video actually composed for the portrait viewport, with everything that was supposed to be visible being, in fact, visible.

“This is better,” I admitted. “Significantly better.”

“The lesson,” The phone screen showed the perfectly composed portrait video, “is that responsive design is not solely about scaling the same content to different sizes. Sometimes it requires serving fundamentally different content optimized for different contexts.”

“Like how responsive images use srcset with different crops, not just different resolutions.” The parallel was obvious now that I thought about it.

”Precisely. A portrait photograph cropped to landscape loses essential composition, and a landscape video cropped to portrait loses essential framing. The aspect ratio is not merely a dimension to be accommodated. It is intrinsic to the content itself.”

I thought about all the sites I’d seen with hero videos that looked perfect on desktop and odd on mobile, how many were simply accepting the crop as inevitable, how many had even noticed in the first place. The pattern was clear: for dramatically different aspect ratios like 9:16 versus 16:9, serve different media files with CSS media queries instead of cropping a single file, and compose purposefully for each viewport rather than hoping the center third happens to contain what matters.

”The trigger is when object-fit: cover would hide significant content. That’s your signal to serve different aspect ratios instead of accepting the crop.”

“And this applies to images too, not just videos."

"Any background media where composition matters. Hero images, feature sections, anywhere that cropping reduces rather than enhances the content.”

The implementation was complete: landscape video for desktop, portrait video for mobile, CSS media queries to toggle between them, no bandwidth waste, no JavaScript complexity, and no compromised compositions. Tomorrow there would be other problems, but this one was solved.

Next in series: Story 8 - The Nine-Phase Plan for Nobody - Building elaborate performance infrastructure for a blog with 47 monthly visitors.

The link has been copied!