Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
tabatkins opened this issue Jul 20, 2023 · 8 comments
Open

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

tabatkins opened this issue Jul 20, 2023 · 8 comments
Labels
css-grid-3 Masonry Layout

Comments

@tabatkins
Copy link
Member

tabatkins commented Jul 20, 2023

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:

  • DOM structure of <h2>...</h2><section>...</section><h2>...</h2><section>...</section>, but author wants to display it as tabs, with the h2s collected together into a flexbox and only one section showing at a time.
  • Author uses a Grid for whole-page layout, and to allow changing the layout significantly between desktop and mobile. On desktop, they have two independent sidebars that they put some of the elements in (a nav, a footer, an aside...), and each sidebar should flow naturally regardless of the sizes of the elements. Using several grid areas for each sidebar, one per element, accidentally establishes relationships between the sizes of the elements across the sidebars, tho.

Complications to Avoid:

  • Significantly changing the layout tree can have significant a11y implications; see the continuing troubles with display: contents and its ability to remove an a11y-significant parent from the tree. If possible, we should avoid changing the layout tree in major ways; ideally don't reparent anything, just rearrange.
  • Large-scale layout-tree reorganization is non-trivial (maybe impossible, depending on browser). Currently CSS is limited to fairly trivial reorderings like popover and other top-layer effects, or display: contents which is a local transform.

Proposal:

  • Add a new grid-flow: <<dashed-ident>> <<integer>>? property, valid on in-flow grid items. It indicates that the grid item will be reparented in a group with other grid items using the same ident. (They are sorted by integer, then by DOM order, identical to how auto-flow works with the 'order' property.)
  • Add a new pseudo-element to grid containers, ::grid-flow(<<dashed-ident>>). Each distinct ident refers to a separate pseudo-element. It's an anonymous block, treated as a grid item of the container, that holds all the reflowed grid items with the matching ident. It's tree-abiding and can take all properties, so you can position it in the grid, set background/border, set overflow, make it a flexbox, etc.

Details:

  • As this just reparents grid items to a new, pseudo-element grid item of the same container, the a11y structure is still essentially the same, just in a different order. The layout-tree movement is fairly local, so it should be doable without too much rearchitecting by other browsers.
  • We might want to limit what values the ::grid-flow() pseudo can take in some cases, to avoid accidentally causing a11y implications. Ideally the ::grid-flow() pseudo is "transparent" for a11y purposes, so for practical purposes the reflowed items can still be treated as children of the grid container. For example, disallow display: list-item, as list items are reflected specially in the a11y tree. (TODO: figure out what the full set of a11y-significant properties/values are and decide how much we want to restrict things.)

Additional Notes:

  • We want to allow ::grid-flow() to exist even if nothing is flowed into it, for stable layouts - an area might have items in it only conditionally, but you still want to display the (empty) area itself. This solves the "decorative grid pseudo-elements" issue as well, which will make people happy.

Questions:

  • Is this satisfactory from an a11y standpoint? We want to verify this early to avoid another display:contents debacle.
  • This proposal is intentionally limited, but is it still powerful enough to be worthwhile?

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;
  }
}
@tabatkins tabatkins added the css-grid-3 Masonry Layout label Jul 20, 2023
@astearns
Copy link
Member

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
Copy link
Member Author

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

@Loirooriol
Copy link
Contributor

So this would basically cover #1183 and #6714

@tabatkins
Copy link
Member Author

Yup!

@fantasai
Copy link
Collaborator

fantasai commented Sep 8, 2023

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
Copy link
Member Author

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
Copy link

ChazUK commented Jul 10, 2024

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
Copy link

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;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
css-grid-3 Masonry Layout
Projects
None yet
Development

No branches or pull requests

6 participants