Breaking Out With Viewport Units and Calc

Breaking Out With Viewport Units and Calc

At 4/19/2024

While iterating on a new article layout for the impending Cloud Four redesign, I encountered an old CSS layout problem.

For long-form content, it’s usually a good idea to limit line lengths for readability. The most straightforward way to do that is to wrap the post content in a containing element:

.u-containProse {
  max-width: 40em;
  margin-left: auto;
  margin-right: auto;
}
Code language: CSS (css)
<div class="u-containProse">
  <p>...</p>
  <p>...</p>
</div>
Code language: HTML, XML (xml)

But what if we want some content to extend beyond the boundaries of our container? Certain images might have greater impact if they fill the viewport:

Mockup of container with full-width element

In the past, I’ve solved this problem by wrapping everything but full-width imagery:

<div class="u-containProse">
  <p>...</p>
</div>
<img src="..." alt="...">
<div class="u-containProse">
  <p>...</p>
</div>
Code language: HTML, XML (xml)

But adding those containers to every post gets tedious very quickly. It can also be difficult to enforce within a content management system.

I’ve also tried capping the width of specific descendent elements (paragraphs, lists, etc.):

.u-containProse p,
.u-containProse ul,
.u-containProse ol,
.u-containProse blockquote/*, etc. */ {
  max-width: 40em;
  margin-left: auto;
  margin-right: auto;
}
Code language: CSS (css)

Aside from that selector giving me nightmares, this technique might also cause width, margin or even float overrides to behave unexpectedly within article content. Plus, it won’t solve the problem at all if your content management system likes to wrap lone images in paragraphs.

The problem with both solutions is that they complicate the most common elements (paragraphs and other flow content) instead of the outliers (full-width imagery). I wondered if we could change that.

To release our child element from its container, we need to know how much space there is between the container edge and the viewport edge… half the viewport width, minus half the container width. We can determine this value using the calc() function, viewport units and good ol’ percentages (for the container width):

.u-release {
  margin-left: calc(-50vw + 50%);
  margin-right: calc(-50vw + 50%);
}
Code language: CSS (css)

Voilà! Any element with this class applied will meet the viewport edge, regardless of container size. Here it is in action:

See the Pen Full-width element in fixed-width container example by Tyler Sticka (@tylersticka) on CodePen.

Browsers like Opera Mini that don’t support calc() or viewport units will simply ignore them.

When I found this solution, I was thrilled. It seemed so clever, straightforward, predictable and concise compared to my previous attempts. It was in the throes of patting myself on the back that I first saw it…

An unexpected scrollbar:

On any page with this utility class in use, a visible vertical scrollbar would always be accompanied by an obnoxious horizontal scrollbar. Shorter pages didn’t suffer from this problem, and browsers without visible scrollbars (iOS Safari, Android Chrome) seemed immune as well. Why??

I found my answer buried deep in the spec (emphasis mine):

The viewport-percentage lengths are relative to the size of the initial containing block. When the height or width of the initial containing block is changed, they are scaled accordingly. However, when the value of overflow on the root element is auto, any scroll bars are assumed not to exist. Note that the initial containing block’s size is affected by the presence of scrollbars on the viewport.

Translation: Viewport units don’t take scrollbar dimensions into account unless you explicitly set overflow values to scroll. But even that doesn’t work in Chrome or Safari (open bugs here and here).

I reacted to this information with characteristic poise:

Not reacting with poise at all

Luckily, a “fix” was relatively straightforward:

html,
body {
  overflow-x: hidden;
}
Code language: CSS (css)

It’s just a shame that it’s even necessary.

Copyrights

We respect the property rights of others and are always careful not to infringe on their rights, so authors and publishing houses have the right to demand that an article or book download link be removed from the site. If you find an article or book of yours and do not agree to the posting of a download link, or you have a suggestion or complaint, write to us through the Contact Us, or by email at: support@freewsad.com.

More About us