Centering content of a scrollable container with preserved offsets on both sides

27 views Asked by At

Here's something that might be simple and hopefully possible with pure css.

We have horizontally scrolling container (.scroller). It's width is 100% of its parent and in most cases is the viewport with.

Inside it is another container (.wrapper) with a maximum width of part of 80% of its container with margin-left and margin-right set to auto in order to centre it within the scrolling container. It is a flex box allowing for its unknown number of children to align as row inside it (.items).

Now, the positioning of the first .items will correspond to the left margin and any padding of the wrapper. As the .scroller scrolls horizontally, this wrapper and all of it's children will move however, because the scrollWidth of scroller is set by the .wrapper and its .items, the final position of the scroll will not reflect the .wrappers offsetRight.

Here is a snippet. The idea is there is the same amount of yellow and green space on the right hand side at the end of the scroll as this is on the left at the beginning of the scroll (don't need to see the colours, just that amount in pixels -- colours are for ease of demo).

.scroller {
  background-color: yellow;
  overflow-y: hidden;
  width: 100%;
}

.wrapper {
  align-items: start; 
  display: flex;
  background: green;
  max-width: 80%;
  margin: 0 auto;
  padding: 4%;
}

.items {
  background: red;
  flex: 0 0 60%;
  height: 200px;
  margin: 4px;
}
<div class="scroller">
  <div class="wrapper">
    <div class="items">1</div>
    <div class="items">2</div>
    <div class="items">3</div>
    <div class="items">4</div>
    <div class="items">5</div>
  </div>
</div>

We could calculate the offset of the first .items in javascript and apply it as margin-right to the last .items but that might interfere with other styles applied. What is the best approach to this / is there a pure css way of doing it.

// EDIT 8 February 2024 //

Yes and no. The reason for the problem concerns layouts where a max-width has been applied and margin: auto to centre said content.

Things get complicated when said max-width 's also incur changes via media queries (breakpoints).

Creative use of the css calc() can overcome this issue but only if all those max-widths are known. It also requires accepting that the padding of .scroller cannot be changed and the use of css custom properties.

IF we have a layout width element of say 300px that can change base on media queries (breakpoints) then we can also calculate its theoretical padding assuming no other constraints.

--content-width: 300px;

--theoretical-padding: calc(calc(100vw - 300px) *.5);

And we can then use that theoretical padding in a css clamp equation meaning that whatever else we do, the padding-left and padding right can't be smaller than this.

padding: clamp(var(--theoretical-padding), 0,  calc(calc(100vw - var(--content-width)) * 0.5), 100vw);

Whilst not a perfect solution it is a pure css solution that can be used for a general class of say .scroller but would have to be modified if the max-width of .scroller is different than standard or if the alignment (margin) is not centred (auto).

0

There are 0 answers