How To Create a Horizontally Scrolling Site

Avatar of Chris Coyier
Chris Coyier on (Updated on )

If web pages were made out of wood, the grain would be running up and down. Vertical is the natural flow of web layout. When page elements reach the right edge of the browser window and go over, the flow defaults to “wrapping” that element down onto the next line. The more content on the page, the taller it gets, not the wider. Why is this? Because it just makes sense. Our eyes are used to reading fairly short lines of text, so if we were to see a paragraph of text in one long straight line, it would be painful to read. Paragraphs need to have line breaks in them to be readable (hence the term “blocks” of text). We sure as heck don’t want to hard-code line breaks into the markup ourselves. Obviously, we don’t have to, the browser does this wrapping for us. Thus the vertical expansion.

This natural flow has lead to conventions in web page layout and even into hardware itself. Notice how many computer mice (mouses?) have a special scroller exclusively for vertical scrolling. But web pages are equipped with both vertical AND horizontal scrollbars, right? If we are responsible with our web layout, we can go “against the grain” and create web pages that use primarily horizontal scrolling and can even expand horizontally as we add more content. Perhaps a slight blow to “usability”, but it sure can be a cool creative touch!

The best way to do it

I’m going to go out on a limb here and say that I think a table is the best layout technique for a horizontally scrolling site.

Update: this is a pretty old article. The core of this was just that with a table you can set things on a row that keeps going and going without line breaking. You could achieve that today with display: flex; on a parent much easier, although the UX of this is pretty questionable.

Before I explain why, let’s look at a couple of other possible techniques:

  • Set a really wide static width. Perhaps the “quick and dirtiest” way to get a horizontal layout started is just to set a really wide static width on the body element itself. Say, 10000px. Go ahead and try it, you’ll surely get a horizontal scrollbar. While this works, it’s a bit inflexible. Web pages are dynamic places and we should be prepared for expandability, not limiting ourselves with static widths. Think about regular vertical scrolling sites. You don’t go around setting static heights on your pages do you?
  • Floats + Whitespace. I spent some time playing with the float property and the white-space property to see if I could find a way to fight browser auto-wrapping, but I didn’t have much luck. Page elements which are floated but do not have a width exhibit a property where they expand to the width of the content inside them. I thought perhaps if I put a bunch of float elements inside of that, it might just keep expanding beyond the width of the browser window. No dice. There is also a white-space: nowrap; property in CSS which I thought might be able to be exploited to fight the auto-wrapping, but it only works for text elements, not blocks or just any old thing you set to inline. Oh well.
  • Use JavaScript to set a width. JavaScript clearly has the ability to manipulate page elements and do calculations on-the-fly. We could use this to create an environment which behaves extensibility. However, it considered bad mo-jo to handle page layout with JavaScript. I agree with this in general, but I do believe you can use JavaScript in this way as long you do so unobtrusively and take care to ensure the page will fall back to a usable layout with JavaScript disabled.

The <table> method

What we need is a page element which can expand horizontally as needed and never “wrap”. A row of table cells fit the bill perfectly here. Table cells will expand to fit whatever content is inside them by their nature, and the will never wrap until a new row is started. Perfect.

Let’s assume we are trying to lay out a series of blog posts one after another horizontally. We would need to use a page structure like this:

<table>
  <tr>
    <td>
       ..  blog post #1
    </td>
    <td>
       ..  blog post #2
    </td>
    <td>
       ..  blog post #3
    </td>
  </tr>
</table>

Yuck, right? It never feels good to use markup like that, not just because it’s a table, but also because of how non-semantic it is. We are using a bunch of tags here which are exclusively for presentation and have nothing to do with content.

Ideally, our page structure would be like this:

<article class="post">
  .. blog post #1 ..
</article>
<article class="post">
  .. blog post #2 ..
</article>
<article class="post">
  .. blog post #3 ..
</article>

Using jQuery, we can easily have the best of both worlds!

Write the markup we want, get the markup we need

We are going to use jQuery to allow us to the markup we want (the div structure) and manipulate it to get the markup we need for horizontally scrolling (the table structure). You should have little alarms going off in your head here about using JavaScript for layout, but rest easy, we will ensure that without JavaScript enabled the layout will be perfectly useable. As an added bonus, the layout will be useable with or without CSS enabled as well, and any combination.

Let’s first think through what we want to happen:

  • Wrap ALL of the posts in a single table tag and single row tag
  • Wrap EACH post in a table cell tag

Now let’s include jQuery on our page in the head section, and write the jQuery we need to get this done.

<script src="js/jquery.js"></script>
<script>
  $(function() {
    $("#page-wrap").wrapInner("<table cellspacing='30'><tr>");
    $(".post").wrap("<td>");
  });
</script>

That should do it! Notice how the cellspacing is added as an inline attribute to the table element. We might normally apply padding to cells with CSS, but we want to make sure that each blog post block is as readable as possible even with CSS turned off. Without this, the blocks would butt right up against each other making them tough to read.

The entire CSS file for this example is very very simple:

* {
  margin: 0; 
  padding: 0; 
}
body { 
  font-size: 62.5%; 
  font-family: 'Lucida Grande', Helvetica, sans-serif;
  background: #121212;
  color: #999; 
  padding: 20px;
}
tr { 
  vertical-align: top;
}
.post { 
  width: 500px; 
}
p { 
  font-size: 1.2em; 
  margin: 0 0 15px 0; 
}
h1 { 
  font-family: Sans-serif; 
  font-size: 4.0em;
  letter-spacing: -1px; 
  color: #ccc; 
}
h2 { 
  font-family: Sans-Serif; 
  font-size: 3.0em;
  letter-spacing: -1px; 
  color: #ccc; 
}

Only a few things worth noting. The static width on the .post div controls the width of each block. The vertical-align property on the table row keeps each of the blocks aligned to the top of their table cells. This defaults to middle, so this is necessary.

The Results

With CSS and JavaScript both on (99% of users), we’ll have a nicely executed horizontally scrolling site. With CSS and JavaScript both off (screen readers), the structure of the individual blog posts rule the page, assuming they are semantically marked up, the page will look great. The only quirk here is if JavaScript is on and CSS is off (RARE), the page looks a little bizarre.

See the Pen
Posts in a Horizontal Row by Table Wrapping
by Chris Coyier (@chriscoyier)
on CodePen.

Other techniques for horizontal scrolling

Literally expanding the width of your page and using scrollbars to navigate it is only one way to achieve the horizontally scrolling effect. Javascript sliders are another route you could take, which simulate the effect. Flash would be another possibility. When it comes to web design, there are always many ways!