Many times, when designing a website, we need to stack a series of cards or containers horizontally and allow the user to scroll them from left to right. Although it is not limited to containers: you might want your entire website to have horizontal navigation, known as a horizontal site.
The web is, by nature, vertical. However, there are many real-world scenarios where stacking content horizontally and enabling side-scrolling makes complete sense: image galleries, product lists, cards, pricing plans, or even entire websites with horizontal navigation.
Horizontal scrolling with CSS is something I have implemented several times in real projects. Although it often seems trivial, the reality is that a single CSS property is not enough for it to work properly, be usable, and not break on different devices or screen sizes.
In this guide, I will show you how to properly create a horizontal scroll in CSS, when to use each technique, which errors to avoid, and how to enhance it with a touch of JavaScript when you really need it.
What is horizontal scrolling and when to use it
Horizontal scrolling is a technique that allows the user to scroll from left to right within a container, instead of the classic vertical scroll. It seems simple, but applied correctly, it can completely transform the user experience in certain contexts.
Horizontal scroll vs. vertical scroll
- Vertical scroll: ideal for long reading and traditional navigation.
- Horizontal scroll: perfect for repetitive visual elements, cards, or content consumed "in blocks."
It is not about replacing vertical scrolling, but about using it strategically where it adds value.
Real-world cases where using it makes sense
Some scenarios where I usually apply it:
- Card lists
- Carousels without JS dependencies
- Image galleries
- Mobile-first sections
- Pricing plans or feature comparisons
How to create horizontal scrolling with CSS (classic method)
This is the simplest, most stable, and compatible technique. I have used it many times because it works without JavaScript and without weird hacks. Even though it seems obvious, forgetting one of the key properties is one of the most common mistakes.
Let's see how to create a div with horizontal scroll like the one in the following example:

It is actually quite simple and you don't need JavaScript or any magic plugin; there are just a few steps to keep in mind. Mind you, it is not as simple as defining a single CSS rule either: you have to combine several properties correctly. The steps are:
- Define the height (
height) of the parent container. - Indicate that we do not want vertical scrolling.
- Enable horizontal scrolling.
Key properties: overflow-x and overflow-y
For the last two steps, a couple of CSS rules with their corresponding values are enough:
overflow-x: auto;
overflow-y: hidden;overflow-x: autoenables horizontal scroll only when content overflows the container.overflow-y: hiddenprevents an unwanted vertical scrollbar from appearing.
The value auto is preferable to scroll because it only shows the scrollbar when really necessary; with scroll the bar always appears, even if the content fits. If you configure the CSS properly, overflow-y: hidden can end up being optional, though I usually add it as a precaution.
The parent container: size, height, and white-space
The following CSS corresponds to the parent container, which is responsible for performing the horizontal movement. Here we define its size and width all at once:
Parent container properties
width: auto;
height: 50px;
padding: 10px;
white-space: nowrap;Basically, we set the container size and internal padding. The white-space property specifies how whitespace inside the container is handled; with the value nowrap, we indicate that there should be no line breaks, meaning all content is displayed in a single row. In my experience, this is the most important property of classic horizontal scrolling.
In addition, we define a fixed height of 50px for the container, while leaving the width as auto so it can grow as much as the content requires.
Here is the summary of the key takeaways:
white-space: nowrapprevents line breaks and forces content into a single row.- Width adapts to the content thanks to
width: auto. - Fixed height prevents strange overflow on the vertical axis.
Child elements and why display: inline-block is important
Now we define the CSS for the container's children. The concept is simple: we are creating small boxes that must remain on the same line:
.horizontal-scroll-contenedor div {
width: 100px;
height: 50px;
margin-right: 10px;
display: inline-block;
}Important points:
display: inline-blockkeeps all elements aligned in a single horizontal row, instead of stacking vertically asdisplay: blockwould do.- The size of the children must not exceed the height of the parent; if it does, the content will be clipped.
margin-rightcreates the visual separation between each element.
Practical example of horizontal scroll with divs in HTML and CSS
The most important thing is that children have the same size or smaller than the parent, and that they use display: inline-block to stay on the same line. The rest of the code is contextual and you can check it out in the download links. This is how the HTML would look:
<div class="horizontal-scroll-contenedor">
<div>Container 1</div>
<div>Container 2</div>
<div>Container 3</div>
<div>Container 4</div>
<div>Container 5</div>
<div>Container 6</div>
<div>Container 7</div>
<div>Container 8</div>
<div>Container 9</div>
<div>Container 10</div>
<div>Container 11</div>
<div>Container 12</div>
<div>Container 13</div>
<div>Container 14</div>
<div>Container 15</div>
<div>Container 16</div>
<div>Container 17</div>
<div>Container 18</div>
<div>Container 19</div>
<div>Container 20</div>
</div>Complete CSS based on what was explained:
.horizontal-scroll-contenedor {
width: auto;
height: 50px;
padding: 10px;
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
}
.horizontal-scroll-contenedor div {
width: 100px;
height: 50px;
margin-right: 10px;
display: inline-block;
}And you can see the result below:
This pattern is simple, predictable, and easy to maintain, which is why I keep using it when I don't need advanced effects.
Horizontal scroll with Flexbox (the modern option)
Nowadays, if I have to choose, Flexbox is usually my first option. It is cleaner, more semantic, and eliminates the need to use white-space and inline-block, which are properties conceptually not intended for layout design.
Why Flexbox simplifies horizontal scrolling
With Flexbox, the code becomes much more readable. The container only needs three properties:
.flex-container {
display: flex;
flex-wrap: nowrap;
overflow-x: auto;
}And for the child elements:
.flex-item {
flex: 0 0 auto;
}flex-wrap: nowrapprevents elements from breaking into a new line, equivalent towhite-space: nowrapin the classic method.flex: 0 0 automaintains the natural size of each element without Flexbox stretching or shrinking it. The three values are:flex-grow: 0(do not grow),flex-shrink: 0(do not shrink), andflex-basis: auto(respect declared size).
When to choose Flexbox over inline-block
- I use Flexbox when:
- The layout is modern and already uses Flexbox elsewhere.
- I need vertical alignment of the elements.
- I want cleaner and more readable code.
- I use
inline-blockwhen:- I am looking for maximum compatibility with legacy browsers.
- It is a small or very simple project.
- I do not want to introduce Flexbox if the rest of the code does not use it.
Scroll snapping: the magnet effect when scrolling
Here we enter a more advanced level. Scroll snapping is a CSS technique that causes the scroll to automatically "latch" onto the nearest element once scrolling finishes, as if it had a magnet. The result feels polished and professional, especially on mobile.
scroll-snap-type and scroll-snap-align
These two properties create the famous "magnet" effect:
.slider {
display: flex;
overflow-x: scroll;
scroll-snap-type: x proximity;
}
.card {
scroll-snap-align: center;
}scroll-snap-type: x proximityactivates snap on the horizontal axis with a certain tolerance; you can changeproximitytomandatoryif you want snapping to always be mandatory.scroll-snap-align: centeraligns each element to the center of the container when snapping. Other possible values arestartandend.
This is ideal for:
- Mobile-first experiences
- Touch carousels
- "Plans" or "Features" sections
I have used it quite a bit in responsive projects because it greatly improves the mobile experience without needing JavaScript.
Common mistakes when implementing horizontal scroll
- The scroll does not appear
- Missing
overflow-x: autooroverflow-x: scroll. - The content does not actually overflow the container width.
- The container width has a fixed value that prevents overflow.
- Missing
- Elements break into multiple lines
- Missing
white-space: nowrap(classic method). - Missing
flex-wrap: nowrap(Flexbox method).
- Missing
- Height and overflow issues
- Container height poorly defined or undefined.
- Child elements taller than the parent, creating unwanted vertical scroll.
- These mistakes are more common than they seem; I have come across them more than once in projects of various sizes.
Is JavaScript needed for horizontal scrolling?
In most cases: no. Pure CSS is:
- Faster (no JavaScript overhead).
- Simpler to maintain.
- More accessible for screen readers and assistive technologies.
- More maintainable long term.
JavaScript only makes sense when you need extra functionality: arrow navigation buttons, autoplay, programmatic scrolling, or more complex animations.
Frequently asked questions about horizontal scrolling with CSS
- Can horizontal scroll be done with CSS alone?
- Yes, and in most cases it is the best option. You don't need any external library.
- Flexbox or
inline-block?- Flexbox is more modern and clean;
inline-blockremains valid for simple cases.
- Flexbox is more modern and clean;
- Does it work on mobile?
- Yes, especially well with touch gestures. If you add
scroll-snap, the experience improves even further.
- Yes, especially well with touch gestures. If you add
- Does it affect SEO?
- No, as long as content is accessible and visible to crawlers. Google seamlessly indexes content inside a
divwith horizontal scroll.
- No, as long as content is accessible and visible to crawlers. Google seamlessly indexes content inside a
- How do I hide the horizontal scrollbar with CSS?
- You can visually hide it using the
::-webkit-scrollbarpseudo-class withdisplay: none, although this is not standard across all browsers:
- You can visually hide it using the
.horizontal-scroll-contenedor::-webkit-scrollbar {
display: none;
}
/* For Firefox */
.horizontal-scroll-contenedor {
scrollbar-width: none;
}Extra: automatic scrolling with JavaScript using scrollLeft
Although pure CSS is more than enough for most cases, JavaScript opens the door to more dynamic capabilities: arrow navigation buttons, autoplay, or code-controlled animations. Let's see how to do it using the scrollLeft property and the scrollTo() method.
The scrollLeft property allows us to read or set the number of pixels a container is shifted horizontally. To move the scroll by 200 pixels all at once:
// Select the container
const contenedor = document.querySelector(".horizontal-scroll-contenedor");
// Assign the scroll value
contenedor.scrollLeft = 200;In modern JavaScript, you can use the scrollTo() method with an options object so the movement is a smooth glide instead of an abrupt jump:
const contenedor = document.querySelector(".horizontal-scroll-contenedor");
contenedor.scrollTo({
left: 200,
behavior: 'smooth' // This makes the scroll animated
});If you want to implement arrow navigation buttons (next/previous), the basic logic is to add or subtract a value from the container's current scrollLeft:
const contenedor = document.querySelector(".horizontal-scroll-contenedor");
const btnSiguiente = document.querySelector("#btn-siguiente");
const btnAnterior = document.querySelector("#btn-anterior");
btnSiguiente.addEventListener("click", () => {
contenedor.scrollBy({ left: 200, behavior: "smooth" });
});
btnAnterior.addEventListener("click", () => {
contenedor.scrollBy({ left: -200, behavior: "smooth" });
});The scrollBy() method scrolls relative to the current position, which makes it ideal for "next" and "previous" type buttons without needing to calculate absolute positions.
Conclusion
Horizontal scrolling with CSS is not only possible, but recommended when done properly. You don't need magic libraries or heavy JavaScript; just an understanding of how overflow, display, and the browser layout model work.
After testing several solutions in real projects, my recommendation is clear:
- Start simple with
overflow-x: autoandwhite-space: nowrap. - Use Flexbox if you can; the code stays much cleaner.
- Add
scroll-snaponly when it adds real value to the user experience. - Avoid unnecessary hacks and resort to JavaScript only for features CSS cannot cover.