Looking for some assistance with my TV Show Searcher project that is based on an API. The functionality is complete, but I'm struggling to get the Bootstrap cards to stack neatly without any empty space between them. I want it to resemble the image gallery layout of unsplash.com where images stack seamlessly regardless of size. Any help or advice would be greatly appreciated.
I have a single row div in which I dynamically add col-4 divs using JavaScript to display 4 TV shows per line based on the API data. Below are the HTML, CSS, and JS files containing the code snippet:
console.log('Connected')
const form = document.querySelector('#searchForm');
const imgs = document.querySelector('#imgsDisplay')
const search = document.querySelector('#searchDisplay')
const row = document.querySelector('#row')
form.addEventListener('submit',async function (e) {
e.preventDefault();
row.innerHTML='';
const searchTerm = form.elements.query.value;
const config = { params: { q: searchTerm } }
const res = await axios.get(`http://api.tvmaze.com/search/shows`, config);
search.textContent = form.elements.query.value
makeImages(res.data)
form.elements.query.value = '';
})
const makeImages = (shows) => {
for (let result of shows) {
if (result.show.image) {
const col = document.createElement('div')
col.classList.add('col-3', 'h-100')
const imgDiv = document.createElement('div')
imgDiv.classList.add('card', 'cardStyle', 'm-0')
const img = document.createElement('IMG');
img.classList.add('card-img-top')
img.src = result.show.image.medium;
const label = document.createElement('h5')
label.textContent = result.show.name;
label.classList.add("card-title")
const text = document.createElement('p')
text.classList.add('card-text')
text.innerHTML = result.show.summary;
const cardBody = document.createElement('div')
cardBody.classList.add('card-body')
const showSite = document.createElement('a')
showSite.href = result.show.officialSite;
showSite.textContent = 'Official Website'
showSite.classList.add('btn', 'btn-outline-success')
cardBody.append(label)
cardBody.append(text);
cardBody.append(showSite)
imgDiv.append(img);
imgDiv.append(cardBody);
col.append(imgDiv);
row.append(col);
imgs.append(row);
}
}
}
#searchForm{
width: 40%;
}
.cardStyle{
width: 18rem;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TV Show Search</title>
<link rel="stylesheet" href="app.css">
<link href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<section>
<div class="container d-flex flex-column align-items-center">
<h1 class="display-1">TV Show Search</h1>
<form id="searchForm">
<div id="inputForm" class="container input-group mb-3">
<input id="search" type="text" class="form-control" placeholder="TV Show Title" aria-label="TV Show Title" aria-describedby="button-addon2" name="query">
<button class="btn btn-outline-success" id="button-addon2">Search</button>
</div>
</form>
</div>
</section>
<section>
<div class="container ms-1 mt-5">
<h1 id='resultsHeader' class="display-3">Results for: <b><span id="searchDisplay"></span></b></h1>
</div>
</section>
<section id="imgsDisplay" class="container mt-5">
<div id = "row" class="row d-flex">
</div>
</section>
<script src="app.js"></script>
</body>
</html>