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.
offsetWidth
to update on resize so the widths update.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>
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
).
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.