Getting Out of the Fixed Container

Most of today's websites use a wrapping container element on their pages – for good reason: it’s handy to have an element that surrounds the content, allowing it to shrink and expand to given breakpoints. But our beloved container can sometimes be a prison (and not even a golden one) when we want a full-screen element in our boxed layout. So the question becomes, how can we solve this before there is a prison break?


Out of the wrong path

If we’re working on an almost static website, we could just wrap everything except the full-width element; not a handy solution since we give away the benefits of using a container. Additionally, this is hard to apply in the strict enforced environment of a CMS where the layout is fixed and wrapped in a fixed container by default.

When trying to find a solution, one early approach could be to use negative margins that equal the positive margin on each side of the container. So if we have a container that takes 80% of the viewport, we can assume that the margins are 10%, and we may be tempted to give our full-width box a -10% margin on each side. The result clearly shows us that we failed, but why?


A common misconception

An element’s margins are calculated based on the width of its parent, so the 10% margin of the container is 1680px * 10% = 168px (in this case the resolution is 1680px) but if we set the same margin on the full-width box it will be (1680px * 80%) * 10% = 134,4px, and this is where our solution fails.

To calculate the right margin, we must use the ratio between the container and its margin, then we divide the viewport (100%) by the calculated ratio. In our case, it’s 80% / 10% = 8, and then 100% / 8 = 12,5% – that’s what our negative margin ought to be.

Copy
#container {
  width: 80%;
  margin: auto 10%;
}
.box-fullWidth { 
  margin-left: -12.5%; 
  margin-right: -12.5%; 
}

With a container width of 60% we would have: 60% / 20% = 3 and 100% / 3 = 33.33%:

Copy
#container {
  width: 60%;
  margin: auto 20%;
}
.box-fullWidth { 
  margin-left: -33.33%; 
  margin-right: -33.33%; 
}

So, problem solved? Sorry to say, but this solution only works if your container has a fixed width expressed as a percentage; the typical CMS container is something like: max-width: 1170px, which doesn’t let you calculate the margins.


A more flexible solution

So we need a more flexible solution that can be applied to the containers typically used in common CMSs, and we actually have it, thanks to CSS3 and the new Viewport Units. For someone who hasn’t ever heard of Viewport Units, they are powerful and nicely supported CSS3 units that refer to the width (vw) or the height (vh) of the viewport which is much more handy than percentages that refer to the element’s parent instead.

Back to our problem, the way to solve it is to push the edges of our full-width element towards the edge of the viewport, by means of a negative margin that equals the one we have between the element and the viewport, and with the help of Viewport Width (vh) and calc() we can reach our goal with ease:

Copy
.box-fullWidth { 
  margin-left: calc(-50vw + 50%); 
  margin-right: calc(-50vw + 50%);
} 

First, we move our box out of the page by half of the viewport (100vw = 100% of the viewport width), and then we push it back again by half of its width.


One last issue, with a reasonable solution

Unfortunately, there’s an issue with this solution that pops up unexpectedly in case the content of our box triggers a vertical scrollbar; with much dismay, we could see a horizontal scrollbar appearing as well. The reason for this is that the specification for the Viewport Units states that if the root element has overflow: auto (which is the default value) the scrollbars aren’t taken into account when computing the viewport width. So, has all of this struggle been in vain? No, there’s a pretty much acceptable solution for that: setting overflow-x to auto on the root level will prevent that unwanted behavior.

Copy
html,
body { overflow-x: hidden; }

Since the support for Viewport Units is overall good (starting from IE9), we can safely employ this solution; using overflow:hidden so it should not normally affect our layout’s behavior. Just note that if you are using jQuery’s scrollTop() you need to trigger it on document instead of on body or html.

Finally we can use CSS3 in its full glory: it seems obvious today but the time when you had to overload the website with hacks, fallback and polyfills was just yesterday. Lots of new properties are now at our disposal and, not only they’re changing the way we conceive layouts, but they help a lot in solving everyday CSS struggles. 

More great blog posts from Alessandro Lo Verde