Extending the content area using calc(...)

Most website layouts use a .content1 class with a fixed max-width to keep text content readable on larger screens. The area grows from mobile viewport sizes up to some maximum, usually around 768px. While this is perfect for text content, other elements, like images, benefit from more width.

One approach to solving this is to wrap only elements that should stay within the max-width with .content.

HTML
Using max-width on individual elements
<main>
  <h1 class="content">About my best friend</h1>
  <img src="..." alt="My cat Dorothy" />
  <p class="content">
    My cat Dorothy has been by my side for well over 13 years, ...
  </p>
</main>

However, using .content on individual paragraphs has its limitations. If .content defines a patterned background, it won't work anymore. Even if it's only a background color, you must be careful and use padding instead of margin, as you'll get gaps otherwise.

I also find it unlikely that you'll want to manually annotate all your content with .content, which might be impossible anyhow if a CMS serves it. You can't simply apply the style to all p elements either, since others, like figure or even regular divs, might also be top-level content.

Using calc(...)

A better way that semantically aligns with extending the content is applying .content to the whole block2 and using a negative margin-inline3 to pull the images or figures outward. Intuitively, you'd apply some fixed negative margin, but this will increase the width to over 100% of the viewport width on viewports smaller than 768px + 2* <your negative margin>, making the page scroll horizontally and clipping your image.

The width of the space around your .content is 100% of the viewport width minus the current width of your .content element. Therefore, the negative margin you need to apply is exactly half of that. Fortunately, calc(...) is widely supported in browsers now, so all you need is margin-inline: calc((100vw - 100%) / -2). This will extend the element all the way to the edges without clipping or scrolling.

viewport width:
content:
calc(( - ) / 2 * -1) =

This is an interactive demonstration of the involved measurements. My site has a minimum margin, so bear that slight behavioral difference in mind. The demo displays rounded values; the browser uses floats.

HTML
Using a negative margin with calc
<main class="content">
  <h1>About my best friend</h1>
  <img class="extend-full" src="..." alt="My cat Dorothy" />
  <p>My cat Dorothy has been by my side for well over 13 years, ...</p>
</main>
CSS
.extend-full {
  margin-inline: calc((100vw - 100%) / 2 * -1);
}

Most of the content you'll want to expand shouldn't stretch to the entire width of the page, though, because the image to text width ratio can look out of place on big or ultra-wide displays.

The min(...) function gives you the smaller of two values. Limiting the extent to 32px extent looks like this:

CSS
.extend-a-bit {
  margin-inline: calc(
    -1 *
    min(
      (100vw - 100%) / 2,
      32px
    )
  );
}

Finished result

If you want to clean up a bit or need multiple extension widths, I recommend using CSS variables to set the maximum extent. Using font-size relative units so margins scale appropriately is also a good idea.

CSS
.extend {
  margin-inline: calc(
    -1 *
    min(
      (100vw - 100%) / 2,
      var(--maximum-extent, 0)
    )
  );
}

.extend-full {
  --maximum-extent: Infinity;
}

.extend-a-bit {
  --maximum-extent: 8em;
}

Bonus tip: Centered content and minimum margins

Before display: flex was a thing, web developers used margin: 0 auto to center content. Using auto has the drawback that content will touch the edges whenever the max-width exceeds the current viewport width. You can apply padding-inline or set fixed widths based on @media (max-width: ...). Both have their own drawbacks4, and I prefer to use display: flex. Wrapping your .content in a centering flex container will honor the minimum margin.

HTML
<div class="content-wrapper">
  <main class="content">
    <!-- ... -->
  </main>
</div>
CSS
.content-wrapper {
  display: flex;
  justify-content: center;
}

.content {
  max-width: 768px;
  margin-block: 8px;
}

This only works with a flex container. Using margin: 0 auto on .content-wrapper won't collapse the margins and thus have the same effect as padding-inline on .content.


Footnotes

  1. A typical .content definition might look like this:

    CSS
    blog.CSS
    .content {
      position: relative;
      max-width: 768px;
      margin: 0 auto;
    }
    
  2. Make sure your .content class is set to position: relative.

  3. Please review whether writing-mode-aware properties (like margin-inline) are appropriate for your page and use margin-left and margin-right otherwise.

  4. It's generally less flexible, and padding must be compensated. For example, with modern max-width settings, like max-width: 65ch, used by .prose from Tailwind. You'd have to use calc(...) to determine how much bigger your container needs to be.