- const IMG_DATA = {
- 	'dessert 1': 'https://images.unsplash.com/photo-1564844536308-75c540dbf14e?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=950&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ', 
- 	'dessert 2': 'https://images.unsplash.com/photo-1548865164-c4e93ca471aa?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=950&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ', 
- 	'dessert 3': 'https://images.unsplash.com/photo-1502004960551-dc67f7c24cb3?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=950&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ', 
- 	'dessert 4': 'https://images.unsplash.com/photo-1551276705-0503a4b9d38c?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=950&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ', 
- 	'dessert 5': 'https://images.unsplash.com/photo-1551529563-9dd66d188764?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=950&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ', 
- 	'dessert 6': 'https://images.unsplash.com/photo-1473340186413-a68ba9c2564e?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=950&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ'
- };
- let min = 1, max = 6, val = 6;
- let key = ['start', 'center', 'end', 'space-between', 'space-around', 'space-evenly'];
- let n = key.length;
- let w = 14;

mixin grid(col_rule = 'auto-fit')
	article(style=`--col-rule: ${col_rule}`)
		pre.dark
			span.token--prop grid-template-columns
			span.token--punc :
			|  
			span.token--func repeat
			span.token--punc (
			span.token--args
				span.token--arg.token--keyw #{col_rule}
				span.token--punc ,
				|  
				span.token--arg.token--len
					span.token--num #{w}
					span.token--unit vw
			span.token--punc )
		section.grid
			- for(let i in IMG_DATA)
				img(src=IMG_DATA[i])

body(style=`--min: ${min}; --val: ${val}; --max: ${max}; --key: ${key[1]}; --w: ${w}vw`)
	pre.dark
		span.token--prop justify-content
		span.token--punc :
		span.ctrl
			output(for=key.join(' ') aria-haspopup='true' aria-expanded='false' aria-controls='pop').token--keyw(data-val=key[1])
			form#pop.dark
				- for(let i = 0; i < n; i++) {
					input(type='radio' name='key' id=key[i] value=key[i] checked=!(i - 1))
					label(for=key[i]) #{key[i]}
				- }
		span.token--comm /* change this value */
	+grid
	+grid('auto-fill')
	form.pan.dark
		label(for='val') Thumbnails per grid:
		input#val(type='range' name='val' min=min value=val max=max)
		output(for='val' data-val=val)
	a(href='https://codepen.io/thebabydino/pen/QWjovRV' target='_blank') Also check out the first version! 😼
View Compiled
$pad: .5em;
$gap: .5vw;
$c: orange;
$t: .2s;

$b-arrow: .5*$pad;

$track-w: 15em;
$track-h: .25em;
$track-r: .5*$track-h;

$thumb-d: 1em;
$thumb-r: .5*$thumb-d;

$mover-w: $track-w - $thumb-d;

@mixin track() {
	border: none;
	width: $track-w; height: $track-h;
	border-radius: $track-r;
	background: currentcolor;
}

@mixin thumb($f: 0) {
	margin-top: $f*($track-r - $thumb-r);
	border: none;
	width: $thumb-d; height: $thumb-d;
	border-radius: 50%;
	background: $c
}

* {
	box-sizing: inherit;
	margin: 0;
	padding: 0;
	background: transparent;
	color: inherit;
	font: inherit
}

body {
	box-sizing: border-box;
	display: grid;
	grid-gap: 2*$pad;
	grid-template-rows: max-content 1fr 1fr max-content;
	overflow-x: hidden;
	margin: 0;
	min-height: 100vh;
	background: whitesmoke;
	font: 1.25em ubuntu mono, consolas, monaco, monospace;
	
	@media (max-width: 385px) { font-size: 1em }
}

a {
	margin-top: -2*$pad;
	padding: .25em .5em;
	background: crimson;
	color: #fff;
	font-weight: 900;
	text-align: center;
	text-decoration: none
}

pre {
	z-index: 2;
	padding: $pad }

form {
	display: grid;
}

label {
	
}

output {
	&::after { content: attr(data-val) }
}

article {
	--dim: calc(100vw - 1.5em);
	place-self: center;
	width: var(--dim);
}

img {
	place-self: stretch;
	height: 8em;
	object-fit: cover;
	border-radius: 3px;
	box-shadow: 2px 2px 5px rgba(#000, .5)
}

.dark {
	padding: $pad;
	background: rgba(#000, .9);
	color: #d9d9d9;
	
	:not(body) > & { border-radius: 5px }
}

.token {
	&--prop { color: #B7E3C0 }
	
	&--func { color: #B8D0DD }
	
	&--keyw {
		display: inline-block;
		padding: 0 .25em;
		border-radius: 3px;
		background: #F8F087;
		color: #222;
		font-weight: 900
	}
	
	&--num { color: #DBBAE5 }
	
	&--unit { color: #F39DD4 }
	
	@media (max-width: 565px) {
		&--prop ~ &--func::before { content: '\A   ' }
	}
}

.ctrl { cursor: pointer }

[id='pop'] {
	--j: 0;
	overflow: hidden;
	position: absolute;
	top: 100%; left: 0;
	width: max-content;
	transform-origin: 0 0;
	transform: scale(var(--j));
	transition: $t calc((1 - var(--j))*#{$t});
	
	label {
		opacity: var(--j);
		transition: $t calc(var(--j)*#{$t})
	}
	
	[aria-expanded='true'] + & { --j: 1 }
}

[type='radio'] {
	position: absolute;
	right: 100%;
	
	+ label { cursor: pointer }
	
	&:checked + label { color: $c	}
}

.grid {
	display: grid;
	justify-content: var(--key);
	grid-gap: $gap;
	grid-template-columns: repeat(var(--col-rule, auto-fit), var(--w));
	margin-top: $pad;
	
	[style*='auto-fill'] > & {
		--g: #{$gap};
		background: 
			repeating-linear-gradient(90deg, 
					transparent 0 0, 
					#dfdfdf 0 calc(var(--w) - 0px), 
					transparent 0 calc(var(--w) + var(--g))) 
				var(--x, 50%) 50%/ 
				calc(var(--max)*var(--w) + (var(--max) - 1)*var(--g)) 
				calc(100% - 2px) no-repeat
	}
	
	body[style*='start'] & { --x: 0 }
	
	body[style*='end'] & { --x: 100% }
	
	body[style*='space-between'] & {
		--g: calc((var(--dim) - var(--max)*var(--w))/(var(--max) - 1))
	}
	
	body[style*='space-around'] & {
		--g: calc((var(--dim) - var(--max)*var(--w) - (var(--max) - 1)*#{$gap})/var(--max) + #{$gap})
	}
	
	body[style*='space-evenly'] & {
		--g: calc((var(--dim) - var(--max)*var(--w) - (var(--max) - 1)*#{$gap})/(var(--max) + 1) + #{$gap})
	}
}

.ctrl {
	position: relative;
	white-space: normal;
	
	> output {
		white-space: pre;
	}
}

.pan {
	--i: var(--wide, 1);
	--not-i: calc(1 - var(--i));
	--focus: 0;
	--not-focus: calc(1 - var(--focus));
	place-content: center;
	grid-template-columns: minmax(max-content, 0) $track-w minmax(max-content, 0);
	grid-gap: $pad;
	filter: grayScale(var(--not-focus));
	
	&:focus-within { --focus: 1 }
	
	@media (max-width: 610px) {
		--wide: 0
	}
}

[for='val'] {
	grid-column: calc(1 + var(--not-i));
	place-self: center var(--wide, end)
}

[type='range'] {
	&, &::-webkit-slider-thumb, 
	&::-webkit-slider-runnable-track { -webkit-appearance: none }

	grid-column: 2;
	grid-row: calc(1 + var(--not-i));
	cursor: pointer;

	&::-webkit-slider-runnable-track {
		@include track()
	}

	&::-moz-range-track {
		@include track()
	}

	&::-webkit-slider-thumb {
		@include thumb(1)
			}

	&::-moz-range-thumb {
		@include thumb()
			}

	&:focus { outline: solid 0 transparent }
}

output[for='val'] {
	grid-column: calc(3 - var(--not-i));
	grid-row: calc(1 + var(--not-i));
	place-self: start;
	transform: 
		translate(calc(var(--not-i)*(#{$thumb-r} + (var(--val) - var(--min))/(var(--max) - var(--min))*#{$mover-w} - 50%)), 
							calc(var(--not-i)*(#{$b-arrow} - 100%)));
	
	&::after {
		display: block;
		border: solid $b-arrow transparent;
		padding: 0 .5em;
		border-radius: calc(#{$b-arrow} + 3px);
		transform-origin: 50% 100%;
		transform: scale(calc(var(--i) + var(--not-i)*var(--focus)));
		background: nth($c, 1) border-box;
		color: #222;
		text-align: center;
		--xy: calc(var(--not-i)*50%) calc(50%*(1 + var(--not-i)));
		--mask:
			linear-gradient(red, red) padding-box, 
			conic-gradient(
					from calc(45deg - var(--not-i)*90deg) 
					at var(--xy), 
					red 0% 25%, transparent 0%) 
				var(--xy)/ 50% 50% no-repeat border-box;
		-webkit-mask: var(--mask);
						mask: var(--mask);
		transition: transform .3s, filter .3s
	}
}
View Compiled
const _BODY = document.body, 
			_GRIDS = [...document.querySelectorAll('.grid')].map(c => ({
				_el: c, 
				_imgs: [...c.querySelectorAll('img')]
			})), 
			FN = ['append', 'remove'];

addEventListener('click', e => {
	let _tg = e.target;
	
	if(_tg.hasAttribute('aria-haspopup')) {
		console.log(_tg.getAttribute('aria-expanded'))
		if(_tg.getAttribute('aria-expanded') === 'false')
			_tg.setAttribute('aria-expanded', 'true')
	}
	else {
		let _octrl = document.querySelector('[aria-expanded=true]');
		
		if(_octrl) _octrl.setAttribute('aria-expanded', 'false')
	}
}, false);

addEventListener('input', e => {
	let _tg = e.target, 
			new_val = _tg.value, 
			_out = document.querySelector(`output[for*='${_tg.id}']`), 
			old_val = _out.dataset.val;
	
	if(new_val != old_val) {		
		if(_tg.type === 'range') {
			_GRIDS.forEach(g => {
				let dif = +new_val - +old_val, 
						sgn = Math.sign(dif), 
						bit = .5*(1 - sgn);

				while(dif !== 0) {
					g._el[`${FN[bit]}Child`](g._imgs[new_val - dif - bit])
					dif -= sgn
				}
			});
		}
		
		_BODY.style.setProperty(`--${_tg.name}`, _out.dataset.val = new_val)
	}
}, false);
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.