CSS dynamic responsive column layout
Asked Answered
C

1

6

I have been searching for answers but could not find anything that solves my problem.

I have a website with dynamic content. What I want is that the content flows into columns when possible, in order to minimize scrolling.

The items have dynamic heights.

  xxx item 1 xxx  |  xxx item 4 xxx
  xxxxxxxxxxxxxx  |  xxxxxxxxxxxxxx
  xxxxxxxxxxxxxx  |------------------
------------------|  xxx item 5 xxx
  xxx item 2 xxx  |  xxxxxxxxxxxxxx
  xxxxxxxxxxxxxx  |------------------
------------------|  xxx item 6 xxx
  xxx item 3 xxx  |  xxxxxxxxxxxxxx
  xxxxxxxxxxxxxx  |  xxxxxxxxxxxxxx

But when the browser window is resized, I want to put the content in a list, so a one-column table.

I know about media queries, but how should I configure it so that it flows into a 2-column layout when the window is wide enough?

It is also important that the items (the "group" div in the HTML below) are not split in half at the bottom.

The content HTML (using KnockoutJS for the dynamic data, the content inside groupsContainer is repeated because of the foreach attribute in groupsContainer):

<div data-bind="foreach: $data.groups" class="groupsContainer">
    <div class="group">
        <div data-bind="text: $data.name" class="groupTitle"></div>
        <table data-bind="foreach: $data.fields" class="fieldsContainer">
            <tr>
                <td data-bind="text: $data.name" class="fieldName"></td>
                <td data-bind="template: { name: $data.typeId, data: $data}" class="fieldValue"></td>
                <td class="valueChanged" data-bind="if:$data.valueChanged"><img
                    src="resources/images/control-state-edited.png" /></td>
            </tr>
        </table>
    </div>
</div>

CSS:

.groupsContainer {
    -webkit-column-width: 20em;
    -webkit-column-gap: 2em;
    -webkit-column-rule: 1px solid #eee;
    -webkit-column-count: 2;
    -moz-column-width: 20em;
    -moz-column-gap: 2em;
    -moz-column-rule: 1px solid #eee;
    -moz-column-count: 2;
    -ms-column-width: 20em;
    -ms-column-gap: 2em;
    -ms-column-rule: 1px solid #eee;
    -ms-column-count: 2;
    column-width: 20em;
    column-gap: 2em;
    column-rule: 1px solid #eee;
    column-count: 2;
}
Cochleate answered 9/5, 2014 at 9:14 Comment(0)
C
10

Although you are using items and not text- the below will still work, simply wrap the items into a container with the below CSS applied (replace div with the id or class of this container).

Have a look at the below- the columns will automatically compress at a smaller screen size without the need to media queries.

Demo Fiddle

CSS:

html, body {
    width:100%;
}
div {
    -webkit-column-width: 20em;
    -webkit-column-gap: 2em;
    -webkit-column-rule: 1px solid #eee;
    -webkit-column-count: 2;
    -moz-column-width: 20em;
    -moz-column-gap: 2em;
    -moz-column-rule: 1px solid #eee;
    -moz-column-count: 2;
    -ms-column-width: 20em;
    -ms-column-gap: 2em;
    -ms-column-rule: 1px solid #eee;
    -ms-column-count: 2;
    column-width: 20em;
    column-gap: 2em;
    column-rule: 1px solid #eee;
    column-count: 2;
}

Alternatively- with Media Queries

If you want more control- you can simply use a media query to apply columns at sizes above that specified (below being 1024)

html, body {
    width:100%;
}
@media screen and (min-width: 1024px){
    div {
        -webkit-column-width: 20em;
        -webkit-column-gap: 2em;
        -webkit-column-rule: 1px solid #eee;
        -webkit-column-count: 2;
        -moz-column-width: 20em;
        -moz-column-gap: 2em;
        -moz-column-rule: 1px solid #eee;
        -moz-column-count: 2;
        -ms-column-width: 20em;
        -ms-column-gap: 2em;
        -ms-column-rule: 1px solid #eee;
        -ms-column-count: 2;
        column-width: 20em;
        column-gap: 2em;
        column-rule: 1px solid #eee;
        column-count: 2;
    }
}

Preventing elements from breaking between columns

To avoid elements from being broken between columns, you can use the below:

.group{ /* class to restrict breaking on */
    break-inside: avoid-column;
    -webkit-column-break-inside: avoid;
    page-break-inside: avoid;
    overflow: hidden; /* optional */
    display:inline-block; /* optional */
}

That said, note that functionality support between browsers may be patchy, if it isnt working as expected, replace display:inline-block; with display:table; or remove entirely.

Cannady answered 9/5, 2014 at 9:17 Comment(9)
That works great, but now the last item of the first column gets cut in half, how can I prevent this?Cochleate
Can you provide a jsfiddle.net? Otherwise hard to say- flying blind!Cannady
Because of the dynamic data I can't make a jsfiddle, but I put the significant html and css in the questionCochleate
What's happening is that the groupTitle div is at the bottom of the first column and the fieldsContainer is at the top of the second column.Cochleate
@MarkBuikema - to make a jsfiddle, just copy the output HTML, its going to be tricky to diagnose otherwiseCannady
@MarkBuikema - I've updated my answer, let me know if the code at the bottom works for youCannady
Thanks, that worked, but not without the optional lines!Cochleate
@MarkBuikema perfect, sorry for the delayed replyCannady
No problem, will award bounty when available (18hours)Cochleate

© 2022 - 2024 — McMap. All rights reserved.