Search code examples
htmlcsscss-grid

When first column is not present, remaining columns should occupy the space


I'm trying to make a card component in CSS, I thought it would be straightforward, but I'm struggling with CSS grid properties. Also, I can't use flexbox in that case, for reasons not worth explaining :)

The layout is dead simple: an image on the left and some text on the right.

<div class="card">
  <figure card="card__img">
    <img src="https://via.placeholder.com/600" width="600" height="600">
  </figure>
  <p class="card__txt">Lorem ipsum tempus fugit.</p>
</div>

Here's the tricky part: the image is optional, and when present, it should not be wider than 50%.

When I put a max-width to the image, then the text doesn't expand if the image is absent.

Here's what I have at the moment:

.card {
  display: grid;
  column-gap: 1em;
  grid-template-columns: minmax(0, 50%) 1fr;
}

I tried to mess width grid-template-columns, but I'm not familiar enought yet with it.


You can see it in action on this Codepen: https://codepen.io/tcharlss/pen/gVvOjY

And here's the code snippet:

/* Layout stuff I'm strugling width*/

.card {
  display: grid;
  column-gap: 1em;
  grid-template-columns: minmax(0, 50%) 1fr;
}

/* Decoration & miscellaneous */

body { font-family: sans; }
.container {
  display: grid;
  column-gap: 1em;
  grid-template-columns: repeat(auto-fill, 35em);
}
.container + .container {
  margin-top: 2em;
}
.explication {
  color: hsl(230, 100%, 45%);
  font-family: monospace;
  font-style: italic;
}
.card {
  border: 1px solid hsl(230, 100%, 45%);
  min-height: 18em;
}
.card__txt {
  background-color: hsl(0, 0%, 90%);
  margin: 0;
}
figure {
  margin: 0;
}
img {
  max-width: 100%;
  height: auto;
}
<div class="container">

  <div class="col">
    <p class="explication">If an image is present, it can't be wider then 50%</p>
    <div class="card">
      <figure card="card__img">
        <img src="https://via.placeholder.com/600" width="600" height="600">
      </figure>
      <p class="card__txt">Lorem ipsum tempus fugit. Aut rerum nostrum qui adipisci est aut. Est error omnis sit velit.</p>
    </div>
  </div>
  
  <div class="col">
    <p class="explication">Without image, the text should expand to fill all the available space</p>
    <div class="card">
      <p class="card__txt">Lorem ipsum tempus fugit. Aut rerum nostrum qui adipisci est aut. Est error omnis sit velit.</p>
    </div>
  </div>
  
</div>


Solution

  • One approach, the easiest I can think of, is to style the generic .card__text elements one way, and then use the + combinator to style the elements that follow a .card__img element differently:

    /* here we use Grid layout, setting two columns
       each of 1fr (using the repeat() function): */
    .card {
      display: grid;
      grid-gap: 1em;
      grid-template-columns: repeat(2, 1fr);
    }
    
    /* setting the default presentation of the
       .card__txt elements; positioning them
       in the first column, spanning two
       columns: */
    .card__txt {
      grid-column: 1 / span 2;
    }
    
    /* separately styling the .card__txt elements
       that follow a .card__img element; here we
       place them in the second column: */
    .card__img + .card__txt {
      grid-column: 2;
    }
    

    /* Decoration & miscellaneous */
    
    body {
      font-family: sans;
    }
    
    .container {
      display: grid;
      column-gap: 1em;
      grid-template-columns: repeat(auto-fill, 35em);
    }
    
    .container+.container {
      margin-top: 2em;
    }
    
    .explication {
      color: hsl(230, 100%, 45%);
      font-family: monospace;
      font-style: italic;
    }
    
    .card {
      border: 1px solid hsl(230, 100%, 45%);
      min-height: 18em;
    }
    
    .card__txt {
      background-color: hsl(0, 0%, 90%);
      margin: 0;
    }
    
    figure {
      margin: 0;
    }
    
    img {
      max-width: 100%;
      height: auto;
    }
    
    
    /* changes */
    
    .card {
      display: grid;
      grid-gap: 1em;
      grid-template-columns: repeat(2, 1fr);
    }
    
    .card__txt {
      grid-column: 1 / span 2;
    }
    
    .card__img+.card__txt {
      grid-column: 2;
    }
    <div class="container">
    
      <div class="col">
        <p class="explication">If an image is present, it can't be wider then 50%</p>
        <div class="card">
    
          <!-- Note the correction, in your posted code the following
               was written:
          <figure card="card__img">
          I corrected 'card' to 'class' -->
          <figure class="card__img">
            <img src="https://via.placeholder.com/600" width="600" height="600">
          </figure>
          <p class="card__txt">Lorem ipsum tempus fugit. Aut rerum nostrum qui adipisci est aut. Est error omnis sit velit.</p>
        </div>
      </div>
    
      <div class="col">
        <p class="explication">Without image, the text should expand to fill all the available space</p>
        <div class="card">
          <p class="card__txt">Lorem ipsum tempus fugit. Aut rerum nostrum qui adipisci est aut. Est error omnis sit velit.</p>
        </div>
      </div>
    
    </div>

    JS Fiddle demo.