2

I have a horizontal scrolling div with several child items. Depending on the width, child items can get cropped. So you might get 4 and a 1/2 visible items. So I've used Javascript to force a width to evenly distribute the child items.

I've used Javascript to detect the width of .palette and divide that by the number of items I want to show (minus margins) and applied that to each .swatch. Not sure if there's a better/simpler way?

If this is the solution, I need a bit of help making this more responsible so it updates on resize of window.

  1. I'd like the offsetWidth to update on resize so the widths update.
  2. Is it possible to use matchMedia to use a different value above certain 'breakpoints'? This is partially working!

let palette = document.querySelector('.palette');
let paletteWidth = palette.offsetWidth;
let swatch = document.querySelectorAll('.swatch')

swatch.forEach((item) => {
    if (window.matchMedia("(min-width: 700px)").matches) {
    item.style.width = (paletteWidth - 40) / 5 + "px";
    } else {
    item.style.width = (paletteWidth - 30) / 4 + "px";
    }
});

const handleResize = () => {
    let paletteWidth = palette.offsetWidth;
};

window.addEventListener('resize', handleResize);
.p-card {
  background: #eee;
  box-sizing: border-box;
  display: flex;
  flex-shrink: 0;
  overflow: hidden;
  padding: 30px 15px;
  max-width: 50%;
}

.palette {
  display: flex;
  overflow-x: scroll;
}

.palette__inner {
  display: flex;
  overflow-x: scroll;
  scroll-snap-type: x mandatory;
  scrollbar-width: none; /* Firefox */
  -ms-overflow-style: none; /* IE and Edge */
}

.palette__inner::-webkit-scrollbar {
  display: none;
}

.palette__group {
  display: flex;
  flex-direction: column;
}

.palette__title {
  font-family: "Arial", sans-serif;
  font-size: 11px;
  font-weight: normal;
  margin: 0 10px 10px 0;
  padding: 0;
  position: sticky;
  align-self: flex-start;
  left: 0;
}

.palette__swatches {
  display: flex;
}

.swatch {
  background: red;
  display: flex;
  height: 20px;
  margin-right: 10px;
  scroll-snap-align: start;
  width: 40px;
}
<div class="p-card">

  <div class="palette">
    <div class="palette__inner">
    
       <div class="palette__group">
        <h4 class="palette__title">Classic</h4>
        <div class="palette__swatches">
          <div class="swatch" style="background: red;"></div>
          <div class="swatch" style="background: red;"></div>
          <div class="swatch" style="background: red;"></div>
          <div class="swatch" style="background: red;"></div>
          <div class="swatch" style="background: red;"></div>
          <div class="swatch" style="background: red;"></div>
        </div>    
      </div>
      
      <div class="palette__group">
        <h4 class="palette__title">Matte</h4>
        <div class="palette__swatches">
          <div class="swatch" style="background: blue;"></div>
          <div class="swatch" style="background: blue;"></div>
          <div class="swatch" style="background: blue;"></div>
          <div class="swatch" style="background: blue;"></div>
          <div class="swatch" style="background: blue;"></div>
          <div class="swatch" style="background: blue;"></div>
        </div>     
      </div>
      
      <div class="palette__group">
        <h4 class="palette__title">Glimmer</h4>
        <div class="palette__swatches">
          <div class="swatch" style="background: green;"></div>
          <div class="swatch" style="background: green;"></div>
          <div class="swatch" style="background: green;"></div>
          <div class="swatch" style="background: green;"></div>
          <div class="swatch" style="background: green;"></div>
          <div class="swatch" style="background: green;"></div>
        </div>  
      </div>

    </div>
  </div>

</div>
user1406440
  • 1,329
  • 2
  • 24
  • 59

1 Answers1

1

The idea is that in your resize callback function, you're just updating the width of the parent element (.palette) but not the width of the children elements (.swatch).

New JS code to adopt:

let palette = document.querySelector('.palette');
let swatchs = document.querySelectorAll('.swatch')

function setSwatchWidth(n = 5) {
  let paletteWidth = palette.offsetWidth;
  swatchs.forEach((swatch) => {
    swatch.style.width = (
      paletteWidth - (n-1) * 10
    ) / n + "px";
  });
}
onload = () => setSwatchWidth();
onresize = () => setSwatchWidth();

Bonus: I made the function more generic so that you can choose how many children you want in the sliding window.

underflow
  • 1,545
  • 1
  • 5
  • 19
  • 1
    That's ace! Thanks a lot, I'm a total novice so just getting the basic JS working was a challenge for me. I got this far but you's is much better/dynamic: https://jsfiddle.net/2jdyoq6L/ ...out of interest on that if I refresh loads the width is wrong and sometimes stars at the end/middle of the carousel. But I think that might just be an issue with running it in JSFiddle? – user1406440 Feb 12 '23 at 18:07
  • 1
    And with 'n' your counting the children minus '1'. Multiplying that by 10. Then dividing it by the total about of items (n)? – user1406440 Feb 12 '23 at 18:08