<div class="container">
<h1>Dynamic Image grid</h1>
<label for="photos">Photos</label>
<input type="number" id="photos" value="5" min="1" max="10" onchange="calculateGrid()" />
<select id="layout" onchange="calculateGrid(true)">
<option>single</option>
<optgroup label="2 Photos" id="group-2">
<option selected>p-p</option>
<option>p-l</option>
<option>l-l</option>
<option>l-p</option>
</optgroup>
<optgroup label="3 Photos" id="group-3">
<option>p-p-p</option>
<option>p-p-l</option>
<option>p-l-l</option>
<option>p-l-p</option>
<option>l-l-l</option>
<option>l-l-p</option>
<option>l-p-p</option>
<option>l-p-l</option>
</optgroup>
<optgroup label="4 or more photos" id="group-4">
<option>p-p-p-p</option>
<option>p-p-p-l</option>
<option>p-p-l-p</option>
<option>p-l-p-p</option>
<option>p-p-l-l</option>
<option>p-l-l-p</option>
<option>p-l-p-l</option>
<option>l-l-l-l</option>
<option>l-l-l-p</option>
<option>l-l-p-l</option>
<option>l-p-l-l</option>
<option>l-l-p-p</option>
<option>l-p-p-l</option>
<option>l-p-l-p</option>
</optgroup>
</select>
<ul id="imageGrid" class="h-h">
</ul>
<aside>
<h2>About</h2>
<p>A dynamically generated image grid that adjusts to show a thumbnail at the correct size depending on the orentation of the photo.</p>
<h2>What could be improved?</h2>
<p>Only the first image is given a special treatment, but in theory any of the images shown could be given a different treatment</p>
</aside>
</div>
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;600&display=swap');
body {
background: linear-gradient(-45deg, #70e1f5, #ffd194);
font-family: 'Open Sans', sans-serif;
}
h1,
aside,
.container {
margin: 0 auto 20px;
max-width: 500px;
}
.container {
background: white;
padding: 20px;
}
ul {
display: grid;
grid-gap: 5px 5px;
height: 300px;
list-style-type: none;
margin: 0;
overflow: hidden;
padding: 0;
width: 300px;
}
li {
background-image: url(https://images.unsplash.com/photo-1590943101617-6642f6f1e909?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60);
background-position: center;
background-size: cover;
display: block;
}
.single {
display: block;
}
#additionalImages {
color: #FFF;
font-size: 2em;
font-weight: bold;
text-shadow: 0 0 5px #000;
}
li {
height: 100%;
width: 100%;
}
.p-p,
.p-l {
grid-template-columns: 50% 50%;
}
.p-p li,
.p-l li {
grid-row-start: 0;
grid-row-end: 2;
}
.l-l,
.l-p {
grid-template-rows: 50% 50%;
}
.l-l li,
.l-p li {
grid-column-start: 0;
grid-column-end: 2;
}
.p-p-p,
.p-p-l,
.p-l-l,
.p-l-p,
.l-l-l,
.l-l-p,
.l-p-p,
.l-p-l {
grid-template-columns: 50% 50%;
grid-template-rows: 50% 50%;
}
.p-p-p li:first-child,
.p-p-l li:first-child,
.p-l-l li:first-child,
.p-l-p li:first-child {
grid-row-start: 1;
grid-row-end: 3;
}
.l-l-l li:first-child,
.l-l-p li:first-child,
.l-p-p li:first-child,
.l-p-l li:first-child {
grid-column-start: 1;
grid-column-end: 3;
}
.p-p-p-p,
.p-p-p-l,
.p-p-l-p,
.p-l-p-p,
.p-p-l-l,
.p-l-l-p,
.p-l-p-l {
grid-template-columns: 50% 50%;
grid-template-rows: calc(100%/3) calc(100%/3) calc(100%/3);
}
.l-l-l-l,
.l-l-l-p,
.l-l-p-l,
.l-p-l-l,
.l-l-p-p,
.l-p-p-l,
.l-p-l-p {
grid-template-columns: calc(100%/3) calc(100%/3) calc(100%/3);
grid-template-rows: 50% 50%;
}
.p-p-p-p li:first-child,
.p-p-p-l li:first-child,
.p-p-l-p li:first-child,
.p-l-p-p li:first-child,
.p-p-l-l li:first-child,
.p-l-l-p li:first-child,
.p-l-p-l li:first-child {
grid-column-start: 1;
grid-column-end: 1;
grid-row-start: 1;
grid-row-end: 4;
}
.l-l-l-l li:first-child,
.l-l-l-p li:first-child,
.l-l-p-l li:first-child,
.l-p-l-l li:first-child,
.l-l-p-p li:first-child,
.l-p-p-l li:first-child,
.l-p-l-p li:first-child {
grid-column-start: 1;
grid-column-end: 4;
grid-row-start: 1;
grid-row-end: 1;
}
function $(id) {
return document.getElementById(id);
}
function calculateGrid(ignoreAdjustingReconfiguration) {
var i = 0,
count = $('photos').value;
if(!ignoreAdjustingReconfiguration) {
allowedConfigurations(count);
}
$('imageGrid').className = $('layout').value;
$('imageGrid').innerHTML = '';
while(i < count) {
if(i < 4) {
if(i == 3 && count > 4) {
$('imageGrid').innerHTML += '<li class="hasMore"><span id="additionalImages">+1</span></li>';
} else {
$('imageGrid').innerHTML += '<li></li>';
}
} else {
$('additionalImages').innerHTML = '+'+(i-2);
}
i++;
}
}
function allowedConfigurations(count) {
var matchfound = false;
if(count == 2) {
$('group-2').disabled = false;
$('group-3').disabled = true;
$('group-4').disabled = true;
for(var i = 0; i < $('group-2').children.length; i++) {
if(layout.options[layout.options.selectedIndex].value == $('group-2').children[i].value) {
matchfound = true;
}
}
if(!matchfound) {
$('group-2').children[0].selected = true;
}
} else if(count == 3) {
$('group-2').disabled = true;
$('group-3').disabled = false;
$('group-4').disabled = true;
for(var i = 0; i < $('group-3').children.length; i++) {
if(layout.options[layout.options.selectedIndex].value == $('group-3').children[i].value) {
matchfound = true;
}
}
if(!matchfound) {
$('group-3').children[0].selected = true;
}
} else if(count >= 4) {
$('group-2').disabled = true;
$('group-3').disabled = true;
$('group-4').disabled = false;
for(var i = 0; i < $('group-4').children.length; i++) {
if(layout.options[layout.options.selectedIndex].value == $('group-4').children[i].value) {
matchfound = true;
}
}
if(!matchfound) {
$('group-4').children[0].selected = true;
}
} else {
$('group-2').disabled = true;
$('group-3').disabled = true;
$('group-4').disabled = true;
$('layout').children[0].selected = true;
}
}
calculateGrid();
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.