Search code examples
htmlcssscrollflexboxcentering

Center elements in a scrollable area


How do you center align the first and last flex items in a scrollable horizontal flex container?

Getting scroll to work is easy.

My container has:

scroll-snap-type: x mandatory;
overflow-x: scroll;

and items have:

scroll-snap-align: center;

Scrolling works, however the leftmost and rightmost items in the list are always align to the left and right, respectively.

I would like to get the first and the last items to be able to centered as well in list of scrollable elements.

If we look at this example "home" tab is the left most item. I would like to get that centered with in the scrollable area.

Do I need to have blank tabs on the left and right of the scrollable area ?

Thanks for any advice.

div.scrollmenu {
  background-color: #333;
  overflow: auto;
  white-space: nowrap;
}

div.scrollmenu a {
  display: inline-block;
  color: white;
  text-align: center;
  padding: 14px;
  text-decoration: none;
}

div.scrollmenu a:hover {
  background-color: #777;
}
<div class="scrollmenu">
  <a href="#home">Home</a>
  <a href="#news">News</a>
  <a href="#contact">Contact</a>
  <a href="#about">About</a>
  <a href="#support">Support</a>
  <a href="#blog">Blog</a>
  <a href="#tools">Tools</a>
  <a href="#base">Base</a>
  <a href="#custom">Custom</a>
  <a href="#more">More</a>
  <a href="#logo">Logo</a>
  <a href="#friends">Friends</a>
  <a href="#partners">Partners</a>
  <a href="#people">People</a>
  <a href="#work">Work</a>
</div>


Solution

  • Do I need to have blank tabs on the left and right of the scrollable area?

    That's not a bad idea.

    You could create a bunch of "fake" elements on both ends, then give them visibility: hidden.

    div.scrollmenu {
      background-color: #333;
      overflow: auto;
      white-space: nowrap;
    }
    
    div.scrollmenu a {
      display: inline-block;
      color: white;
      text-align: center;
      padding: 14px;
      text-decoration: none;
    }
    
    div.scrollmenu a:hover {
      background-color: #777;
    }
    
    /* NEW */
    a:nth-child(-n + 5),
    a:nth-last-child(-n + 5) {
      background-color: green;
      visibility: hidden;
    <div class="scrollmenu">
      <a href="#home">Home</a>
      <a href="#home">Home</a>
      <a href="#home">Home</a>
      <a href="#home">Home</a>
      <a href="#home">Home</a>
      <a href="#home">Home</a>
      <a href="#news">News</a>
      <a href="#contact">Contact</a>
      <a href="#about">About</a>
      <a href="#support">Support</a>
      <a href="#blog">Blog</a>
      <a href="#tools">Tools</a>
      <a href="#base">Base</a>
      <a href="#custom">Custom</a>
      <a href="#more">More</a>
      <a href="#logo">Logo</a>
      <a href="#friends">Friends</a>
      <a href="#partners">Partners</a>
      <a href="#people">People</a>
      <a href="#work">Work</a>
      <a href="#home">Home</a>
      <a href="#home">Home</a>
      <a href="#home">Home</a>
      <a href="#home">Home</a>
      <a href="#home">Home</a>
      <a href="#home">Home</a>
    </div>

    However, there's a simpler and more semantically valuable solution: use CSS pseudo-elements.

    Since you're only focusing on the appearance of the layout, you shouldn't tamper with the HTML. You should stick with pure CSS.

    And since pseudo-elements on a flex container are treated as flex items, you can use ::before (the first item in the natural flow) and ::after (the last item in the natural flow) to create the centering effect you need.

    div.scrollmenu {
      background-color: #333;
      overflow: auto;
      white-space: nowrap;
      display: flex;
    }
    
    div.scrollmenu a {
      color: white;
      text-align: center;
      padding: 14px;
      text-decoration: none;
    }
    
    div.scrollmenu a:hover {
      background-color: #777;
    }
    
    /* NEW */
    .scrollmenu::before,
    .scrollmenu::after {
      content: "";
      flex: 0 0 50%;
    }
    <div class="scrollmenu">
      <a href="#home">Home</a>
      <a href="#news">News</a>
      <a href="#contact">Contact</a>
      <a href="#about">About</a>
      <a href="#support">Support</a>
      <a href="#blog">Blog</a>
      <a href="#tools">Tools</a>
      <a href="#base">Base</a>
      <a href="#custom">Custom</a>
      <a href="#more">More</a>
      <a href="#logo">Logo</a>
      <a href="#friends">Friends</a>
      <a href="#partners">Partners</a>
      <a href="#people">People</a>
      <a href="#work">Work</a>
    </div>