Visitar URL original
[css-multicol] Do we need column-wrap as well as column-height · Issue #11754 · w3c/csswg-drafts · GitHub
Skip to content

[css-multicol] Do we need column-wrap as well as column-height #11754

Open

Description

@rachelandrew

I've added an initial draft based on the resolution in #2923 (comment). That resolution resolved to add column-height with the suggestion that setting a value of column-height other than auto should trigger the creation of column rows, rather than new columns in the inline direction, as currently happens.

Using 'column-height' means that authors have the option, when creating these overflow rows to have additional space in the multicol container which can then be controlled by the alignment properties. For example:

.container {
  block-size: 20em;
  column-count: 3;
  column-height: 5em;
}

In this case,column-height is the trigger for rows. Assuming we have less content than would create rows that fill or overflow the block-size of the multicol container, there's extra space. I imagine this would then be controlled in the same way as additional space in a grid container after laying out columns, meaning you could center the multicol inside the container.

However, with column-height the trigger for wrapping this would mean you couldn't set a column-height yet keep inline column overflow, in the case that you wanted to have additional space in a multicol that was doing inline overflow. So you couldn't use the preceding example, keep inline overflow of columns then center the single line of columns inside the multicol container.

Also, using column-height to trigger wrapping seems a little magical and doesn't map to the way other things behave.

In my original suggestion I had proposed a column-wrap property to trigger the wrapping. My suggestion is to keep that as the trigger, but maintain this column-height property, as this will allow for the scenario mentioned, with inline overflowing columns and extra space, it also means that to get wrapping you asking for wrapping, rather than set a height on columns and something else happens.

Therefore, the following example would have a multicol container height of 20em, column-height of 5em. If there was too much content after filling three 5em tall columns, columns would be created in the inline direction. The extra space in the block direction could be distributed by the alignment properties.

.container {
  block-size: 20em;
  column-count: 3;
  column-height: 5em;
}

To get rows from this example, you add the column-wrap property. After the three columns are filled, a new row of three columns is created in the block direction, and this continues until all content is displayed. Again, if this results in spare space, this can be distributed by alignment.

.container {
  block-size: 20em;
  column-count: 3;
  column-height: 5em;
  column-wrap: wrap;
}

Adding this to the agenda in the hope of getting a resolution on this property. If we resolve on this, there's a secondary point to resolve on.

What is the behavior, if the author sets column-wrap: wrap, a height on the multicol container, but column-height is auto. I think the two options are:

  1. Do nothing, column-wrap: wrap only does something if column-height is not auto.
  2. Create new rows, if there is overflow, essentially resolving column-height to the available height of the multicol container, and creating new rows of that same size in the block direction.

My preference is 2, as then we maintain the trigger behavior of column-wrap, and it feels reasonable logical, but we'd need a decision one way or another should we adopt column-wrap and column-height.

Activity

  1. self-assigned this
    on Feb 20, 2025
  2. SebastianZ commented on Feb 20, 2025

    @SebastianZ
    Contributor

    I agree that it makes sense to split the column height from whether additional columns are layed out in inline or block direction.

    I just wanted to note that there's another way of thinking about this is like the auto-flow mechanism in Grid. I.e. a property similar to grid-auto-flow that takes either row (default) or column as values.

    Sebastian

  3. rachelandrew commented on Feb 24, 2025

    @rachelandrew
    ContributorAuthor

    I still think this behavior is more like flex wrapping than grid, and giving another property the value of column while in multiple column layout seems a bit confusing ... "do you want columns with those columns?"

  4. fantasai commented on Mar 10, 2025

    @fantasai
    Collaborator

    I don't think the use case of using the alignment properties to distribute space around fixed-height columns within the container is that compelling, so I think I'd lean towards not keeping column-wrap in favor of automatically wrapping. We can introduce a value for column-height that fills the containing block (stretch?) when it is definite, if that's a use case we want to serve.

  5. rachelandrew commented on Mar 10, 2025

    @rachelandrew
    ContributorAuthor

    I'm not keen on column-height triggering this behavior, I don't think it would be expected, and it seems clumsy to work around that in the future with another property just to avoid the column-wrap property now.

  6. mstensho commented on Mar 12, 2025

    @mstensho
    Contributor

    I really think that we want column-wrap. Wrapping automatically if column-height is non-auto (and small enough) seems too magical to me.

    What is the behavior, if the author sets column-wrap: wrap, a height on the multicol container, but column-height is auto. I think the two options are:

    1. Do nothing, column-wrap: wrap only does something if column-height is not auto.
    2. Create new rows, if there is overflow, essentially resolving column-height to the available height of the multicol container, and creating new rows of that same size in the block direction.

    My preference is 2, as then we maintain the trigger behavior of column-wrap, and it feels reasonable logical, but we'd need a decision one way or another should we adopt column-wrap and column-height.

    I agree. The two properties should be set completely independently and not affect each other.

    Meaning that what https://drafts.csswg.org/css-multicol-2/#cwr says for column-wrap needs to go away:

    The property only takes effect if column-height is not auto, [...]

    I wonder if column-wrap should have a third value auto, to support the current behavior, and always honor the value, regardless of media type.

    As the spec seems to be aware of, for paged media we always wrap. But this is also true for nested multicol.

    <!DOCTYPE html>
    <div style="line-height:50px; orphans:1; widows:1;">
      <div style="columns:2; column-fill:auto; height:100px; background:yellow;">
        <div style="height:50px;"></div>
        <div style="columns:2; column-fill:auto; background:cyan;">
          A<br>
          B<br>
          C<br>
          D<br>
        </div>
      </div>
    </div>

    This renders like:

    Image

    Not like this:

    Image

    Columns currently wrap if the multicol container lives inside another fragmentation context, be it paged media or another ancestor multicol.

  7. mstensho commented on Mar 13, 2025

    @mstensho
    Contributor

    Regarding column-wrap:auto, though (my previous comment), is that going to cause trouble for the columns shorthand?

  8. moved this from FTF agenda items to Wednesday Morning in CSSWG April 2025 meeting agendaon Apr 2, 2025
  9. moved this from Wednesday Morning to Wednesday Afternoon in CSSWG April 2025 meeting agendaon Apr 2, 2025
  10. 12 remaining items

  11. mstensho commented on Apr 9, 2025

    @mstensho
    Contributor

    Maybe it doesn't match with everyone's mental model of this, but there's essentially an implicit wrap between the two "A B" columns and the two "C D E F" columns, and between the two "C D E F" columns and the five "G H I J K" columns. Without these implicit wraps, there would be eleven columns next to each other on one row/line, like this, all in the first outer column:

    Image

    Yes exactly, no column-height in my example. I'm just pointing out that there's already some sort of wrapping as it is (and has been for years), and that sometimes it wraps (between the first and second column, and again between the second and third column), and sometimes it doesn't (if the block-size is constrained, like in the third outer column). But maybe that's an other kind of wrapping that shouldn't be controlled by column-wrap. Otherwise column-wrap:auto (initial value) would resolve to nowrap in my example, and result in the rendering shown above, in this comment - which would break existing implementations.

    If we could explain lines and rows in the spec, and how they relate to each other, this might become a bit clearer.

  12. rachelandrew commented on Apr 9, 2025

    @rachelandrew
    ContributorAuthor

    That doesn't seem to be wrapping as we're defining it here though (I'm finding these examples hard to follow, but I don't see anything I'd describe as a "wrap") this is because you have one multicol nested inside another.

    A regular multicol container has a single row, as we're defining it, inside which is at least one line of columns, but could be more if there is a spanner (that was the diagram I posted here). You only get multiple rows if you wrap. The column-wrap property only controls those "overflow" columns. The ones that would currently go out in the inline direction and cause a scrollbar. I need to add all this to the multcol model part of the spec, maybe I'll get chance on Friday to do that.

    I feel like I'm just not getting your point about the nested columns, do you have a more realistic example or use case?

  13. mstensho commented on Apr 9, 2025

    @mstensho
    Contributor

    Nested multicol isn't very realistic, but it's similar to printing a multicol, which also gives you a nested fragmentation context.

    I'm talking about this: https://drafts.csswg.org/css-break/#nested-flows

    [...] when a multi-column container breaks across pages, it generates a new row of columns on the next page for the rest of its content [...]

  14. rachelandrew commented on Apr 9, 2025

    @rachelandrew
    ContributorAuthor

    I understand when it happens, it's what you are describing as "wrapping" I don't understand.

  15. mstensho commented on Apr 9, 2025

    @mstensho
    Contributor

    When an inner multicol container breaks, it generates a new row. New row means wrapping, is what I'm thinking.

    Let's do printing instead. Nested multicol is bad for the brain.

    <!DOCTYPE html>
    <style>
      @page {
        size: 500px 240px;
        margin: 20px;
      }
      body {
        line-height: 50px;
        orphans: 1;
        widows: 1;
        margin: 0;
      }
    </style>
    <div style="height:100px;"></div>
    <div style="columns:2; column-fill:auto; height:300px; background:yellow;">
      A<br>B<br>C<br>D<br>E<br>F<br>G<br>H<br>I<br>J<br>K<br>
    </div>

    Image

    A new row of columns is started on the second page. If we hadn't done that, and instead let columns be as tall as they want, and cross page boundaries, all in a single row, it would have looked like this:

    Image

    I.e. one would have to read the left column on all pages first, then turn back to page one and read the second column on all pages.

  16. rachelandrew commented on Jun 20, 2025

    @rachelandrew
    ContributorAuthor

    Back looking at this after an I/O induced hiatus...

    So, I believe this new behavior will never occur in paged contexts, which don't have overflow columns, because in paged media we have this forced break. In the multicolumn model section we have:

    If the multi-column container is paginated, the height of each column is constrained by the page and the content continues in a new line of column boxes on the next page; a column box never splits across pages.

    and also for spanners:

    The same effect occurs when a spanning element divides the multi-column container: the columns before the spanning element are balanced and shortened to fit their content. Content after the spanning element then flows into a new, subsequent line of column boxes.

    We're already defining this as lines. So we wouldn't expect gaps and rules, for example, to go between lines, whereas we do expect them to go between rows.

    In addition, in continuous contexts where we do have multiple rows, each row could contain multiple lines (due to spanners, as in the diagram in #11976 (comment)). So I think the wrapping you are talking about is the wrapping of lines, and not this sort of author-dictated wrapping in continuous contexts.

    (I'm working on adding essentially what I've just described to the model section of the spec.)

  17. mstensho commented on Jun 23, 2025

    @mstensho
    Contributor

    Back looking at this after an I/O induced hiatus...

    So, I believe this new behavior will never occur in paged contexts, which don't have overflow columns, because in paged media we have this forced break. In the multicolumn model section we have:

    If the multi-column container is paginated, the height of each column is constrained by the page and the content continues in a new line of column boxes on the next page; a column box never splits across pages.

    and also for spanners:

    The same effect occurs when a spanning element divides the multi-column container: the columns before the spanning element are balanced and shortened to fit their content. Content after the spanning element then flows into a new, subsequent line of column boxes.

    We're already defining this as lines. So we wouldn't expect gaps and rules, for example, to go between lines, whereas we do expect them to go between rows.

    Thank you. I think this is where my confusion came from. Lines, not rows. As long as column-height isn't used, there'll be no change.

    Here's a pagination example that does use column-height and column-wrap:nowrap, though:

    <!DOCTYPE html>
    <style>
      @page {
        size: 20em 10em;
        margin: 0;
      }
      body {
        margin: 0;
      }
      #mc {
        columns: 2;
        width: 40%;
        column-wrap: nowrap;
        column-height: 10em;
        font: 3em;
        column-rule: solid;
        background: yellow;
      }
      #mc > div {
        counter-increment: ctr;
      }
      #mc > div::before {
        content: counter(ctr);
      }
    </style>
    <div id="mc">
      <div></div><div></div><div></div><div></div><div></div>
      <div></div><div></div><div></div><div></div><div></div>
      <div></div><div></div><div></div><div></div><div></div>
      <div></div><div></div><div></div><div></div><div></div>
      <div></div><div></div><div></div><div></div><div></div>
    </div>

    This currently gets rendered like this in Chrome (with the feature enabled):

    Image

    Which is correct, I guess? We run out of columns (2), and keep overflowing in the inline direction, even if we're paginated.

  18. rachelandrew commented on Jul 30, 2025

    @rachelandrew
    ContributorAuthor

    Yes, in this case we carry on in the inline direction because we've explicitly said to nowrap.

    I think a lot of the above discussion just needs the updates to the multicol model section of the spec to define all the bits and how they relate to each other. We agreed to just leave this issue open and make a decision about whether to keep column-wrap later, I don't think we ned to resolve on this to progress the other issues so leaving it on hold for now.

  19. mstensho commented on Sep 16, 2025

    @mstensho
    Contributor

    If you want to create a vertical carousel using column wrapping on a scrollable container, and there is no column-wrap property, and you don't want to specify a fixed column-height (which you don't want to if all you want is to use available space), then how can we get multiple rows?

    The initial value of column-height is auto, and this does not enable multicol (nor wrapping). We could add another keyword value for column-height and let that value enable multicol and wrapping to solve this.

    Or, we can keep column-wrap?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions