Responsive CSS cannot rescue a hero image that was composed for the wrong shape.
That is the whole argument, and it costs a week every time somebody learns it the slow way. You build a cinematic 16:9 hero. It looks expensive on the laptop. Then a visitor opens the site on a phone held upright, the building you framed so carefully is now a wall, the headline sits across the subject's face, and the thing that made the shot worth taking is somewhere off the left edge of the viewport.
You have probably tried to fix that in CSS. A different object-position, an aspect-ratio override at a breakpoint, maybe a scale transform to buy back some subject. Those tools slide the crop window around inside the frame you already have. None of them invent pixels that were never captured.
So the portrait vs landscape hero image question on mobile is not really a styling question. It is a capture question that shows up disguised as a styling question, three weeks after the shoot, when going back for another one is expensive.
Why does one 16:9 hero fail on a portrait phone?

A 16:9 source in a tall phone container loses more than half its width to the crop, so an off-centre subject vanishes before CSS gets a vote.
Run the arithmetic once and you stop arguing about it. Take a 390-pixel-wide iPhone viewport with a hero occupying roughly 500 pixels of height. Fill that 390×500 box using object-fit: cover from a 1920×1080 source and the browser scales until the short axis fits: height 1080 scales to 500, a factor of 0.463, which renders the full width at about 889 pixels. The container shows 390 of those. You keep 44% of the frame and throw away the rest.
Now place your subject where a good wide composition usually puts it, a third of the way in from one edge. It falls outside the surviving 44%. The phone does not clip it at the shoulder; it never receives it at all.
Calling that a rendering bug misplaces the blame. It is arithmetic you agreed to the moment you decided that one file would serve two aspect ratios.
Object-fit crops, it does not compose

object-fit and object-position choose which rectangle of an existing image survives. They are a pair of scissors with a ruler attached. Useful, and often enough for a portrait photo of a person where the head is near the middle, and useless for a composition whose meaning depends on the relationship between two things at opposite ends of a wide frame.
There is a CSS property that gets suggested here, object-view-box, which lets you define a viewbox inside a replaced element the way SVG does. It is still not Baseline and does not work across the browsers most of your traffic uses. Even if it shipped everywhere tomorrow it would not help, because it pans and zooms within the pixels you have. Same scissors. Nicer handle.
Actually, that overstates the pessimism slightly. There is one case where a single flexible image is the right call: when the subject is centred, the background is texture rather than content, and nothing in the frame carries meaning by its position. Skies. Fabric. Concrete. If your hero is a mood, one file is fine. If your hero is a statement, it is two files.
Should you ship separate portrait and landscape files?

Ship separate files whenever the subject's position inside the frame carries meaning; keep one flexible image only when the background is texture rather than content.
The decision is narrower than it looks. There are four real options and they sort by how much the composition matters and whether motion is involved.
| Approach | Assets to produce | Subject survives portrait | Choose it when |
|---|---|---|---|
One flexible image plus object-position | 1 | Only if centred | Background is texture, not content |
Art-directed <picture> with media | 2 or more crops | Yes, by construction | Composition carries meaning and the layout is static |
Poster image plus art-directed <video> | 2 clips, 2 posters | Yes, with one caveat below | Motion is the point and you control both cuts |
| Separate components per breakpoint | 2 or more | Yes | The hero's markup, not only its image, differs by device |
The third column is the one people skip, and it is the only column a client ever notices.
For the <picture> route the mechanics matter. The browser walks the <source> elements in order, evaluates each media condition, and as MDN puts it, if a source's media condition evaluates to false the browser skips it and moves to the next. First match wins, and the <img> inside is mandatory rather than decorative, because it supplies both the fallback and the alt text. Order your portrait source before your landscape source or write conditions that cannot both be true, or you will ship the wide crop to phones and never see it on your own machine.
web.dev draws the distinction better than I can: srcset and sizes are suggestions you hand the browser, while a <source> is closer to a command. Art direction needs the command.
Here is the decision procedure, in order:
- Ask whether the subject's position inside the frame carries meaning. If no, ship one image and set
object-positionto the focal point. Stop here. - Ask whether the hero moves. If it does not, use
<picture>with amediacondition on orientation or width, and produce a genuinely re-composed portrait crop rather than a centre cut of the wide one. - If it does move, produce two clips, two posters, and art-direct both, then read the video caveat below before you ship it.
- If the portrait and landscape heroes need different markup and not only different pixels, split the component, and keep the copy and the interaction identical so the content stays one thing.
If you work in Next.js, the framework does not expose art direction through the Image component at all. The current Image API reference routes it through getImageProps, pulling a srcSet for each crop and assembling a plain <picture> around them, with different width, height and quality per source. Their own example ships 1440×875 for desktop and 750×1334 for mobile. Those are not two sizes of one picture. They are two pictures.
The visual decision and the network decision are the same decision

Choosing the crop and choosing the bytes are one act, because the element that selects the source also selects the download.
This is where a lot of otherwise careful work falls apart. Teams build both crops, then deliver them by rendering both elements and hiding one with display: none. How many megabytes does your phone pull down for an asset it will never paint? On that pattern, all of them. You have doubled the cost of the hero to solve a cropping problem, which leaves you worse off than the cropping problem did.
Here's how that went on Elpida Solutions.
Elpida Solutions uses dedicated landscape and portrait hero media because the dove, architecture and headline cannot share one crop without sacrificing the subject on a phone. I also had to prevent mobile from downloading the desktop clip it never displays; the wrong source selection wasted more than a megabyte per first visit. The visual decision and the network decision were the same problem.
A megabyte on a first visit is not a rounding error. The 2024 Web Almanac media chapter put the median largest image on a mobile page at 135 KB, and the 90th percentile at 1002 KB. A wasted desktop clip puts you past the worst tenth of the web before your real hero has loaded. The full Elpida Solutions case study covers how the rest of that build was verified, including the multilingual routing and the production checks.
The same chapter has a number worth sitting with. Only 9.3% of mobile pages use <picture> at all, 42% use srcset, and within the pages that do reach for <picture>, the media attribute appears on 40% of them, down three percentage points from 2022. Art direction is not a crowded field. Doing it properly is still a differentiator, which is an odd thing to say about a fifteen-year-old element.
Video has a trap that pictures do not

A <video> evaluates its <source> list once when it loads and never re-evaluates it when the media condition changes, which <picture> does.
Rotate the phone from portrait to landscape after the page has loaded and the portrait clip stays on screen, stretched or letterboxed into a shape it was not cut for. Resize a desktop window across the breakpoint and nothing swaps. Scott Jehl, who did the work to get this feature restored, documents the limitation plainly and there is an open WHATWG issue asking the spec to make video behave like picture. Part of the difficulty is obvious once stated: swapping a source mid-playback means preserving the time code.
Some history explains why so many developers still believe this does not work at all. The media attribute was pulled from the video spec in 2014 and Chrome and Firefox dropped their implementations. Safari kept it. Both browsers restored support in version 120, so responsive video is usable today with the one-shot caveat. The stakes are not small either: Jehl cites a median video weight of almost 5 MB on mobile pages that use video, up 45% over five years.
The practical rule that falls out: art-direct on the initial load, accept that rotation will not re-cut, and choose a portrait composition that still reads acceptably at landscape phone dimensions. If you cannot accept that, listen for orientationchange, swap the source, and restore currentTime yourself. If your hero is decorative and short, do not bother.
Autoplaying heroes bring a second cost that has nothing to do with shape. A phone that holds several decoded clips at once can have its tab reclaimed by the system, which I wrote up separately in why mobile Safari reloads video-heavy pages.
What do you actually capture, and at what sizes?
Capture for the narrowest container you will ever ship, then crop outward, because you can always remove width and you can never add it back.
These are the widths worth framing against. They cover the overwhelming majority of phones in use, and the landscape row is the one people forget until a client rotates their handset during a review call.
| Target | CSS width | Working hero box | What the frame must protect |
|---|---|---|---|
| Small phone | 320px | 320 × 420 | Subject plus 12% margin on every side |
| Common Android | 360px | 360 × 470 | Same subject, headline baseline clear |
| iPhone standard | 390px | 390 × 500 | Subject, plus room for the overlay block |
| Large phone | 430px | 430 × 560 | Subject and overlay, plus any logo lockup |
| Phone landscape | 844 × 390 | 844 × 300 | Subject survives a shallow band, no vertical detail below the fold |
Shoot or render the portrait asset at 1080×1920 and crop down. Keep the subject inside the middle 76% of the portrait frame so a 12% safe margin survives on both axes at every width in that table. Put the text overlay in a zone you deliberately left quiet, not wherever the layout happens to drop it, and check the contrast against the darkest and lightest pixels that zone can contain at 320 and at 430.
One more constraint belongs in the capture brief rather than the stylesheet. Size the hero box in svh rather than vh or dvh. MDN is direct about why: dynamic viewport units mean content resizes while the user scrolls, which degrades the interface and costs performance as the address bar retracts. A hero that changes height mid-scroll re-crops itself under the reader's thumb.
Reduced motion is a crop decision too
If the visitor has asked for reduced motion, the still you serve them is the hero. Not a paused frame from a clip composed for movement. Pick a frame where the composition resolves on its own, export it as a proper portrait asset, and give it the same safe-area treatment as everything above.
Verify the waterfall, not the mockup
Open the network panel on a real phone profile, load the page cold, and look at what actually arrived. One hero asset should be there. If two are, your media conditions overlap or a hidden element is still fetching. This takes ninety seconds and catches the failure that every visual review misses, because a hidden download looks perfect. Load performance work I have written about elsewhere applies here too, in how to get a Webflow site under one second.
So: pull up your own hero on a phone right now, in portrait, and ask whether the subject is where you framed it. If it is not, the fix starts in the capture brief, not the stylesheet.
