A fascinating puzzle to solve, given the variability in the number of cards that can exist within the "wallet," ranging from 1, 2 to N
, and the necessity for explicit specification of a tracking size in the CSS properties grid-auto-rows
and/or grid-template-rows
.
Several solutions at hand (all while utilizing grid efficiently)
https://i.sstatic.net/eHCTcm.pnghttps://i.sstatic.net/vPzlym.png
#1 A straightforward yet inelegant approach
The simple fix involves adding a margin-top: 200px;
to the TEXT div specifically when the cards are stacked.
This solution may not be ideal as it's more of a quick workaround rather than a refined design choice.
function expandStackCards() {
var wrapper = document.getElementById("wrapper");
if (wrapper.classList.contains("stacked")) {
wrapper.classList.remove("stacked");
} else {
wrapper.classList.add("stacked");
}
}
button {
width: 400px;
margin-bottom: 10px;
}
#wrapper {
display: grid;
grid-template-columns: 400px;
gap: 10px;
}
#wrapper.stacked {
grid-auto-rows: 30px;
gap: 0px;
}
.card {
width: 100%;
height: 200px;
background-color: grey;
border-radius: 20px;
padding: 6px 20px;
box-sizing: border-box;
}
.card span {
font-family: sans-serif;
text-transform: uppercase;
color: white;
}
.card.green {
background-color: green;
}
.card.blue {
background-color: blue;
}
.my-text {
margin: 10px;
}
.stacked .my-text {
margin-top: 200px;
}
<button onclick="expandStackCards()">Expand / Stack</button>
<div id="wrapper" class="stacked">
<div class="card green"><span>Card #1</span></div>
<div class="card blue"><span>Card #2</span></div>
<div class="my-text">TEXT</div>
</div>
Alternatively, check out the Codepen code here
#2 Leveraging JavaScript for dynamic adjustment of grid-auto-rows
In my view, this is the most effective solution as it entails no reliance on margin adjustments but solely utilizes grid CSS.
To implement this method, a bit of JavaScript is required to determine the card count and accordingly set the value of grid auto rows.
function stackedCards() {
var wrapper = document.querySelector('#wrapper.stacked');
if (wrapper) {
var num_cards = wrapper.querySelectorAll(':scope .card').length;
let style = getComputedStyle(wrapper);
row_height_str = style.gridAutoRows;
var new_grid_auto_rows = row_height_str.concat(' ').repeat(num_cards - 1);
new_grid_auto_rows = new_grid_auto_rows.concat('auto');
wrapper.style.gridAutoRows = new_grid_auto_rows;
}
}
// The function below is designed solely for DEMO purposes
function expandStackCards() {
var wrapper = document.getElementById("wrapper");
if (wrapper.classList.contains("stacked")) {
wrapper.classList.remove("stacked");
wrapper.style.removeProperty("grid-auto-rows");
} else {
wrapper.classList.add("stacked");
stackedCards();
}
}
stackedCards();
button {
width: 400px;
margin-bottom: 10px;
}
#wrapper {
display: grid;
grid-template-columns: 400px;
gap: 10px;
}
#wrapper.stacked {
grid-auto-rows: 30px;
gap: 0px;
}
.card {
width: 100%;
height: 200px;
background-color: grey;
border-radius: 20px;
padding: 6px 20px;
box-sizing: border-box;
}
.card span {
font-family: sans-serif;
text-transform: uppercase;
color: white;
}
.card.green {
background-color: green;
}
.card.blue {
background-color: blue;
}
.my-text {
margin: 10px;
}
<button onclick="expandStackCards()">Expand / Stack</button>
<div id="wrapper" class="stacked">
<div class="card green"><span>Card #1</span></div>
<div class="card blue"><span>Card #2</span></div>
<div class="my-text">TEXT</div>
</div>
For the corresponding implementation, feel free to explore the Codepen code here
#3 Employing JavaScript to assign a class to the #wrapper
An additional strategy involves using JavaScript to identify the number of cards and subsequently apply an appropriate class to the grid container (#wrapper
).
This method resembles the previous one but refrains from setting CSS styles via JavaScript; however, your CSS file needs declarations like the following:
.wallet-1-cards {
grid-auto-rows: auto;
}
.wallet-2-cards {
grid-auto-rows: 30px auto;
}
.wallet-3-cards {
grid-auto-rows: 30px 30px auto;
}
.wallet-4-cards {
grid-auto-rows: 30px 30px 30px auto;
}
// etc...
By opting for this third approach, you steer clear of incorporating CSS within your JS code (instead, applying a class to a div), which proves advantageous provided the likelihood of exceeding a certain card limit is minimal—thereby preventing CSS clutter with numerous redundant definitions.