3

Let's consider example of cards with only subgrid feature.

body {
  max-width: 500px;
  margin: 1rem auto;
}

.container {
  display: grid;
  grid-template-columns: 2fr 1fr;
  grid-gap: 1rem;
}

.card {
  border: 1px solid #ccc;
  padding: 1rem;
  display: grid;
  grid-gap: 1rem;
  grid-row: span 3;
  grid-template-rows: subgrid;
}
<div class="container">
  <div class="card">
    <h2>Title Similique quisquam nesciunt</h2>
    <p>
      Body Lorem ipsum dolor sit, amet consectetur adipisicing elit. Similique quisquam nesciunt nihil totam laborum corporis animi expedita molestias, accusantium amet libero at neque id voluptatum, numquam, natus blanditiis eos sit!
    </p>
    <p>Footer nesciunt nihil</p>
  </div>
  <div class="card">
    <h2>Title accusantium amet libero at neque</h2>
    <p>
      Body Lorem, ipsum dolor sit amet consectetur adipisicing elit. Quisquam minima ducimus numquam deleniti perspiciatis expedita nam commodi laboriosam illo! Blanditiis in dolorem eius. Hic assumenda architecto quidem magnam?
    </p>
    <p>Footer dolor sit amet consectetur adipisicing elit</p>
  </div>
</div>

This generates perfectly what I want (title, body and footer are align vertically):

enter image description here

Codesanbox for first implementation (https://codesandbox.io/s/silent-voice-cklrms), at time of 23.07.2023 I suggest to open it in Chrome Canary or Firefox.


Problem

When I try to add to my example CSS @container query I don't know how to keep the previous functionality of subgrid.

Consider this modification to HTML, addition of .card-outer-wrapper, reference why I had to add this wrapper:

body {
  max-width: 500px;
  margin: 1rem auto;
}

.container {
  display: grid;
  grid-template-columns: 2fr 1fr;
  grid-gap: 1rem;
}

.card {
  border: 1px solid #ccc;
  padding: 1rem;
  display: grid;
  grid-gap: 1rem;
  grid-row: span 3;
  grid-template-rows: subgrid;
}

.card-outer-wrapper {
  container-type: inline-size;
}

@container (min-width: 300px) {
  .card {
    background-color: aqua;
  }
}
<div class="container">
  <div class="card-outer-wrapper">
    <div class="card">
      <h2>Title Similique quisquam nesciunt</h2>
      <p>
        Body Lorem ipsum dolor sit, amet consectetur adipisicing elit. Similique quisquam nesciunt nihil totam laborum corporis animi expedita molestias, accusantium amet libero at neque id voluptatum, numquam, natus blanditiis eos sit!
      </p>
      <p>Footer nesciunt nihil</p>
    </div>
  </div>
  <div class="card-outer-wrapper">
    <div class="card">
      <h2>Title accusantium amet libero at neque</h2>
      <p>
        Body Lorem, ipsum dolor sit amet consectetur adipisicing elit. Quisquam minima ducimus numquam deleniti perspiciatis expedita nam commodi laboriosam illo! Blanditiis in dolorem eius. Hic assumenda architecto quidem magnam?
      </p>
      <p>Footer dolor sit amet consectetur adipisicing elit</p>
    </div>
  </div>
</div>

It properly shows background color on wider card but it lacks of subgrid functionality:

enter image description here

Here is code sandbox for second example: https://codesandbox.io/s/nifty-feynman-n42s5p

Question

How to modify my second example to achieve subgrid alignment and @container query together?

Desired output should look like this: enter image description here

Highlight of desired vertical alignment: enter image description here

Everettss
  • 15,475
  • 9
  • 72
  • 98
  • 2
    For reference purposes, browser support for `grid-template-rows: subgrid` is still very weak. https://caniuse.com/mdn-css_properties_grid-template-rows_subgrid – Michael Benjamin Jul 23 '23 at 15:41
  • @MichaelBenjamin I'm aware of this. But I believe that the end of this year support will be decent enough to ship code with subgrid with in mind that fallback still will look ok. Like in my example when you open this in browser not supporting subgrid layout look ok, it will only lack of vertical alignment (nice to have). – Everettss Jul 23 '23 at 16:43

2 Answers2

1

It is my understanding that what you are trying to do is currently not possible.

If you set the value subgrid on grid-template-columns and/or grid-template-rows, the nested grid uses the tracks defined for its parent instead of creating a new track listing. This allows two sibling nested grids to have the same structure.

Container queries enable you to apply styles to an element based on the size of the element's container. In other words, you can apply styles to the descendent elements of the container, not the container itself.

However, when a wrapper div is added to be the container element for container queries, the wrapper div is the child of the grid container. The two card divs are no longer siblings and no longer share the same internal grid structure.

Additionally, I discovered through testing that the subgrid structure is lost if container-type is also declared on that element. Therefore, the following idea currently does not maintain subgrid structure:

.card {
  /* ... */
  grid-template-rows: subgrid;
  container-type: inline-size;
}

@container (min-width: 300px) {
  .card > * {
    background-color: aqua;
    margin: 0;
    padding: 1rem;
  }
}


I came up with a "hack" (workaround). If it's known what fraction of the grid container the column is, you can calculate how wide the grid container has to be in order for the column to be the targeted width. Therefore, you can get a result similar to the desired container query by applying the container query to the grid container and using pseudo-classes (such as :first-child, :nth-child()) to target individual columns.

Declare container-type for the grid container. Since you are using grid-template-columns: 2fr 1fr, the first column's width is 2/3 of the grid container (before factoring in padding and gap, which I won't address.) Therefore, you can calculate the min-width value of the container to be 3/2 times the targeted min-width of the first column. Finally, use the :first-child pseudo-class in the container query to target the first column.

(If every column is 1fr, then multiply the number of columns by the targeted min-width for each column and there's no need to use a pseudo-class.)

3 / 2 * 300px = 450px

.container {
  container-type: inline-size;
}

@container (min-width: 450px) {
  .card:first-child {
    background-color: aqua;
  }
}

body {
  max-width: 500px;
  margin: 1rem auto;
}

.container {
  container-type: inline-size;
  display: grid;
  grid-template-columns: 2fr 1fr;
  grid-gap: 1rem;
}

.card {
  border: 1px solid #ccc;
  padding: 1rem;
  display: grid;
  grid-gap: 1rem;
  grid-row: span 3;
  grid-template-rows: subgrid;
}

@container (min-width: 450px) {
  .card:first-child {
    background-color: aqua;
  }
}
<div class="container">
  <div class="card">
    <h2>Title Similique quisquam nesciunt</h2>
    <p>
      Body Lorem ipsum dolor sit, amet consectetur adipisicing elit. Similique quisquam nesciunt nihil totam laborum corporis animi expedita molestias, accusantium amet libero at neque id voluptatum, numquam, natus blanditiis eos sit!
    </p>
    <p>Footer nesciunt nihil</p>
  </div>
  <div class="card">
    <h2>Title accusantium amet libero at neque</h2>
    <p>
      Body Lorem, ipsum dolor sit amet consectetur adipisicing elit. Quisquam minima ducimus numquam deleniti perspiciatis expedita nam commodi laboriosam illo! Blanditiis in dolorem eius. Hic assumenda architecto quidem magnam?
    </p>
    <p>Footer dolor sit amet consectetur adipisicing elit</p>
  </div>
</div>
Tim R
  • 2,622
  • 1
  • 3
  • 19
  • But now you are not utilizing any @container feature. You can remove `@container (min-width: 450px) {` wrapper and achieve the same solution. It is more prominent that this code is not using properly @container query when you modify in `.container` template columns to: `grid-template-columns: 1fr 2fr;` – Everettss Jul 27 '23 at 08:24
  • @Everettss Not true, the background color is applied only when the container has a minimum width of 450px. And I did say it is a hack for the targeted column. – Tim R Jul 27 '23 at 08:43
  • I'm not looking for solution based on `.container` width but on row width. For example when in future I decide to show 3 cards in a row by modifying `.container` to `grid-template-columns: 1fr 1fr 1fr;` I want all my 3 cards to be white. – Everettss Jul 27 '23 at 08:49
  • I understand what you want, however, I believe it is currently not possible. That's why my suggestion for getting a similar result is to calculate the width of the container. It's known what fraction of the container the column is, therefore it's known how wide the container has to be in order for the column to be the targeted width. Individual columns can be targeted with a pseudo-class. Admittedly, not an ideal solution, just a workaround based on current browser support. Maybe someone can come up with a better solution. – Tim R Jul 27 '23 at 09:19
  • 1
    I prefer answer: "it is not possible, because (here is some good explanation)" rather than hacky workaround. – Everettss Jul 27 '23 at 09:39
  • 1
    @Everettss I explained at the beginning of my answer why it's not currently possible... – Tim R Jul 27 '23 at 21:08
1

According to your requirement, you have to calculate the width of the card and also want to change the background color of that card. But according to the official documentation of @container, we can't directly change the properties on which we apply container-type property. So, what I did is I wrapped every component inside the card with a div tag and used a background color to that div tag.

I got the answer like this

changed the background color of the first column

  body {
  max-width: 500px;
  margin: 1rem auto;
}
.container {
  display: grid;
  grid-template-columns: 2fr 1fr;
  grid-template-rows: auto;
  grid-gap:1rem;
}

.card {
  container-type: inline-size;
  border: 1px solid #ccc;
  display: grid;
  grid-row:span 3;
  grid-template-rows:subgrid;
}

.card div{
  padding:1rem;
}

@container (min-width: 300px) {
  .card div {
    background-color: aqua !important;
  }
}
<div class="container">
      <div class="card">
        <div>
        <h2>Title Similique quisquam nesciunt</h2>
        </div>
        <div>
        <p>
          Body Lorem ipsum dolor sit, amet consectetur adipisicing elit. Similique quisquam nesciunt nihil totam laborum corporis animi expedita molestias, accusantium amet libero at neque id voluptatum, numquam, natus blanditiis eos sit!
        </p>
       </div>
       <div>
        <p>Footer nesciunt nihil</p>
       </div>
      </div>
      <div class="card">
        <div>
        <h2>Title accusantium amet libero at neque</h2>
       </div>
       <div>
        <p>
          Body Lorem, ipsum dolor sit amet consectetur adipisicing elit. Quisquam minima ducimus numquam deleniti perspiciatis expedita nam commodi laboriosam illo! Blanditiis in dolorem eius. Hic assumenda architecto quidem magnam?
        </p>
       </div>
       <div>
        <p>Footer dolor sit amet consectetur adipisicing elit</p>
       </div>
      </div>

  </div>

now I changed grid-templete-columns: 1fr 1fr 1fr

I got this as the result Result after changing the grid-templete-columns value to 1fr 1fr 1fr

body {
  max-width: 500px;
  margin: 1rem auto;
}

.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: auto;
  grid-gap:1rem;
}

.card {
  container-type: inline-size;
  border: 1px solid #ccc;
  display: grid;
  grid-row:span 3;
  grid-template-rows:subgrid;
}

.card div{
  padding:1rem;
}

@container (min-width: 300px) {
  .card div {
    background-color: aqua !important;
  }
}
<div class="container">
    <div class="card">
      <div>
      <h2>Title Similique quisquam nesciunt</h2>
      </div>
      <div>
      <p>
        Body Lorem ipsum dolor sit, amet consectetur adipisicing elit. Similique quisquam nesciunt nihil totam laborum corporis animi expedita molestias, accusantium amet libero at neque id voluptatum, numquam, natus blanditiis eos sit!
      </p>
     </div>
     <div>
      <p>Footer nesciunt nihil</p>
     </div>
    </div>
    <div class="card">
      <div>
      <h2>Title accusantium amet libero at neque</h2>
     </div>
     <div>
      <p>
        Body Lorem, ipsum dolor sit amet consectetur adipisicing elit. Quisquam minima ducimus numquam deleniti perspiciatis expedita nam commodi laboriosam illo! Blanditiis in dolorem eius. Hic assumenda architecto quidem magnam?
      </p>
     </div>
     <div>
      <p>Footer dolor sit amet consectetur adipisicing elit</p>
     </div>
    </div>
    <div class="card">
     <div>
     <h2>Title accusantium amet libero at neque</h2>
     </div>
     <div>
      <p>
      Body Lorem, ipsum dolor sit amet consectetur adipisicing elit. Quisquam minima ducimus numquam deleniti perspiciatis expedita nam commodi laboriosam illo! Blanditiis in dolorem eius. Hic assumenda architecto quidem magnam?
      </p>
     </div>
     <div>
     <p>Footer dolor sit amet consectetur adipisicing elit</p>
     </div>
    </div>

</div>
</body>
Tim R
  • 2,622
  • 1
  • 3
  • 19
  • Good effort but subgrid is not working in both of your examples. As I explained in my answer, an element cannot currently have both subgrid and container-type declarations. – Tim R Aug 01 '23 at 02:48
  • Instead of wrapping each element in a `div`, the container query selector could be `.card > *` instead of `.card div` – Tim R Aug 01 '23 at 02:51