w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.52k stars 673 forks source link

[css-grid-N] Flowing grid items together #9098

Open tabatkins opened 1 year ago

tabatkins commented 1 year ago

Problem: There are several situations where authors want to use a particular DOM structure for semantic reasons, but want to rearrange the elements on layout. Grid (and other layout methods) can do this to some extent, but when the rearrangement would involve wrapping a container around some of the elements, it's impossible. This proposal aims to solve a limited subset of these use-cases, that should be sufficiently useful, widely implementable, and have minimal (ideally, none) accessibility implications.

Examples:

Complications to Avoid:

Proposal:

Details:

Additional Notes:

Questions:

Examples using this proposal:

.tab-container {
  display: grid;
  grid-template: "tabs" "cards";
}
.tab-container::grid-flow(--tabs) {
  display: flexbox;
  grid-area: tabs;
}
.tab-container > h2 {
  grid-flow: --tabs;
}
.tab-container > section {
  grid-area: cards;
  &:not(.active) {
    visibility: hidden;
    order: -1;
  }
}
@media (width < 800px) {
  body {
    display: flexbox;
    /* just lay out the page vertically */
    ...
  }
}
@media (width >= 800px) {
  body {
    display: grid;
    grid-template: "header header header"
                   "side   main   ads"
                   "side   footer footer";
  }
  body > main { grid-area: main; }
  body > header { grid-area: header; }
  body > footer { grid-area: footer; }
  body > nav, body > aside { grid-flow: --side; }
  body > .ad-spot { grid-flow: --ads; }
  body::grid-flow(--side) {
    grid-area: side;
  }
  body::grid-flow(--ads) {
    grid-area: ads;
  }
}
astearns commented 1 year ago

I don’t want to jinx this proposal, but there are likely a lot of considerations we already hammered out around general named flows that we should apply to grid-flows.

tabatkins commented 1 year ago

Nah this actually avoids virtually all of the issues with general flows. It just slaps a wrapper around siblings.

Loirooriol commented 1 year ago

So this would basically cover #1183 and #6714

tabatkins commented 1 year ago

Yup!

fantasai commented 1 year ago

Historical note: Bert's original (grid) template layout proposal had a feature like this. https://www.w3.org/TR/css-template-3/ If we spec this, might want to poke around in the historical archives for details that might be useful. :)

tabatkins commented 1 year ago

Yup, specifically in https://www.w3.org/TR/css-template-3/#flow. The behavior was essentially what is defined here, it just named the pseudo-element ::slot().

It did have a way to target empty slots, which is interesting.

ChazUK commented 4 months ago

Would love to know if this has been thought about being accepted. CSS Grids would become so powerful for reordering elements for different breakpoints

johannesodland commented 2 months ago

Would it be possible to auto-generate ::grid-flow() pseudos when doing auto layout?

Say that you want to layout an article with grid, and place most items in a centered text-column. Wrapping these elements with a ::grid-flow() pseudo would be awesome, and would unlock using a separate layout for the text elements, such as regular flow.

Every now and then you might want an element to pop out of the column and use different grid tracks.

After the popout element you really want to start a new ::grid-flow() wrapper, as you don't want to reorder the elements of the article.

Would it be possible automatically generate separate ::grid-flow() wrappers for each group of adjacent siblings?

<article>
  <!-- start of ::grid-flow(--text 1) -->
  <h1>Title</h1>
  <p>Text...</p>
  <p>Some more text...</p>
  <!-- end of ::grid-flow(--text 1) -->
  <img class=popout />
  <!-- start of ::grid-flow(--text 2) -->
  <h2>Subtitle</h2>
  <p>Some more text..</p>
  <!-- end of ::grid-flow(--text 2) -->
</article>
article {
  display: grid;
  grid-template-columns:
    [popout-start] minmax(20px, 1fr)
    [text-start] minmax(auto, 600px)
    [text-end] minmax(20px, 1fr)
    [popout-end];
}

article > :is(h1, h2, p, img) {
  grid-flow: --text;
}

article::grid-flow(--text /* auto/adjacent? */) {
  grid-column: text-start / text-end;
}

article > .popout {
  grid-column: popout-start / popout-end;
  grid-flow: none;
}