Section breaks for very long CSS columns
Asked Answered
C

2

14

Using CSS columns I can format contiguous data into columns without having to manually break it into sections. This is especially useful when displaying complex, dynamic content.

However when the columns' content is so long that their height is greater than the viewport, dividing into columns makes for a poor reading experience. When the reader reaches the bottom of one column they must manually scroll up to begin reading the next.

In traditional print layouts, readability issues with very long columns are generally mitigated by breaking the columns into sections that 'restart' the column. (Physical pages themselves form a natural separation that the endlessly scrolling webpage does not have). The image below shows how horizontal section breaks makes columnar content that is longer than the height of the viewport more readable.

enter image description here

(Note that by 'restart the columns' I mean that once you reach the end of a left-hand column section you then read the right-hand column of that section before scrolling down to read both columns of the next section. https://www.shutterstock.com/image-vector/newspaper-template... might illustrate it more clearly).

There are very few guarantees for the column content. It may contain any number of paragraphs, images, nested block elements, nested inline elements and so on. Example markup is shown below.

.columns {
  columns: 2 200px;
}
.columns * {
  max-width: 100%;
}
<div class="columns">
  <div class="introduction">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas posuere dictum tincidunt. Cras in lectus eget libero suscipit venenatis at sit amet dolor. Donec tempor cursus justo, volutpat sodales dolor tempor eu.</p>
    <p class="a-class">Pellentesque nec tempor sapien, sed vehicula sem. Ut pretium leo eget nisi cursus viverra. Ut ultrices porta nibh, sed laoreet felis condimentum sit amet. Aliquam a felis nec urna dignissim placerat sed sit amet elit. Donec elementum sagittis purus, facilisis convallis urna dapibus eu. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam erat volutpat. Phasellus vel placerat metus. In efficitur enim eget lacinia ultrices. Duis ultricies dignissim nisi, id ultricies nulla venenatis vitae.</p>
  </div>
  <img src="https://i.kym-cdn.com/entries/icons/original/000/016/546/hidethepainharold.jpg">
  <div class="body" style="">
    <p>Suspendisse quis ante ullamcorper, lobortis orci ut, vestibulum dolor. Aenean sit amet purus commodo, sagittis leo vel, consequat nisi. Vestibulum sit amet sem vitae sapien pulvinar finibus. Ut sapien purus, luctus condimentum iaculis quis, lobortis at elit. Cras nulla ante, scelerisque ut aliquet in, elementum vel turpis. Vestibulum ipsum magna, congue sit amet sodales vel, aliquam vel nunc. <img src="https://upload.wikimedia.org/wikipedia/commons/e/e0/SNice.svg" width="100"> Sed eu dapibus nulla. In ut libero sit amet elit elementum gravida. Suspendisse quis quam consequat, pretium felis vel, laoreet turpis. Proin fringilla lobortis magna. Duis quam sapien, sodales nec accumsan id, ullamcorper eget tellus. Aliquam vitae orci cursus, porttitor ligula ut, fringilla odio. Donec a lorem ac eros interdum varius ultricies quis nulla.</p>
  </div>
  <p contenteditable="true">Nunc in elit tincidunt, ultrices massa sed, ultricies elit. In nec accumsan metus. Nullam ultricies eget tortor ut malesuada. Fusce in elit sit amet dolor bibendum malesuada.</p>
  <div style="display:none">
    <p>Curabitur sed hendrerit massa, vitae porta enim.</p>
  </div>
  <div><div><span>hey</span><div id="an-id">
    Nullam ultricies eget tortor ut malesuada. Fusce in elit sit amet dolor bibendum malesuada. Nulla sed nisi vel nulla aliquam blandit. Nam vel tellus ut libero ultrices volutpat. Curabitur blandit quis arcu rutrum ullamcorper. Cras et pharetra augue, eget eleifend sem.
    <img src="https://socialnewsdaily.com/wp-content/uploads/2018/08/Webp.net-resizeimage-27.jpg">
  </div></div></div>
  <p>
    Mauris accumsan condimentum porttitor. Quisque tellus justo, suscipit sit amet posuere in, scelerisque nec orci. Aenean iaculis nisi in porta viverra. Sed eget ultricies nibh. Donec accumsan laoreet interdum. Donec risus mauris, dapibus et pulvinar at, posuere non nisi. Mauris at viverra nunc. Ut laoreet suscipit erat et cursus. Aenean id lacus volutpat lectus condimentum posuere. Nam ut lectus elit. Morbi sagittis elementum libero. Donec congue dolor sed tristique efficitur.
  </p>
  <p>
    <div>
      <p>Sed elementum velit sapien, et tristique justo bibendum at. Aliquam tincidunt magna nec nisi congue varius. Etiam dolor eros, rhoncus quis purus a, tempus malesuada quam. Sed bibendum condimentum eros vitae varius. Donec fermentum magna vel tellus tempus, nec finibus neque fermentum. Mauris tempus nisl sit amet lacus fermentum, at egestas urna egestas.</p>
      <p>Interdum et malesuada fames ac ante ipsum primis in faucibus. Suspendisse ultrices lectus vitae nisl congue, sed porta dolor luctus. Donec aliquet at sapien sit amet tincidunt. Mauris vestibulum consectetur augue at imperdiet.</p>
    </div>
  </p>
</div>

I would like to automatically break my columns into regular sections after the columns reach a maximum height, as in the image above.

I have not found any property that controls the layout of CSS columns in this way. CSS regions look promising but have very poor browser support.

Computing the height of content with JavaScript and then inserting wrappers for each column block is probably possible, but not ideal. The content is dynamic and may change at any time, meaning the function must be run on every change. In addition the content may be very complex with sub elements that need to traverse section breaks, so naively inserting wrappers for each section will likely break the layout.

How can I automatically set section breaks for columnar content after a maximum height? (I am not married to the idea of CSS columns; perhaps a creative use of flex or inline-block will give the result I need).

Cathryncathy answered 10/8, 2019 at 0:4 Comment(9)
Have you tried, instead of using the literal columns property, using something like display: flex with flex-wrap: wrap and then a max-height on the child items? Does that not work well because of the dynamic nature of the content?Jehanna
For flex columns to work, each column would need to be wrapped in a containing element. Otherwise if my content was, for example, a series of paragraphs, each <p> would be placed in its own column. Processing the content to be placed in column elements is very difficult if the content has sub elements of its own as the sub elements may need to traverse a column break.Cathryncathy
@jla, could you, please, provide a demo in the question description to shed some light on your markup structure?Decurrent
@ViacheslavMoskalenko updated the question with a demoCathryncathy
Would adding "possible break point" in the content be acceptable (or not automatical enough) ? I guess it depends on how your content is added. If it's ok to do it that way, I may have a solution using grid and display : contents on those 'possible break points".Lauzon
Not sure what you mean by "possible break point". I'm intrigued by CSS grid; I'd prefer to support at least IE 11 but if display: contents is the way to go then so be it.Cathryncathy
By break points i meant adding in your html/content p or div tag that could be "activated" to break the content if certain conditions are met. Switching between display: contents and display: block would allow to make the "box" of those breakpoint appear or disapear thus creating a new grid row. The but being.. how are those possible break points/tags inserted meaninfuly .. if manualy then its not fully automatedLauzon
@Pierre-Yves The column content is created by end users and at the moment they can't enter such breakpoints manually. My fallback option is to give the users a tool to manually insert such breakpoints, but I'm looking for a way to format the column section breaks automatically and at intervals of equal height. It's looking like CSS has reached its limits here and automatic section breaks will need to be inserted with JavaScript. Column section breaks are quite common in print layouts so this seems like an oversight in the design of CSS columns..Cathryncathy
Yes, I saw the newspaper image afterward. You should put it in you question, personally that's what made me understand what you wantedLauzon
D
4

There's actually a pretty simple solution using CSS columns. And the column-span attribute.

You can achieve all of this WITHOUT injecting anything into the content and simply styling HTML tags.

Basically, the CSS Columns Layout Module is intended to replicate print design layouts (like a newspaper) where the stylistic rule is that headlines should cross all columns of a story. Therefore any element with column-span: all will separate columns and cause the wrapping to reset. (notice the colors in my example show the wrap).

In this case, since you don't control the content its best to provide a common structure to your users. For example, I'd set H1, H2, H3 tags as well as <hr> and maybe some images to break columns. Allow your users to implement these tags as they normally would in writing and you'll achieve a nice layout. However, if they decide NOT to implement any of that stuff, that's up to them and you should let it wrap and cause a long scroll. (I might also suggest providing a preview so they can see what the result will look like)

Example of column-span

.columns {
	margin: 30px;
	columns: 2;
}

h1, h2, h3, h4, h5 {
	column-span: all;
}



// simply to show where things wrap
h2 {
	background-color: #eee;
	padding: 5px 10px;
}

h5 {
	border-bottom: 1px solid #ddd;
	padding-bottom: 5px;
	text-align: center;
}

p:nth-of-type(1) {
	color: blue;
}

p:nth-of-type(2) {
	color: green;
}

p:nth-of-type(3) {
	color: orange;
}
p:nth-of-type(4) {
	color: teal;
}
<div class="columns">
	<p>
		Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras venenatis tellus non nunc tincidunt, vitae rutrum metus dapibus. Fusce at ante massa. Nam et nibh aliquet, porta nibh quis, rhoncus tortor. Aenean vestibulum neque sed urna lacinia aliquet.
		Vestibulum facilisis egestas commodo. Cras sed maximus odio. Mauris posuere, ante id posuere facilisis, ligula libero consectetur lacus, at pellentesque nibh elit at magna. Proin sollicitudin quis nibh at viverra. Duis feugiat, lorem vitae facilisis
		blandit, augue tortor cursus orci, sed porttitor eros elit at sapien. Quisque eleifend pulvinar pellentesque.
	</p>

	<h2>This is a header (h2) with column-span: all set on it</h2>

	<p>
		Donec blandit sapien leo, id aliquam purus vulputate a. Sed vel turpis ut eros suscipit blandit vel id eros. Nullam ut mauris luctus magna sollicitudin venenatis. Pellentesque leo mauris, malesuada nec purus ut, vestibulum malesuada lectus. Nullam ultricies
		tellus sapien, ut fermentum risus pretium a. Nullam magna urna, ullamcorper non congue a, efficitur nec orci. Ut aliquam molestie nisi. In at accumsan purus. Etiam non tempor ipsum. Maecenas gravida mauris in nibh vehicula ullamcorper. Sed libero lorem,
		faucibus eu lorem ut, gravida eleifend enim. Nunc vehicula fermentum consequat. Phasellus a pellentesque nisl. Nulla vel suscipit nibh, ac cursus dui. Suspendisse elementum dapibus risus. Nam egestas congue finibus.
	</p>

	<p>
		Nunc vel risus nec nulla dignissim congue. Cras sit amet lacus nec nisl mollis pellentesque in vel purus. Suspendisse efficitur mollis nibh, congue facilisis libero auctor ac. Nulla facilisi. Etiam ut erat eget erat egestas suscipit. Curabitur vitae varius
		mauris. Sed accumsan diam eros, id dapibus metus rutrum at. Nunc vitae pretium massa. Aenean quis mauris leo. Nulla egestas ligula eu libero interdum feugiat. Aliquam maximus erat et tortor auctor varius. Nulla in pharetra leo, vel suscipit nunc. Orci
		varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec nec egestas ante, vitae sollicitudin arcu. Pellentesque posuere tempus nibh, nec tempus eros pellentesque ac.
	</p>

	<p>
		Curabitur tempus massa dolor, nec congue purus efficitur id. Phasellus a dictum mauris. In porta nulla lectus, pretium semper erat semper id. Fusce ornare fringilla mi, ut auctor tortor semper non. Aliquam sed felis fermentum, molestie dolor vel, eleifend
		diam. Donec accumsan bibendum mi, sed pretium tortor pulvinar nec. Aliquam et metus accumsan, pretium neque eu, elementum ipsum. Nam dapibus risus sed velit viverra, non consequat nibh pretium. Morbi nec gravida turpis. Quisque convallis justo ut rhoncus
		porttitor. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
	</p>
	<h5>This is a header (h5) with column-span: all set on it</h5>
	<p>
		Proin fringilla, sapien molestie mattis commodo, leo ligula viverra massa, eget semper leo purus sit amet est. Quisque eu diam interdum, pretium dui sed, dictum sem. Sed cursus eu est in ultrices. Suspendisse eleifend imperdiet lectus eu consectetur.
		Duis semper libero nec magna commodo, sollicitudin pharetra magna luctus. Fusce pellentesque sollicitudin dolor, eu scelerisque elit condimentum vel. Curabitur id condimentum nisi, eu rhoncus arcu. Proin metus purus, condimentum nec semper vitae, blandit
		at leo. Proin commodo et ipsum ac euismod. Aliquam erat volutpat. Nam neque nisi, ornare sit amet metus ac, faucibus tempor nulla. Quisque tristique malesuada finibus. Praesent fermentum posuere urna, a blandit risus sollicitudin nec.
	</p>

</div>
Douse answered 15/8, 2019 at 16:42 Comment(3)
column-span doesn't work in Firefox unfortunately. 9 year old bug on bugzilla hereRepulse
True but FF doesn't really support CSS column in general (at least parity with other browsers) and the OP decided to use it anyway... At the end of the day, crossing columns is technically progressive enhancement.Douse
This does seem to be getting close to what I'm wanting. Getting column-spans at regular intervals so that the column sections are equally spaced with the same maximum height will probably require some JavaScript, but the column-span property does seem to be the way forward. It's a huge shame about FF support - and incredible that IE10 supports it unprefixed!Cathryncathy
C
1

Using 'break-inside: avoid;' each paragraph

In the solution I attached, I gave each DIV a break-avoid class to avoid breaking in the middle of the paragraph.

Like you asked, if the paragraph is not over yet you can scroll down. I added a gray color that you can see in the paragraphs.

You can control when it will break and you can also insert a div into a div if you want it in sequence.

Hope the solution is effective for you.

.columns {
  columns: 5 250px;
}
.columns * {
  max-width: 100%;
}
.break-avoid{
  break-inside: avoid;
  background-color: #ccc;
}
<div class="columns">
  <div class="introduction break-avoid">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas posuere dictum tincidunt. Cras in lectus eget libero suscipit venenatis at sit amet dolor. Donec tempor cursus justo, volutpat sodales dolor tempor eu.</p>
    <p class="a-class">Pellentesque nec tempor sapien, sed vehicula sem. Ut pretium leo eget nisi cursus viverra. Ut ultrices porta nibh, sed laoreet felis condimentum sit amet. Aliquam a felis nec urna dignissim placerat sed sit amet elit. Donec elementum sagittis purus, facilisis convallis urna dapibus eu. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam erat volutpat. Phasellus vel placerat metus. In efficitur enim eget lacinia ultrices. Duis ultricies dignissim nisi, id ultricies nulla venenatis vitae.</p>
  </div>
  <img src="https://i.kym-cdn.com/entries/icons/original/000/016/546/hidethepainharold.jpg">
  <div class="body break-avoid" style="">
    <div>
    <p>Suspendisse quis ante ullamcorper, lobortis orci ut, vestibulum dolor. Aenean sit amet purus commodo, sagittis leo vel, consequat nisi. Vestibulum sit amet sem vitae sapien pulvinar finibus. Ut sapien purus, luctus condimentum iaculis quis, lobortis at elit. Cras nulla ante, scelerisque ut aliquet in, elementum vel turpis. Vestibulum ipsum magna, congue sit amet sodales vel, aliquam vel nunc.Suspendisse quis ante ullamcorper, lobortis orci ut, vestibulum dolor. Aenean sit amet purus commodo, sagittis leo vel, consequat nisi. Vestibulum sit amet sem vitae sapien pulvinar finibus. Ut sapien purus, luctus condimentum iaculis quis, lobortis at elit. Cras nulla ante, scelerisque ut aliquet in, elementum vel turpis. Vestibulum ipsum magna, congue sit amet sodales vel, aliquam vel nunc.Suspendisse quis ante ullamcorper, lobortis orci ut, vestibulum dolor. Aenean sit amet purus commodo, sagittis leo vel, consequat nisi. Vestibulum sit amet sem vitae sapien pulvinar finibus. Ut sapien purus, luctus condimentum iaculis quis, lobortis at elit. Cras nulla ante, scelerisque ut aliquet in, elementum vel turpis. Vestibulum ipsum magna, congue sit amet sodales vel, aliquam vel nunc.Suspendisse quis ante ullamcorper, lobortis orci ut, vestibulum dolor. Aenean sit amet purus commodo, sagittis leo vel, consequat nisi. Vestibulum sit amet sem vitae sapien pulvinar finibus. Ut sapien purus, luctus condimentum iaculis quis, lobortis at elit. Cras nulla ante, scelerisque ut aliquet in, elementum vel turpis. Vestibulum ipsum magna, congue sit amet sodales vel, aliquam vel nunc. <img src="https://upload.wikimedia.org/wikipedia/commons/e/e0/SNice.svg" width="100"> Sed eu dapibus nulla. In ut libero sit amet elit elementum gravida. Suspendisse quis quam consequat, pretium felis vel, laoreet turpis. Proin fringilla lobortis magna. Duis quam sapien, sodales nec accumsan id, ullamcorper eget tellus. Aliquam vitae orci cursus, porttitor ligula ut, fringilla odio. Donec a lorem ac eros interdum varius ultricies quis nulla.</p>
    </div>
  </div>
  <p class="break-avoid" contenteditable="true">Nunc in elit tincidunt, ultrices massa sed, ultricies elit. In nec accumsan metus. Nullam ultricies eget tortor ut malesuada. Fusce in elit sit amet dolor bibendum malesuada.</p>
  <div style="display:none;" class="break-avoid">
    <p>Curabitur sed hendrerit massa, vitae porta enim.</p>
  </div>
  <div class="break-avoid"><div><span>hey</span><div id="an-id">
    Nullam ultricies eget tortor ut malesuada. Fusce in elit sit amet dolor bibendum malesuada. Nulla sed nisi vel nulla aliquam blandit. Nam vel tellus ut libero ultrices volutpat. Curabitur blandit quis arcu rutrum ullamcorper. Cras et pharetra augue, eget eleifend sem.
    <img src="https://socialnewsdaily.com/wp-content/uploads/2018/08/Webp.net-resizeimage-27.jpg">
  </div></div></div>
  <div class="break-avoid">
  <p>
    Mauris accumsan condimentum porttitor. Quisque tellus justo, suscipit sit amet posuere in, scelerisque nec orci. Aenean iaculis nisi in porta viverra. Sed eget ultricies nibh. Donec accumsan laoreet interdum. Donec risus mauris, dapibus et pulvinar at, posuere non nisi. Mauris at viverra nunc. Ut laoreet suscipit erat et cursus. Aenean id lacus volutpat lectus condimentum posuere. Nam ut lectus elit. Morbi sagittis elementum libero. Donec congue dolor sed tristique efficitur.
  </p>
 </div>
    <div class="break-avoid">
      <p>Sed elementum velit sapien, et tristique justo bibendum at. Aliquam tincidunt magna nec nisi congue varius. Etiam dolor eros, rhoncus quis purus a, tempus malesuada quam. Sed bibendum condimentum eros vitae varius. Donec fermentum magna vel tellus tempus, nec finibus neque fermentum. Mauris tempus nisl sit amet lacus fermentum, at egestas urna egestas.</p>
      <p>Interdum et malesuada fames ac ante ipsum primis in faucibus. Suspendisse ultrices lectus vitae nisl congue, sed porta dolor luctus. Donec aliquet at sapien sit amet tincidunt. Mauris vestibulum consectetur augue at imperdiet.</p>
    </div>
  
</div>
Calque answered 12/8, 2019 at 2:4 Comment(6)
break-inside requires modern browsers. See: developer.mozilla.org/en-US/docs/Web/CSS/…Hansom
This isn't quite what I was looking for; sorry that the question is a bit ambiguous. I'm not looking to break the individual columns into sections, I'm looking to break across all columns, effectively 'restarting' the columns. When you reach the end of a left-hand column section you then read the column on the right-hand side before scrolling down to read the next section of columns. shutterstock.com/image-vector/… might illustrate it better.Cathryncathy
Yes, that codepen result is essentially what I'm looking for. Note that in my question I said "there are very few guarantees for the column content." I'm not able to put any such break-inisde classes in the content before it gets to my frontend. To use break-inside: avoid in that way would require injecting the classes (or wrapper divs) into the content at evenly spaced locations with JavaScript; and as stated in the question this is not ideal as the content is dynamic and might change at any time.Cathryncathy
So you basically ask for a 100% reliable cross-browser solution that works on potentially any markup you have little to no control. I am afraid that even a smart js solution would fail if you have dynamic content (e.g. single page web app) unless you ready to use mutation observer with a price of a performance hit. I'd suggest you rethink the markup sections because it quickly becomes tricky otherwise.Decurrent
@ViacheslavMoskalenko the column content is created by end users so rethinking the markup isn't really possible. My fallback option is to give users a tool to manually insert column section breaks into their content, but I want to exhaust my options for automatic column sections before resorting to this. I'm already using JavaScript to render portions of the content so a solution that uses mutation observers isn't a bad thing.Cathryncathy
@Cathryncathy I agree with Viacheslav Moskalenko. Your Idea with separate columns is great. Though it looks impossible to implement without major problems. Most likely any of your solutions will have a lot of pitfalls. "tool to manually insert column section" looks as best variant for me.Samarskite

© 2022 - 2024 — McMap. All rights reserved.