In this example, we demonstrate how to create scroll buttons on a CSS carousel.
HTML
We have a basic HTML <ul> list with several <li> list items.
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 7</li>
<li>Item 8</li>
</ul>
CSS
Styling the carousel
We convert our <ul> into a carousel by setting the display to flex, creating a single, non-wrapping row of <li> elements. The overflow-x property is set to auto, meaning if the items overflow their container on the x-axis, the content will scroll horizontally. We then convert the <ul> into a scroll-snap container, ensuring that items always snap into place when the container is scrolled with a scroll-snap-type value of mandatory.
ul {
display: flex;
gap: 4vw;
padding-left: 0;
overflow-x: auto;
overscroll-behavior-x: contain;
scroll-snap-type: x mandatory;
}
Next, we style the <li> elements, using the flex property to make them 100% of the width of the container. The scroll-snap-align value of start causes the left-hand side of the left-most visible item to snap to the left edge of the container when the content is scrolled.
li {
list-style-type: none;
background-color: #eee;
flex: 0 0 100%;
height: 100px;
padding-top: 20px;
scroll-snap-align: start;
text-align: center;
}
First, all scroll buttons are targeted with some rudimentary styles, as well as styling based on different states. It is important to set :focus styles for keyboard users. Also, as scroll buttons are automatically set to disabled when no more scrolling can occur in that direction, we use the :disabled pseudo-class to target this state.
ul::scroll-button(*) {
border: 0;
font-size: 2rem;
background: none;
color: rgb(0 0 0 / 0.7);
cursor: pointer;
}
ul::scroll-button(*):hover,
ul::scroll-button(*):focus {
color: rgb(0 0 0 / 1);
}
ul::scroll-button(*):active {
translate: 1px 1px;
}
ul::scroll-button(*):disabled {
color: rgb(0 0 0 / 0.2);
cursor: unset;
}
Note: We also set a cursor value of pointer on the scroll buttons to make it more obvious that they can be interacted with (an improvement for both general UX and cognitive accessibility), unsetting it when the scroll buttons are :disabled.
Next, an appropriate icon is set on the left and right scroll buttons via the content property, which is also what causes the scroll buttons to be generated:
ul::scroll-button(left) {
content: "◄";
}
ul::scroll-button(right) {
content: "►";
}
We don't need to set alternative text for the icons on the content as the browser takes care of providing appropriate accessible names automatically.
Result
Note how the scroll buttons are created at the bottom left on the carousel. Try pressing them to see how they cause the content to be scrolled.