4

I have a multi-column div (2-4 columns depending on a setting in my app) generated live by user-provided markdown in a text editor. In some cases, they want to manually insert column breaks. To achieve this, I provide a Markdown snippet that generates a div with the CSS property break-after: column to manually trigger column breaks. It works fine if it is set to display: block. However, if the user then inserts a div that spans both columns (with CSS column-span: all), that column-spanning element gets shunted to below its containing element, and any further text disappears entirely, as follows (in the latest version of Chrome, specifically):

.container {
  column-count: 2;
  height: 60mm;
  border: solid black 1px;
}

.container .colbreak {
 color: red;
 break-after: column;
}

.container .wide {
  color: blue;
  column-span: all;
}
<div class="container">

  <p>left left left</p>
  <p>left left left</p>
   
  <div class="colbreak">Column Break</div>
  
  <p>right right right</p>
  <p>right right right</p>
  <p>right right right</p>
  <p>right right right</p>
  <p>right right right</p>

  <div class="wide">
    span all span all span all
    span all span all span all
    span all span
  </div>
  
  <p>more columns after</p>
  <p>more columns after</p>
  <p>more columns after</p>
  <p>more columns after</p>

</div>

This is what it looks like (note the "more columns after" paragraphs are missing):

Broken Wide

Changing the colbreak to have display: inline-block or otherwise just seems to ignore the break-after: column altogether (perhaps this is the real question: Why is break-after ignored for my inline-block element?:

Column Break Ignored?

As shown below, I get the same behavior by simply not including the colbreak div at all:

No Column Break

Can anyone explain how to achieve the desired behavior? Since this is being rendered live as the user types it in, I would like to maintain the automatic balancing of columns by not requiring a separate div for each column. Calculating text length and height and moving them between columns on the fly as it is typed seems more trouble than it's worth. This also stops working if the user changes to a setting with

Trevor Buckner
  • 588
  • 2
  • 13

3 Answers3

2

How to achieve close to desired result:

I think css-multicol will be good read if you want to understand bit more about multi-column css support.

Main issue with your current css is height in container. To fix that, you can put container inside another div and style it with your desired style, that will give you as much as you can get close to your desired result.

.main-container {
  height: minmax(min-content, 100mm);
  overflow: auto;
  border: solid black 1px;
}

.container {
  column-count: 2;
}

.container .colbreak {
  color: red;
  break-after: column;
}

.container .wide {
  color: blue;
  column-span: all;
}
<div class="main-container">
  <div class="container">
    <p>left left left</p>
    <p>left left left</p>

    <div class="colbreak">Column Break</div>

    <p>right right right</p>
    <p>right right right</p>
    <p>right right right</p>
    <p>right right right</p>
    <p>right right right</p>

    <div class="wide">
      span all span all span all span all span all span all span all span
    </div>

    <p>more columns after</p>
    <p>more columns after</p>
    <p>more columns after</p>
    <p>more columns after</p>
  </div>
</div>

Why height on container is not working as expected?

I believe that is by design, at least from my understanding based on reading the spec, which says:

An element that spans more than one column is called a spanning element and the box it creates is called a spanner.

A spanning element is taken out-of-flow, leaving a forced break. This does not affect the painting order [CSS21] of the spanning element.

Update:

Why is break-after ignored for my inline-block element?:

That is because break-word is supposed to be working only for block-level elements as per W3C guidelines.

Original answer: You need to wrap your column content into separate div and apply column-count style to that div and it will work.

.container {
  height: 100mm;
  border: solid black 1px;
}

.col2 {
  column-count: 2;
}

.container .colbreak {
  break-after: column;
}

.container .wide {
  color: blue;
  column-span: all;
}
<div class="container">
  <div class="col2">
    <p>left left left</p>
    <p>left left left</p>
    <p>left left left</p>

    <div class="colbreak">Column Break</div>

    <p>right right right</p>
    <p>right right right</p>
    <p>right right right</p>
    <p>right right right</p>
    <p>right right right</p>
    <p>right right right</p>
    <p>right right right</p>
  </div>
  <div class="wide">
    span all span all span all span all span all span all span all span all span all span all span all span all span all span all span all
  </div>

</div>

or you can use CSS grid:

.container {
  height: 100mm;
  border: solid black 1px;
  display: grid;
  grid-template-columns: 50% 50%;
}

.container .wide {
  color: blue;
  grid-column-start: 1;
  grid-column-end: -1;
}
<div class="container">
  <div>
    <p>left left left</p>
    <p>left left left</p>
    <p>left left left</p>
  </div>
  <div>
    <p>right right right</p>
    <p>right right right</p>
    <p>right right right</p>
    <p>right right right</p>
    <p>right right right</p>
    <p>right right right</p>
    <p>right right right</p>
  </div>
  <div class="wide">
    span all span all span all span all span all span all span all span all span all span all span all span all span all span all span all
  </div>
</div>
Dipen Shah
  • 25,562
  • 1
  • 32
  • 58
  • This was something we tried early on, but as you can see, the column break no longer occurs at the desired location (some of the "right right right" paragraphs are on the left side). It seems the "break-after: column" is simply ignored when we change the display type of the `colbreak` div. – Trevor Buckner Oct 30 '20 at 16:37
  • 1
    @TrevorBuckner I misunderstood a bit, let me update the anwer. – Dipen Shah Oct 30 '20 at 16:38
  • wrapping column content in a separate div will give you desired behavior. – Dipen Shah Oct 30 '20 at 16:57
  • 1
    This is an interesting option. Essentially, we just remove the `wide` div from the 2-column block. If possible though, I would like to allow additional text after the `wide` block that resumes 2-column behavior. This HTML is generated live from user-provide markdown in a textbox, so reducing the complexity of multiple divs would be ideal if possible (a new div each time we swap between 2-column). I think the key for solving this might actually be: "Why is break-after ignored when my element uses `display: inline-block`?" See my updated question. (This is good though and is giving me ideas) – Trevor Buckner Oct 30 '20 at 17:36
  • 1
    @TrevorBuckner check my updated answer, `break-after` is is supposed to be working only for `block-level` elements and not inline. – Dipen Shah Oct 30 '20 at 19:07
2

You could try separating the columns into 2 divs. It will separate them, allowing to style them as individual columns rather than having to insert a break.

.column {
  float: left;
  width: 50%;
}
<div class="container">
  <div class="column">
    <p>left left left</p>
    <p>left left left</p>
    <p>left left left</p>
  </div>

  <div class="column">
    <p>right right right</p>
    <p>right right right</p>
    <p>right right right</p>
    <p>right right right</p>
    <p>right right right</p>
    <p>right right right</p>
    <p>right right right</p>
  </div>

  <div class="wide">
    span all span all span all span all span all span all span all span all span all span all span all span all span all span all span all
  </div>
</div>
Dipen Shah
  • 25,562
  • 1
  • 32
  • 58
afor94
  • 21
  • 3
  • Hmmm... If possible, I would like to avoid separate `div`s for each column since it removes the natural column-breaking behavior once the text reaches the bottom of the container. But so far this looks like it captures the desired behavior the best and might be doable.... – Trevor Buckner Oct 30 '20 at 16:42
  • in all honesty you could do a table with 2 columns as well, and have the bottom row colspan = 2 – afor94 Oct 31 '20 at 02:19
0

Would suggest you restructure your HTML code and use flexbox. It will give you more control over the position of your divs and the way you want to play with it's content. Also, it is very easy to go responsive with flexbox.

.container{
  width: 50%;
  border: 1px solid black;
}

.container .flex {
  display:flex;
  flex-direction: row;
  justify-content: space-around;
}

.container .wide {
  color: blue;
  column-span: all;
}
<div class="container">
  <div class="flex">
    <div>
  <p>left left left</p>
  <p>left left left</p>
  <p>left left left</p>
   <p>left left left</p>
 
   <p>left left left</p>
  <p>left left left</p>
  <p>left left left</p>
   <p>left left left</p>
  <p>left left left</p>
  <p>left left left</p>
   
  <div class="colbreak">Column Break</div>
  </div>
  <div class="flex-2">
  <p>right right right</p>
  <p>right right right</p>
  <p>right right right</p>
  <p>right right right</p>
  <p>right right right</p>
  <p>right right right</p>
  <p>right right right</p>
  </div>
</div>

<div class="wide">
  
  span all span all span all
  span all span all span all
  span all span all span all
  span all span all span all
  span all span all span all
</div>
</div>
Dhruvi Makvana
  • 895
  • 5
  • 17
  • Thanks for the answer. If possible, I would like to avoid separate divs for each column since it removes the natural column-breaking behavior once the text reaches the bottom of the container. – Trevor Buckner Oct 30 '20 at 17:27
  • Can you explain more on column-breaking behavior because flexbox is flexible and will be in the same layout irrespective of content within. – Dhruvi Makvana Oct 30 '20 at 17:39
  • Sure. Normally in a 2-column div, you can type and type and your text will automatically be split into two columns. Since this HTML is being generated live from user-provided markdown in a text box, it is ideal that the text reflow between columns automatically, rather than trying to sort and balance text into two flexboxes on the fly. Does that clarify? (See updated question) – Trevor Buckner Oct 30 '20 at 17:46