Nathan
Nathan

Reputation: 7032

Can I automatically break CSS columns into 'pages' that fit vertically inside the viewport?

I have a page that presents a long article for comfortable reading. I would like to break the text into columns on wide screens, but I don't want to make users scroll all the way to the bottom of the page and then back up to the top again after finishing each column.

Is there a way, without using JavaScript, to automatically split the article into vertical sections ('pages') that are short enough to fit entirely within the viewport? Here's some ASCII art to illustrate:

+-------------------------------------------------------------+
|                       === Some Title ===                    |
|                                                             |
| You think water moves fast?    it out. Now we took an oath, |
| You should see ice. It moves   that I'm breaking now. We    |
| like it has a mind. Like it    said we'd say it was the     |
| knows it killed the world      snow that killed the other   |
| once and got a taste for       two, but it wasn't. Nature   |
| murder. After the avalanche,   is lethal but it doesn't     |
| it took us a week to climb     hold a candle to man.        |
| out. Now, I don't know                                      |
| exactly when we turned on      Like you, I used to think    |
| each other, but I know that    the world was this great     |
| seven of us survived the       place where everybody lived  |
| slide... and only five made    by the same standards I did, |
+-------------------------------------------------------------+
| then some kid with a nail     Dr. Wu inserted a gene that   |
| showed me I was living in     makes a single faulty enzyme  |
| his world, a world where      in protein metabolism. The    |
| chaos rules not order, a      animals can't manufacture the |
| world where righteousness is  amino acid lysine. Unless     |
| not rewarded. That's Cesar's  they're continually supplied  |
| world, and if you're not      with lysine by us, they'll    |
| willing to play by his rules, slip into a coma and die.     |
| then you're gonna have to pay                               |
| the price.                    Do you see any Teletubbies in |
| The lysine contingency -      here? Do you see a slender    |
| it's intended to prevent the  plastic tag clipped to my     |
| spread of the animals is case shirt with my name printed on |
| they ever got off the island. it?                           |
+-------------------------------------------------------------+

The lines represent the height of the viewport. The columns end at the bottom of the viewport and the text flows to the top of the next column, which begins at the top of the viewport. Once that 'page' of text has been read, the user scrolls down to the next one and begins again. This allows the text to be split into columns without requiring lots of extra scrolling. On a large screen, the 'pages' would be tall, but on a small screen they would be short enough to fit within the viewport.

A good solution doesn't have to be perfectly semantic, but shouldn't require any JavaScript.

Upvotes: 1

Views: 644

Answers (4)

hobbeshunter
hobbeshunter

Reputation: 629

I played a bit around. It just works with plain text, but is responsive.

(function($) {
    $.fn.fitcol = function(options) {

            changes = function(el) {
                    var $el = $(el),
                            settings = $.extend({
                            intendedheight: $(window).height() - ($el.outerHeight()-$el.height()), // set default intended height (rough estimation: height of window - padding and border)
                    }, options),
                            height = $el.height(),
                            ratio = height / settings.intendedheight,
                            text = $el.text(), //clear all inner html (should be fixed) currently needed in case of window resize
                            length = text.length,
                            intendedlength = Math.floor(length / ratio),
                            i = 1,
                            html = '</div><div class="column">'; //code for a breakpoint
                            text = '<div class="column">' + text;
                var correction = 20; 
                while((intendedlength * i) + correction < text.length) { // loop to put breakpoints into the text
                    var j = 0
                    while(text.charAt((intendedlength * i) + correction) !== ' ' &&  j<= 20) { //loop so we don't break words
                                correction--;
                                j++;
                                }
                    text = text.substr(0, (intendedlength * i) + correction ) + html + text.substr((intendedlength * i) + correction);
                    correction += html.length; // we are changing the length of text when we add html
                    i++;
                }
                text = text + '</div>';

                $el.removeClass('column');
                $el.html(text);

            };
            //make it responsive
            return this.each(function() {
                    var that = this;
                    $(window).resize(function() {
                            changes(that);
                    });
                    changes(this);
            });
    };
}(jQuery));

$('.container').fitcol();

See it at http://codepen.io/wudi96/pen/doXYrv

It's very experimental and far from beeing optimized.

Would be nice to use together with panelSnap http://guidobouman.github.io/jquery-panelsnap/.

Upvotes: 3

Rob Sterlini
Rob Sterlini

Reputation: 342

Honestly, I think the best answer to this one is to avoid pagination altogether. People are quite used to reading single column blogs, news stories, articles etc. I'd just set max-width:800px; width:95%; margin:0 auto; and have it as one long stream.

This might cause issues if you have loads of images, but can be solved by only loading those that are needed, see lazy loading.

That's a personal opinion. Remember pages can be as long as you like, pagination is for books ;)

Good luck.

Upvotes: -2

matty-d
matty-d

Reputation: 2651

You want css columns and you just need to put the text into different divs in groups. here is a jsfiddle that shows it. Here is my css:

.mydiv
{
-moz-column-count:2; /* Firefox */
-webkit-column-count:2; /* Safari and Chrome */
column-count:2;
}

Upvotes: 1

dievardump
dievardump

Reputation: 2503

I think that http://quirksmode.org/css/columns/ is what you are looking for.

See Example: http://www.w3.org/TR/css3-multicol/#the-multi-column-model

Upvotes: 0

Related Questions