cssflexboxcss-gridsubgrid

Make Item Stretch to Fill Space in Row Using Grid


I would like to have a grid .wrapper div that has 3 .card divs within it utilizing a subgrid with 2 sections within each .card div. These sections should line up because of the subgrid, which is why I need to use the grid for the parent div. However, I need to make this responsive similar to flexbox but with a subgrid. I am aware flexbox would solve this problem, however, I really want a subgrid so the cards line up on each line. I also have a .most-popular div that I would like to stay on top of the grid, however, this is not required if it breaks everything else. If A, B, and C were the rows and B was the .most-popular div, then here is what I want it to look like:


A B C for screens that are wide enough


B B
A C for screens that are medium-sized


B
A
C for screens that are too small


.list-grid {
    display: grid;
    gap: 20px;
    grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
    grid-template-rows: auto auto;
}

.list-grid>.card {
    display: grid;
    grid-template-rows: subgrid;
    grid-row: span 2;
}

.list-grid>.card>div:nth-child(1) {
    border-width: 0px;
    border-bottom: 2px solid;
    border-image: var(--secondary-accent-border-gradient) 1;
    border-bottom-width: 2px;
    border-style: solid;
    padding-bottom: 10px;
    border-top-width: 0px;
}

.most-popular {
    -webkit-transform: translateY(-100%);
    transform: translateY(-100%);
    border: 2px solid var(--secondary-accent-hover);
    border-radius: 5px;
    background-color: var(--primary-accent-color);
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    width: 70%;
    min-width: fit-content;
    position: absolute;
}

.most-popular>h3 {
    color: var(--accent-text-color);
}

.account-plan-desc-list {
    width: 90%;
    margin-inline: auto;
}
<div class="center-content" style="margin-top: 20px; margin-bottom: 35px;">
    <div class="list-grid center-content" style="width: 80%; height: 100%;">
        <div class="card">
            <div>
                <h1 class="card-title">Savings</h1>
                <div class="account-plan-desc-list">
                    <p class="check-mark">Good interest rate (4.20% per month)</p>
                    <p class="x-mark">Low § maximum (§150,000)</p>
                    <p class="x-mark">Only one account allowed</p>
                    <p class="x-mark">Not free</p>
                </div>
            </div>
            <div>
                <h2><span class="descriptor">from </span>§50.00<span class="descriptor">/account</span>
                </h2>
                <button class="btn fill-area-horiz" id="addToProfileSavings" style="margin-top: 10px;">
                    <h1><i class="fa-solid fa-plus"></i> Add to Profile</h1>
                </button>
            </div>
        </div>

        <div class="card" style="position: relative;">
            <div>
                <div class="center-content">
                    <div class="most-popular">
                        <h3><span class="nowrap"><i class="fa-solid fa-star"></i> MOST</span> <span
                                class="nowrap">POPULAR <i class="fa-solid fa-star"></i></span></h3>
                    </div>
                </div>
                <h1 class="card-title">Checking</h1>
                <div class="account-plan-desc-list">
                    <p class="check-mark">Collect an interest each month (<span class="descriptor">from
                        </span>0.03%<span class="descriptor">/month</span>)</p>
                    <p class="check-mark">Decent § maximum (§250,000)</p>
                    <p class="check-mark">Free</p>
                    <p class="x-mark">Only one account allowed</p>
                </div>
            </div>
            <div>
                <h2>Free</h2>
                <button class="btn fill-area-horiz" id="addToProfileChecking" style="margin-top: 10px;">
                    <h1><i class="fa-solid fa-plus"></i> Add to Profile</h1>
                </button>
            </div>
        </div>

        <div class="card">
            <div>
                <h1 class="card-title">Expanded Checking</h1>
                <div class="account-plan-desc-list">
                    <p class="check-mark">Collect an interest each month (<span class="descriptor">from
                        </span>0.04%<span class="descriptor">/month</span>)</p>
                    <p class="check-mark">As many accounts as you would like</p>
                    <p class="check-mark">Very large § maximum (§1,000,000)</p>
                    <p class="x-mark">Not free</p>
                </div>
            </div>
            <div>
                <h2><span class="descriptor">from </span>§10,000.00<span class="descriptor">/account</span>
                </h2>
                <button class="btn fill-area-horiz" id="addToProfileExChecking" style="margin-top: 10px;">
                    <h1><i class="fa-solid fa-plus"></i> Add to Profile</h1>
                </button>
            </div>
        </div>
    </div>
</div>

I tried using grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));. This worked, but when a .card div wrapped to the next line it made a huge gap to the right of it. I want that to instead fill all of the remaining space on its row if there are no other .card divs there.


Solution

  • The cleanest implementation of this would use grid areas. Your CSS can then precisely mirror the description of the placement of the A’s, B’s and C’s you gave in your post. You don’t need a subgrid or a nested grid: a simple, single grid will do the job.

    body {
      font-family: sans-serif;
      font-weight: bold;
      font-size: 20px;
    }
    
    .d1 {                                       /* small */
      display: grid;
      grid-template-columns: auto;              /* one column */
      grid-template-areas: "B" "A" "C";         /* three rows */ 
    }
    
    @media (min-width: 750px) {                 /* medium */
      .d1 {
        grid-template-columns: auto auto;       /* two columns */
        grid-template-areas: "B B" "A C";       /* two rows */
      }
    }
    
    @media (min-width: 1250px) {                /* large */
      .d1 {
        grid-template-columns: auto auto auto;  /* three columns */
        grid-template-areas: "A B C";           /* one row */
      }
    }
    
    .d1>* {
      padding: 1em;
      display: flex;
      justify-content: center;
    }
    
    .d1>*:nth-child(1) {
      grid-area: A;
      background: #DBE4EE;
    }
    
    .d1>*:nth-child(2) {
      grid-area: B;
      background: #81A4CD;
    }
    
    .d1>*:nth-child(3) {
      grid-area: C;
      background: #3E7CB1;
    }
    <div class="d1">
      <div>A</div>
      <div>B</div>
      <div>C</div>
    </div>

    After running this snippet, use the full page link to test the responsive behaviour.

    Read more about the properties grid-template-areas and grid-areas.