adjust the scrollbar right offset of a grid wrapper

Viewed 79

The blue box is fixed size with 100px x 100px. The margin between boxes is dynamic but minimum 10px. under this situation. The row should be fit with the boxes with "The more the better" rule. Say, the margin between boxes is (A). I would like the padding of grid container (B) is two times to (A). If width of (A) is 20px then width of (B) is 40px.

and The scrollbar in (B) should be align center to (B).

expect layout

  body{
    overflow: hidden;
  }
  
  .container {
    display: grid;
    width: 100%;
    gap: 10px;
    overflow-y: auto;
    justify-content: space-evenly;
    grid-template-columns: repeat(auto-fit, 100px);
  }

  ::-webkit-scrollbar {
    width: 4px;
    background-color: transparent;
  }

  ::-webkit-scrollbar-thumb {
        background-color: rgba(0, 0, 0, 0.4);
        background-color: var(--scrollbar-color, rgba(0, 0, 0, 0.4) );
        width: 4px;
        border-radius: 10px;
  }

  .box {
    width: 100px;
    height: 100px;
    display: inline-flex;
    background-color: blue;
  }
<div class="container">
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <!-- many boxes below -->
</div>

2 Answers

Try this:

  body{
    padding: calc(20px + 1em);
    margin: 0;
    padding-right: calc(8px + 0.5em);
  }
  
  .container {
    display: grid;
    width: 100%;
    gap: calc(10px + 0.5em);
    overflow-y: auto;
    justify-content: space-between;
    grid-template-columns: repeat(auto-fit, 100px);
  }

  ::-webkit-scrollbar {
    width: calc(12px + 0.5em);
  }

  ::-webkit-scrollbar-thumb {
    border-right: calc(8px + 0.5em) solid rgba(0, 0, 0, 0);
    background-clip: content-box;
    background-color: rgba(0, 0, 0, 0.15);
  }

  .box {
    width: 100px;
    height: 100px;
    display: inline-flex;
    background-color: blue;
  }
<div class="container">
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <!-- many boxes below -->
</div>

I'm afraid I can't think of a way to do it via pure CSS but it'd be achievable via JS.

See:

function scrollAlign() {
  let e = document.getElementsByClassName("container")[0];
  let eWidth = e.getBoundingClientRect().width;
  let n = (eWidth - 10) / 110;
  let gaps = eWidth - parseInt(n) * 100;
  let gapWidth = gaps / 14;
  document.documentElement.style.setProperty("--gapWidth", gapWidth + "px");
}
scrollAlign();
:root {
  --gapWidth: 10px;
  --scrollWidth: 4px;
}

body {
  overflow: hidden;
}

.container {
  display: grid;
  gap: 10px;
  overflow-y: auto;
  justify-content: space-around;
  grid-template-columns: repeat(auto-fit, 100px);
  height: 330px;
  padding-right: calc(1.5* var(--gapWidth) - var(--scrollWidth));
  width: calc(100% - var(--gapWidth) + var);
  margin: 0;
}

.container::-webkit-scrollbar {
  width: var(--scrollWidth);
  background-color: transparent;
  padding-right: calc(2*var(--gapWidth));
}

.container::-webkit-scrollbar-thumb {
  background-color: rgba(0, 0, 0, 0.4);
  background-color: var(--scrollbar-color, rgba(0, 0, 0, 0.4));
  width: var(--scrollWidth);
  border-radius: 10px;
}

.box {
  width: 100px;
  height: 100px;
  display: inline-flex;
  background-color: blue;
}

.gridContainer {
  padding-right: calc(2 * var(--gapWidth) - var(--scrollWidth)/2);
  outline: 5px ridge black;
}
<div class="gridContainer">
  <div class="container">
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
  </div>
</div>

I'm afraid I can't provide you with a better sample that uses CSS alone. But this JS, indeed, does the trick.

If you need it, I could explain to you how exactly it does it, but for short, scrollAlign() calculates the gapWidth (the width of a single gap) and provides it as --gapWidth to the root.

And from here, CSS starts its work, it calculates how much padding each element needs to centre-align the scrollbar.

Just note that I have added a new element ".gridContainer".

Good luck!

**EDIT: ** I have added an outline for the .gridContainer, so you'd see the scrollbar is centre-aligned; By the way id you seek a border, you must calculate the width of the border in some CSS calculations, outlines are okay though.

Related