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-multicol] Overflow in the block direction for continuous media #2923

Open
rachelandrew opened this issue Jul 13, 2018 · 23 comments
Open

Comments

@rachelandrew
Copy link
Contributor

In multicol 1, overflow in continuous media happens in the inline direction, therefore if we restrict a multicol container by height and the content of that container creates more columns than will fit, new columns are created in the inline direction and we get a horizontal scrollbar. This is, in general, not what web authors want.

Overflow in the Block direction would enable something like the below image, where the additional columns are created below the initial multicol container.

overflow-block-direction

In talking to web authors, there was an interest in this ability. Use cases would be to give the multicol container a height in viewport units in order to know that a reader would not have to scroll up and down to read the content, instead they could read one set of columns, scroll down and read the next. There are examples of people using vertical media queries to check for enough space to display columns such as https://css-tricks.com/guide-responsive-friendly-css-columns/#article-header-id-12

When discussing this, authors immediately jumped to the need/desire to control those overflow columns in some way, perhaps by being able to specify a different number of columns/column width in the overflow. For example having the first set of column boxes render three columns, and the second two.

@frivoal
Copy link
Collaborator

frivoal commented Jul 13, 2018

I have a work-in-progress draft spec to deal with putting additional columns in the block direction (and sizing things properly, so that these extra columns are not only overflow, but actually consume space and don't collide with what's after). I'll share as soon as it is a bit more fleshed out.

When it comes to styling the next row(s) of columns differently, I think this will be solved by continue: fragment and ::nth-fragment](https://drafts.csswg.org/css-overflow-4/#fragment-pseudo-element). That isn't solved yet, but we're making baby steps towards it in css-overflow-3, since line-clamp starts to put in place some of the related machinery.

@arnt
Copy link

arnt commented Jan 12, 2019

For paged media, please make the default height of the multicol container be "to the bottom of the current page".

@jr-grenoble
Copy link

The feature is absolutely needed, but it begs one comment: allowing text to flow in the block direction is equivalent to assigning paged media behavior to continuous media for the purpose of multicols (in paged media, columns must overflow in the "block" direction).

Wouldn't it be both more general and easier to allow CSS to assign paged media behavior to continuous media? This would well support the use of CSS to create interactive presentations (slides) or newspaper like layouts, on screen; and it would immediately solve the multicol issue.

By the way, controlling whether columns have the same specs when moving to the next "page/block" remains an open question.

@Heydon
Copy link

Heydon commented Jul 19, 2019

What can I do to help push this along?

@rachelandrew
Copy link
Contributor Author

It's something we intend to look at in Level 2, I'm currently working to get Level 1 back to CR so it isn't something we can focus on right now. What would help would be if someone were willing to pay for the work - neither @frivoal nor myself are specifically paid to work on multicol. So we do it as we have time to do and the time I have I'm using to get the issues in the Level 1 specification sorted.

@Heydon
Copy link

Heydon commented Jul 19, 2019

@rachelandrew Thanks for the quick reply. Okay, I don't think I can afford to pay you 😅but, if it is at all helpful, maybe I can write about it publicly, and moot some ideas for the syntax. I am already exploring some existing ways to control column display based on circumstance, such as using quantity queries: https://codepen.io/heydon/pen/PvXJGv.

@rachelandrew
Copy link
Contributor Author

Yes - we are always interested in ideas and particularly in use cases for this stuff! Do post a link back here, it can take a while for things to get worked on but we do take the contributions of folk into account when we get to it.

@Heydon
Copy link

Heydon commented Jul 22, 2019

@rachelandrew Here's the post: https://every-layout.dev/blog/multi-column-manipulation/

P.S. I tried using a CSS regions polyfill to emulate block overflow, but couldn't get the polyfill itself yo work. I may revisit it.

@baybal
Copy link

baybal commented Nov 29, 2021

I just stumbled on this peculiarity of the spec, and I want the spec to follow firefox, and historical webkit behaviour: extra content overflows vertically as if columns are balanced, and it respects orphans css prop.

Otherwise, I see no way how to square it with #4689 and spec-compliant column-fill, an min-height behaviour.

How overflow-y: auto can work if columns overflow an y-scrollable container element? Columns will overlow on the right, while y-direction will be occupied by empty space equivalent to height of overflown column?

I cannot fathom what purpose this logic serves.

@seannherdy
Copy link

End user here. I am using multicol for wide displays (e.g. 4K) when a user maximizes their browser window. This is to reduce difficulty in reading extra long lines of text.

I did run into a pecularity with this feature on iPad and I'm not sure if it's a bug or a feature. On the following web page, there is a line chart and a pie chart that just happen to straddle the column break. The page displays correctly at first, and sometimes when I scroll the line chart gets moved to the top of column 2 and the pie chart is displayed on top of the line chart. (not supposed to happen) Here's a screenshot:

IMG_0005

Multicol seems to work as expected everywhere else that I have tested, it's just a physical iPad where I am seeing the issue, and only sometimes. I'm wondering if it's the particular webkit that runs on the iPad or some other issue. Environment is Chrome 126.0.6478.153 running on iPadOS 17.5.1.

@rachelandrew
Copy link
Contributor Author

@seannherdy this seems to be a browser issue rather than related to the issue you have commented on. Perhaps raise a WebKit bug https://webkit.org/reporting-bugs/

@rachelandrew
Copy link
Contributor Author

rachelandrew commented Dec 31, 2024

I've written up some proposed spec changes for the multicol level 2 spec, for block direction overflow, and discussed them with a few folks at Chrome. Posted in this comment for discussion, and I'll add to the agenda. If I can get a resolution on the general approach I'll add this into the level 2 draft (which has a new FPWD) and raise any individual issues that come up separately.

Notes on the approach

  • I’ve modeled this after flex-wrap as it seems the closest thing we already have.
  • When we rejigged multicol level 1 I preserved “row” as a name for doing this (rather than use it for the rows of columns created by a spanner) as then we can talk about it in terms familiar to flex and grid. Also, if people want to put a decorative line between rows, that would be the row created by this block fragmentation rather than a spanner (you can already decorate a spanner with borders and so on, if that's the visual effect you want).
  • I think that creating new rows gives us a nested fragmentation flow that behaves pretty much like what happens in paged media, so a lot of the things we need to spec and implement are roughly the same as what happens when a multicol is paged. For example, column-fill already deals with balancing the last fragment in fragmented contexts. I’ll need to go through the spec and make sure that we talk about paged media and "continuous media where column-wrap is wrap".

Relationship to other work

The carousel work prompted me to write this up, as it will be nice to do block direction carousels (though developers want this functionality anyway as it makes multicol more useful on the web). We’d need to be able to snap to the row fragment as for a column fragment.

The work on gap decorations, as it’s likely that developers will want to have lines between the rows as well as between columns as already mentioned.

Additions and changes to the multicol-2 spec

A new property: column-wrap

The overflow direction in continuous media: the column-wrap property

Name: column-wrap
Value: nowrap | wrap
Initial: nowrap
Applies to: multicol containers
Inherited: no
Percentages: n/a
Computed value: specified keyword
Canonical order: per grammar
Animation type: discrete

The column-wrap property controls the behavior of overflow columns in continuous media.

  • nowrap: Overflow columns are created in the inline direction.
  • wrap: Overflow columns create a new multicol row in the block direction.

Example:

body {
  column-count:3;
  block-size: 10em;
  column-wrap: wrap;
}

This would create a set of three columns. If there was more content than would fit in the 10em block-size of these columns, rather than overflowing in the line direction as currently happens, a new row of columns would be created in the block direction, again at a max block-size of 10em.

Changes to the columns shorthand

The column-width, column-count, and column-wrap Shorthand: The columns property

Name: columns
Value: <'column-width'> || <'column-count'> || <'column-wrap'>
Initial: see individual properties
Applies to: see individual properties
Inherited: see individual properties
Percentages: see individual properties
Computed value: see individual properties
Animation type: see individual properties
Canonical order: per grammar

This is a shorthand property for setting column-width, column-count, and column-wrap. Omitted values are set to their initial values.

Adding column-wrap here so that it's possible to set all three at once.

Changes to section Overflow

Content and column rules that extend outside column boxes at the edges of the multi-column container are clipped according to the overflow property.

A multicol container can have more columns than it has room for due to:

  • a declaration that constrains the column height (e.g., using height or max-height). In this case, additional column boxes are created according to the value of column-wrap.
  • the size of the page. In this case, additional column boxes are moved to the next page(s).
  • explicit column breaks. In this case, additional column boxes are created according to the value of column-wrap for continuous contexts and additional column boxes are moved to the next fragment(s) for fragmented media.

Other changes

  • Define rows in the section the multi-column model
  • multicol-2 defines the ::column pseudo-element. I think we'll also want to define ::row if we're scrolling in the block direction and stopping on rows.
  • There will be other places in the spec (anywhere mentioning paged vs continuous media) that need to refer to the value of column-wrap.

@kbabbitt
Copy link
Collaborator

Proposal lgtm overall and should mesh nicely with gap decorations.

For completeness and clarity: Is it also the intent that row-gap will apply to multicol containers? Assuming so, I think css-align-3 will also need to be updated. https://drafts.csswg.org/css-align-3/#gap-multicol:

multi-column containers
column-gap specifies the gutter between adjacent column boxes. See [CSS-MULTICOL-1] for details on how this affects the layout of multicol elements. row-gap does not currently apply.

(having said that, I also wouldn't mind if the specifications for how gaps apply to different container types were instead sharded out to the specs that define those container types)

@rachelandrew
Copy link
Contributor Author

Yes I think row-gap should apply, I guess the question would be whether it should match column-gap in multicol and normal be 1em, or match other gaps and be 0. I'll raise that as a separate issue, thanks for bringing it up.

@rachelandrew
Copy link
Contributor Author

Issue for row-gap: normal: #11539

@mstensho
Copy link

Looks good! One thing I don't get is why this would give us a nested fragmentation flow. It's still just one fragmentation context.

@astearns astearns moved this to FTF agenda items in CSSWG January 2025 meeting Jan 22, 2025
@astearns astearns moved this from FTF agenda items to Thursday afternoon in CSSWG January 2025 meeting Jan 28, 2025
@frivoal
Copy link
Collaborator

frivoal commented Jan 29, 2025

I (strongly) agree with the goal of this, but I have different proposal / syntax for getting here.

One thing I am not a fan of in the proposal in #2923 (comment) is how it handles (max-)height / block-size: say you set the height of your multicol to be 10em. Depending on how many rows you get, the actual height might be 20em, or 30em (+ the gap size), and that's weird. What we are constraining is not the height / block-size of the multicol, it's the height / block-size of the rows, so using the height / block-size property seems off to me: that should care about the multicol as a whole, and a separate property should care about the height of the rows. Based on that notion, here's an outline my alternative proposal:


The multi-col container contains at one or more column-row box, which in turn, contain column lines (themselves containing column boxes), as described in multi-col 1.

If there is more than 1 column row box, they stack up in the block axis, separated by a gutter whose size is determined by 'row-gap'.

If 'column-rule' is set, a rule is drawn in the row gaps as well as in the column gaps.

Name: columns
Value: <'column-width'> || <'column-count'> [ / <'column-row-height'> ]?

name: column-row-height
value: auto | <length [0,∞]>
initial: auto

Sets available space in the block direction for column boxes, effectively acting as a cap on column box height.

auto: the available space is equal to the min inner height of the multicol container.

When 'column-row-height' has a value other than ''column-row-height/auto'',
[=overflow columns=] are not added in the inline direction.
Instead, additional column rows are created as needed
to host the excess columns.

If you set both column-row-height to a non-auto value and height, your may have some leftover space in your multicol. https://drafts.csswg.org/css-align would tell you how to deal with it. (Details of how that works are interesting, but secondary to the concept as a whole.)

example

article {
columns: 3 20em / 80vh;
gap: 1em 2em;
}

****** ****** ******
****** ****** ******
****** ****** ******
****** ****** ******
****** ****** ******

****** ****** ******
****** ****** ******
****** ******
****** ******
****** ******

Notes:

  • This could also be extended to have a column-row-count property, but I find the use cases less convincing, so I didn't include it.
  • In a way, there's an implied column-wrap: auto | nowrap | wrap underlying this, where auto is the initial value, which resolves to nowrap if column-row-height is auto, and to wrap if not. I had it in my initial draft, but in practice I don't think there's much use for values other that auto, so I think this should not be exposed, at least in an initial version.

@mstensho
Copy link

I (strongly) agree with the goal of this, but I have different proposal / syntax for getting here.

One thing I am not a fan of in the proposal in #2923 (comment) is how it handles (max-)height / block-size: say you set the height of your multicol to be 10em. Depending on how many rows you get, the actual height might be 20em, or 30em (+ the gap size), and that's weird. What we are constraining is not the height / block-size of the multicol, it's the height / block-size of the rows, so using the height / block-size property seems off to me: that should care about the multicol as a whole, and a separate property should care about the height of the rows.

I don't think that was how it was meant to be read. The actual multicol height will be 10em, but it will be overflown with any additional rows. Using height / block-size both for sizing the multicol container and its rows does limit the possible uses, indeed. The use case it does support quite conveniently is when the multicol container has scrollable overflow. If it doesn't have scrollable overflow, the overflow will just overlap with subsequent content and look bad.

Based on that notion, here's an outline my alternative proposal:

[...]

name: column-row-height value: auto | <length [0,∞]> initial: auto

Sets available space in the block direction for column boxes, effectively acting as a cap on column box height.

auto: the available space is equal to the min inner height of the multicol container.

When 'column-row-height' has a value other than ''column-row-height/auto'', [=overflow columns=] are not added in the inline direction. Instead, additional column rows are created as needed to host the excess columns.

If you set both column-row-height to a non-auto value and height, your may have some leftover space in your multicol. https://drafts.csswg.org/css-align would tell you how to deal with it. (Details of how that works are interesting, but secondary to the concept as a whole.)

[...]

  • In a way, there's an implied column-wrap: auto | nowrap | wrap underlying this, where auto is the initial value, which resolves to nowrap if column-row-height is auto, and to wrap if not. I had it in my initial draft, but in practice I don't think there's much use for values other that auto, so I think this should not be exposed, at least in an initial version.

If column-row-height is auto, I really think we want to have a way of controlling where the overflow goes.

<div style="overflow:scroll; columns:3; column-fill:auto; height:100px;">
  [... lots of text ...]
</div>

This will create additional columns in the inline direction. Back to the original use case, where we don't want to specify a column row size, but want overflowing content to establish additional rows, rather than creating overflowing columns in the inline direction... We want a way of achieving that. I think column-wrap is needed for that.

Quite oppositely of what you're thinking, I'm not sure what the auto value would be used for, but I see strong use cases for the two other values. :)

A column-row-height property would allow for some "interesting" scenarios in nested fragmentation, since this new thing "column rows" isn't the same as what happens when breaking inside a nested block fragmentation context:

<!DOCTYPE html>
<div style="columns:4; column-fill:auto; width:460px; height:100px; gap:20px; line-height:20px; orphans:1; widows:1;">
  <div style="columns:2; column-fill:auto; column-row-height:120px; background:hotpink;">
    <div style="background:cyan;">
      A<br>B<br>C<br>D<br>E<br>
      F<br>G<br>H<br>I<br>J<br>
      K<br>L<br>M<br>N<br>O<br>
      P<br>Q<br>R<br>S<br>T<br>
      U<br>V<br>W<br>X<br>Y<br>
      Z<br>Æ<br>Ø<br>Å<br>1<br>
      2<br>3<br>4<br>5<br>6<br>
    </div>
  </div>
</div>

Image

Should it look like this?

@kizu
Copy link
Member

kizu commented Jan 29, 2025

I agree with @frivoal that using (max-)height/block-size for this feels weird, especially when you start thinking about stuff like calc-size() and animating the block-size of the columns’ container with interpolate-size: allow-keywords.

And yes, “If it doesn't have scrollable overflow, the overflow will just overlap with subsequent content and look bad.” is something we'd want to avoid, and the case with the overflow is a good one, as I don't think we want the element to have different outer dimensions based on if it is visible or auto, for example.


There is another thing that I would like to throw in. It could be totally to be something for the future level of the spec, but I felt that this is something that also points to using a different property to control the block direction rather than the height/block-size. It is that there might be cases where you'd want each row created this way to be different. If we'd want to control this via something similar to grid-template-rows, where we could define either a static value (as described now), or a pattern that would include repeat(), it could unlock some more interesting layouts.

If we think about the overflow in block direction as “pages” and think about print, then this is not a use case that comes to mind, but when translated to a web page, having dynamic rows can make more sense. Although, maybe at this point we're going closer to regions :) But I wanted to mention this possible extension as something that would be harder to do with just height/block-size.

@rachelandrew
Copy link
Contributor Author

I think one concern I have with having a separate value for the block size, is that we then end up with situations such as an author wanting overflow in the block direction, setting a height on the multicol, and the row height however there still isn't enough space in the multicol container for all of the rows (due to the height). What happens then?

The dev ergonomics currently are:

  1. Set a height.
  2. Get overflow columns in the inline direction

The future spec (my version)

  1. Set a height
  2. Choose whether to get overflow columns in the inline or block direction, by setting them to wrap.

Multicol is a pretty simple thing, in terms of how it's used. I get that having a separate size for rows might open up a bunch of other possibilities, but are they possibilities that anyone actually needs for multicol? Or are we just making the spec more complex because it might be nice to do that stuff at some point.

That said, I'm not completely against the idea, and we should discuss it, I'm just wary of making something complex for the sake of it. We have more complex layout methods, we could potentially introduce something more like regions to do the more complex fragmented cases ... I'm thinking we probably don't want to morph multicol into something that does bits of regions-like things, but never really fulfils that idea.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-multicol] Overflow in the block direction for continuous media, and agreed to the following:

  • RESOLVED: start specifying column-height
The full IRC log of that discussion <nicole> rachelandrew: speccing overflow in block direction for multicol
<nicole> rachelandrew: partially becuases of the carousel work, and partially because it can go in different directions. Rachel put proposed spec in the issue as a starting point
<nicole> rachelandrew: modeled after flex
<astearns> proposal: https://github.com//issues/2923#issuecomment-2566448417
<nicole> rachelandrew: modeled after logical container. Instead you could opt to use column wrap
<fantasai> +1 for a row-height property
<astearns> florian's: https://github.com//issues/2923#issuecomment-2620334162
<nicole> rachelandrew: has a different proposal. what should we do, which looks best?
<florian> q+
<astearns> ack florian
<nicole> florian: want to have this ability. multicol having overflow columns in inline dir isnt' what people want most of the time. Having multiple rows of multicol is extremely desirable.
<nicole> florian: constrain height, overflow in block direction rather than inline direction
<kizu> q+
<nicole> florian: are they simply overflowing. Will they clash? Or whether you simply grow the multicol despite the constrained height
<nicole> florian: should the rows add height?
<nicole> florian: proposes a new prop to constrain the height of the row of the multicol. column-height or column-row-height would work well.
<nicole> florian: column-row-height: 10em
<nicole> florian: if you also set the multicol height, you use all the css tools to deal with how to lay them out
<TabAtkins> yup, +1 to column-row-height
<nicole> florian: not sure what short hands should be
<astearns> ack fantasai
<nicole> florian: how to make it work with gap and other properties needs to be worked out
<florian> q+
<nicole> fantasai: doesn't want an overflow model for this feature (in flow content). Don't conflate sizing the box with content inside the box. Prop that sets column height is the right thing to do
<astearns> ack kizu
<TabAtkins> ah yeah, column-height is shorter and just as right
<astearns> q+
<nicole> fantasai: likes column-height
<nicole> roman: wants this feature. Could imagine automatically fragmenting so that each item goes into the overflow container
<astearns> ack florian
<nicole> roman: use case to fit everything in viewport so it paginates properly
<nicole> florian: not incompatible with having a property
<TabAtkins> (i do think it would be nice to have a `column-height: auto` that matches the height of the nearest scroller)
<fantasai> s/use case/but more common is use case of having it in-flow,/
<nicole> florian: if you set it to auto it would go in the block direction otherwise inline
<nicole> florian: row-height instead of column-height because we might want to use column-row-count later, but won't insiste
<rachelandrew> q+
<nicole> fantasai: column-height and column-width as a pair seems better
<nicole> fantasai: authors won't think about columns as explicitly as rows
<florian> q+
<nicole> astearns: florian mentioned overflow in inline dir, but thinks it is the wrong way to talk about it. We are fragmenting in the inline direction or block direction. As you fragment columns now they can overflow in inline direction.
<nicole> astearns: when we add this you will be able to fragment in the block direction
<nicole> astearns: but it also might overflow, to put the content in the new contents
<nicole> florian: agree overflow isn't quite the right word. Neither is fragmentation. Fragmenting the content of the multicol, and deciding where to place them. Whether they overflow depends where you place them and what else is there.
<nicole> florian: rachelandrew proposed column wrap, whatever we call it, they describe where the extra content goes (block or inline direction)
<astearns> ack rachelandrew
<astearns> ack astearns
<astearns> ack florian
<nicole> astearns: doesn't agree with fantasai that ___ will be rare, he thinks authors will want to do it at the outset
<nicole> rachelandrew: what happens if you have set a height on multicol and then you set column height and row height. And then you have too many things to fit in the container. Answer could be that it overflows
<nicole> florian: yes
<astearns> s/___ /choosing how many rows of columns you want/
<florian> q+
<astearns> ack florian
<nicole> rachelandrew: are we bringing in too much extra complexity? Is it getting to be like regions. Not against direction, just concerned about complexity.
<nicole> florian: yes it would overflow, like any content that doesn't fit would
<nicole> florian: doesn't matter how many rows cols you put in there
<nicole> florian: if it is too big, you have other tools to deal with extra space
<TabAtkins> I definitely think tying this explicitly to overflow *is* making it too complex. Just adding more columns to the content seems like the most straightforward way
<nicole> astearns: proposed resolution to start specifying this using column-height
<nicole> rachelandrew: happy with that
<kbabbitt> 👍
<nicole> RESOLVED: start specifying column-height

@rachelandrew
Copy link
Contributor Author

@frivoal I think we do still need the wrap property as a trigger.

If we give people the ability to use the alignment properties when there is extra space in the container, I can imagine people wanting to use that with inline overflow columns. So to set a column-height, and a container height, keep the inline columns and use the extra space somehow.

If we're going for the column-height version I think we should allow it to work both ways, therefore the switch does need to be something else, probably column-wrap. That seems cleaner to me anyway, and makes it explicit that you want wrapping, rather than the magic happening because you set a column-height.

@rachelandrew
Copy link
Contributor Author

I've added an initial draft in 29b1f61

This also includes my suggestion for keeping column-wrap as the trigger. I have not gone through the entire spec and updated all the places that need changing based on adding block direction overflow, as I'd like to get a resolution on column-wrap first, as that's going to at the very least change how we describe the feature elsewhere.

I raised #11754 to explain why I think we need column-wrap and a secondary issue should we adopt that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Thursday afternoon
Development

No branches or pull requests