CSS dynamic responsive column layout

Mark Buikema picture Mark Buikema · May 9, 2014 · Viewed 7.5k times · Source

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;
}

Answer

SW4 picture SW4 · May 9, 2014

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.