A media object is the familiar pattern where an image, icon, avatar, or thumbnail sits beside text. It looks simple until real content arrives. The title wraps to three lines, the metadata has two badges, the image is missing, the action label gets longer, and the whole row starts pushing wider than its container.
The durable version gives each part a clear responsibility. The media gets a stable frame. The body gets permission to shrink. Text wraps where it can. Actions stay connected to the content instead of floating into a different row by accident.
Start with a stable frame
.media-object {
display: grid;
grid-template-columns: 7rem minmax(0, 1fr);
gap: 1rem;
align-items: start;
}
.media-object__frame {
aspect-ratio: 4 / 3;
overflow: hidden;
background: var(--media-placeholder, #eef2eb);
}
.media-object__frame img {
inline-size: 100%;
block-size: 100%;
object-fit: cover;
}
The frame owns the layout size. The image owns the visual crop. That separation prevents late-loading images from resizing the row and makes missing media easier to handle. If the content is a product image or diagram where cropping would remove meaning, switch to object-fit: contain and use a background that makes the empty space intentional.
Avoid letting the image’s intrinsic size define the pattern. A huge source image should not force a card wider than the grid. A tiny avatar should not collapse the row. The component needs a frame because the layout needs a predictable media region before the media file is considered.
Let the body shrink
The text column should use minmax(0, 1fr) in Grid or min-inline-size: 0 in Flexbox. Without that, a long heading, unbroken URL, or code-like token can make the body refuse to shrink and create horizontal overflow.
.media-object__body {
display: grid;
gap: 0.5rem;
min-inline-size: 0;
}
.media-object__title {
overflow-wrap: anywhere;
}
Use aggressive wrapping only where it is acceptable. A title or URL may be safe to break. A short product code may need a local scroll or a different presentation. The goal is not to break every word; it is to decide which content should protect the page width.
Stack when the relationship changes
At narrow widths, the image may stop being a side object and become a header image. That change should follow the component’s available space, not only the viewport.
.media-slot {
container-type: inline-size;
}
@container (max-width: 26rem) {
.media-object {
grid-template-columns: 1fr;
}
}
This keeps the component reusable. The same media object can sit in a sidebar, article rail, or full-width listing and choose the layout that matches its actual slot.
Keep actions attached
Actions belong with the media object’s body, not in a distant grid row that only lines up for ideal content. If there are several actions, let them wrap.
.media-object__actions {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-block-start: 0.25rem;
}
Do not hide actions until hover unless the same actions remain reachable by keyboard and touch. A media object often appears in lists, search results, and resource cards where users scan quickly. The primary link should be visible and the hit target should be clear.
Test with bad content
Before reusing the pattern, test long titles, missing images, tall images, no description, several metadata badges, and a narrow parent. The layout should not depend on every item having the same amount of copy. If equal heights are required for comparison, make that a separate grid decision rather than forcing the media object to clip or stretch its content.
The media object is content-safe when the row survives variation without a special breakpoint for every case. A stable frame, shrinkable body, local wrapping, and explicit action layout are usually enough.
Choose semantics before layout
A media object can be an article preview, a list item, a search result, a comment, or a product summary. Use the element that matches that role. A list of search results should usually be a list. An article preview can be an article. A comment may need author, time, and body text grouped in a way that makes sense without the side-by-side layout.
Do not make the whole object clickable by wrapping unrelated controls in a single link. If the object has one destination, a heading link is often enough. If it has secondary actions, keep those actions as real buttons or links with their own labels. The CSS can make the row feel unified without turning the interaction model into one oversized target.
Keep placeholders honest
Missing media should not create a broken-looking hole. Use a neutral placeholder only when the absence of media is expected. If media is required and missing because of an error, expose that state in a way the editorial or product team can fix. A decorative placeholder can hide data quality problems when every card appears visually complete.