CSS Horizontal Scroll: a Step-by-Step Guide
Tags: html, css, webdev
Published: 2022-07-10 08:05:05

Bored with all the vertical scrolls in websites? Today, let's build a simple horizontal scrolling page using CSS.

- [CSS Horizontal Scroll: a Step-by-Step Guide](#css-horizontal-scroll-a-step-by-step-guide)
  - [Overview](#overview)
  - [HTML](#html)
  - [CSS](#css)
- [Notes](#notes)

## Overview

The key concept is **to rotate the container 90 degrees and then rotate its child elements 90 degrees backwards to counter the container's rotation**.

![key concept is to rotate the container 90 degrees and then rotate its child elements 90 degrees backwards](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/auwbt1ckdjkhoi544ldk.png)

Here is a [live demo](https://mrjwei.github.io/css-horizontal-scroll/) of what we are going to build.

You can find the complete code [here](https://github.com/mrjwei/css-horizontal-scroll).

## HTML

With that in mind, we can build it out really fast. Let's begin with HTML.

```html
<div class="container">
  <div>
    <img src="./images/image1.jpeg" alt="" />
    <p>image 1</p>
  </div>
  <div>
    <img src="./images/image2.jpeg" alt="" />
    <p>image 2</p>
  </div>
  <div>
    <img src="./images/image3.jpeg" alt="" />
    <p>image 3</p>
  </div>
  <div>
    <img src="./images/image4.jpeg" alt="" />
    <p>image 4</p>
  </div>
  <div>
    <img src="./images/image5.jpeg" alt="" />
    <p>image 5</p>
  </div>
  <div>
    <img src="./images/image6.jpeg" alt="" />
    <p>image 6</p>
  </div>
  <div>
    <img src="./images/image7.jpeg" alt="" />
    <p>image 7</p>
  </div>
  <div>
    <img src="./images/image8.jpeg" alt="" />
    <p>image 8</p>
  </div>
</div>
```

## CSS

CSS code is a bit more complicated but the concept has been covered above. We just need to code carefully and incremently.

Let's start with the big picture and give the page a structure.

```css
.container {
  /* 
  Width and height will swap after rotation. 
  To make the container as wide as the screen after rotation,
  we need to set its initial height to 100vw.
  */
  width: 500px;
  height: 100vw;
}
.container div {
  width: 100%;
  height: 500px;
}
img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
```

Now, the page should look like this. It's still far from what we want.


![page after css step 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9au5v9iunc7hqsvrault.png)

Let's rotate the container 90 degrees and its children 90 degrees backwards.

```css
.container {
  ...
  /*
  translateY(-500px) makes the container align
  to the left of the screen.
  */
  transform: rotate(-90deg) translateY(-500px);
  transform-origin: top right;
}
.container div {
  ...
  transform: rotate(90deg);
}
```

Now it's closer to what we expect but it cannot scroll horizontally yet.


![page after css step 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1zltkj5gvom4b3lisn28.png)

To make it horizontally scrollable is as easy as adding two lines of code.

```css
.container {
  ...
  overflow-x: hidden;
  overflow-y: auto;
}
```

We are almost done except some clean-ups and polishing. Let's add the following code.

```css
body {
  margin: 0;
}
/*
To hide the scroll bar.
*/
::-webkit-scrollbar {
  display: none;
}
* {
  -ms-overflow-style: none;
  scrollbar-width: none;
}
img {
  ...
}
.container div {
  ...
  position: relative;
  margin: 10px 0;
}
.container div:first-child {
  margin: 0;
}
p {
  padding: 10px;
  background: white;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
```

The final page should look like this and scroll horizontally.


![final page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6lh4kokvrt0u98a1sajw.gif)

Here is the complete CSS code.

```css
body {
  margin: 0;
}
::-webkit-scrollbar {
  display: none;
}
* {
  -ms-overflow-style: none;
  scrollbar-width: none;
}
img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.container {
  width: 500px;
  height: 100vw;
  transform: rotate(-90deg) translateY(-500px);
  transform-origin: top right;
  overflow-x: hidden;
  overflow-y: auto;
}
.container div {
  position: relative;
  width: 100%;
  height: 500px;
  transform: rotate(90deg);
  margin: 10px 0;
}
.container div:first-child {
  margin: 0;
}
p {
  padding: 10px;
  background: white;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
```

## Notes

- In this example, we used **squared** child elements (500 \* 500 images) and there is a reason for this. If the width:height ratio was not 1:1, we would have to work out how much to offset the child elements after rotation so that they do not overlap each other.
- For such cases and more advanced functionalities or effects, you would want to write some javacript code.