Full Browser Width Bars

Chris Coyier //

Updated on December 17, 2014 by Parker Bennett.

As the line length of text content gets longer, it can be harder to read. So it's common practice to limit the width of content as the viewport widens. Often, this is accomplished by giving the content a max-width and centering it, either within a wrapping element, or section by section.

But what if we want an element to extend visually to cover the full width of the viewport, say, a background color for a header or individual headings?

One approach is to use an inner wrapper for the content we want width-constrained, but leave the outer element at 100% width. However, this adds extra markup and it's (arguably, GASP) non-semantic!

<header>
  <div class="wrap">
    <h2>Header</h2>
  </div>
</header>

<h3 class="full-width">
  <div class="wrap">Heading</div>
</h3>
<div class="wrap">
  <p>... text ... </p>
</div>
header, .full-width {
  width: 100%;
  background: #ccc;
}
.wrap {
  width: 80%;
  max-width: 24em;
  margin: 0 auto;
  padding: 0.25em 0.625em;
}

It would be better to wrap the content semantically (e.g., main or section) and have the headings break out visually as needed. Here are a few ways we can:

Using negative margin

A simple approach (from Timothy Mackey) uses negative margins and padding to extend the background in both directions. To avoid triggering horizontal scrolling, we need to set overflow-x:hidden on both the html and body elements.

html, body {
  overflow-x: hidden;
}
.full-width-bar {
  margin: 0 -9999rem;
  /* add back negative margin value */
  padding: 0.25rem 9999rem;
  background: rgba(0, 0, 0, 0.5);
}

See the Pen Full Width Bars Using Negative Margins by Chris Coyier (@chriscoyier) on CodePen.

Want to make the full-width bar a different color than the heading background? One way is to use left and right borders. But it turns out super-wide borders have some issues. For borders over 960px, you need to make them exactly 9600px or 10240px (or equivalent ems) to avoid a bug in Chrome. Also, you need to use solid colors, since RGBa values display a tiny gap in Safari. This is because of rounding errors when the containing element is centered.

html, body {
  overflow-x: hidden;
}

.full-width-borders {
  /* also subtract section padding (1.5rem) */
  margin: 0 -601.5rem;
  /* add back section padding (1.5rem) */
  padding: 0.25rem 1.5rem;
  background: red;
  /* border has to be solid, not RGBa */
  /* 9600px or equiv (600rem = 9600/16) */
  border-left: 600rem solid maroon;
  border-right: 600rem solid maroon;
}

See the Pen Full Width Bars Using Borders by Parker Bennett (@parkerbennett) on CodePen.

Given the fussiness of using borders, let's look at an alternative:

Using pseudo elements

By adding a :before pseudo-element to the heading, you can make the background behind it distinct from the full-width bar, using absolute positioning and a negative z-index. This also lets us use RGBa for the full-width bar.

.full-width-tinted {
  position: relative; /* for child pseudo-element */
  z-index: 0;
  margin: 0 -600rem;
  /* add back negative margin value */
  padding: 0.25rem 600rem;
  background: #666;
  background: rgba(0, 0, 0, 0.25);
}

.full-width-tinted:before {
  content: "";
  position: absolute;
  z-index: -1; /* behind parent */
  top: 0;
  bottom: 0;
  /* subtract h2 padding (1.5rem) */
  left: 598.5rem;
  right: 598.5rem;
  background: green;
}

See the Pen Full Width Bars Using Negative Margins by Chris Coyier (@chriscoyier) on CodePen.

You need to be a little careful with negative z-index, since it tends to work only in fairly simple situations without many nested elements with their own backgrounds.

If you want even more flexibility, you can use two pseudo-elements, :before and :after, to extend the header background both left and right. This way the background could include different color, widths, or heights, extend in only one direction, fade with a gradient, etc.

.full-width {
  position: relative; /* for the child pseudo-elements */
  /* negative offset = section padding */
  margin: 0 -30px;
  /* add back section padding value */
  padding: 0.25rem 30px;
  background: #333;
}
.full-width:before, .full-width:after {
  content: "";
  position: absolute;
  /* fill vertically */
  top: 0;
  bottom: 0;
  width: 9600px;
  right: 100%;
  background: green;
}
.full-width:after { 
  width: 320px;
  left: 100%;
  /* you're free to do something totally different here */
  background: green;
}

See the Pen Full Width Bars Using Pseudo-Elements by Chris Coyier (@chriscoyier) on CodePen.

Using box-shadow

A clever way to not trigger horizontal scrolling is to use box-shadow to generate the background extensions (at least on the right). Andreas created a demo of this:

See the Pen Full Width Browser Bars with box-shadow by Andreas (@receter) on CodePen.

Unfortunately, there are issues with this. Charles Stuart pointed out a bug in Internet Explorer 11 (v11.0.9600.17501) that makes using box-shadow unreliable. It appears IE is using sub-pixel antialiasing on the box-shadow even when blur is set to 0.

Using viewport units

Lisa suggested a way to not trigger horizontal scrolling by using a combination of vw and calc(), which now have pretty solid browser support. It could be useful in the right circumstance (but doesn't yet factor in things like padding or min-width).

See the Pen Full width bars by Chris Coyier (@chriscoyier) on CodePen.