8

I have a HTML layout puzzle on my hands. I have a large alphabetical list, generated by my PHP app, and I need to output it on a web page. The markup generated look like this:

<div class="list_item">A</div>
<div class="list_item">B</div>
<div class="list_item">C</div>
<div class="list_item">D</div>
<div class="list_item">E</div>
<div class="list_item">F</div>
<div class="list_item">G</div>
<div class="list_item">H</div>
...

The stylesheet looks like this:

.list_item {
    margin: 5px;
    padding: 5px;
    border: 1px solid gray;

    width: 200px;
    float: left;
}

Rendered result:

Rendered result

As you can see, this is not very readable, I would expect DIV's to be outputted in two columns, so the first columns would contain "A B C D" and the second one "E F G H".

Is there a way to do this, without changing the markup? It's possible, to add different class, to even and odd divs, but since divs are outputted in a loop, theres is no way split them differently.

See a demo: http://jsfiddle.net/KZcCM/

Note: I already solved it by splitting the list in two parts by PHP, but I want to know, if there is a HTML/CSS solution here.

Silver Light
  • 44,202
  • 36
  • 123
  • 164
  • Do you want to split it alphabetically or height-wise? Personally I prefer it floated as you know "A" is at the top and "Z" is at the bottom. – Marcel Mar 30 '11 at 09:03
  • 1
    When you have a class called "list_item", you know it's time to start using the `li` (list item) tag instead, along with `ul`. – thirtydot Mar 30 '11 at 09:06
  • I think the best way for you to do this is to split the left column and right column in two seperate divs. – arnehehe Mar 30 '11 at 09:07
  • @thirtydot in a real world, there is a very complicated markup inside of every DIV. – Silver Light Mar 30 '11 at 09:07
  • @Silver Light: Anything you can put inside a `div`, you can put inside an `li`. Just saying.. – thirtydot Mar 30 '11 at 09:09
  • Here was my attemp: http://jsfiddle.net/KZcCM/2/ – Tom Gruner Mar 30 '11 at 09:12
  • Does this have to work in Internet Explorer? It's become a rather contentious point. – thirtydot Mar 30 '11 at 12:44
  • @thirtydot Well, 20% of my audience uses IE. But I think, if it will work in IE9, then those 20% can see "not-so-beutiful" list until they upgrade :) – Silver Light Mar 30 '11 at 12:50
  • @Silver Light: The CSS3 columns won't work in even IE9. Your options, as I see them: use CSS3 columns, forget about IE users having the right order boxes, or; use CSS3 columns, but use the jQuery plugin workaround to make it work in IE, or; keep what you have, or; do what I wrote in my answer. – thirtydot Mar 30 '11 at 17:40

5 Answers5

14

Depending on which browsers you need to support, you can use the new CSS3 column-count property.

With a simple list mark up

<ul>
    <li>A</li>
    <li>B</li>
    <li>C</li>
    <li>D</li>
</ul>

Use this CSS:

ul {
    -moz-column-count: 2;
    -moz-column-gap: 20px;
    -webkit-column-count: 2;
    -webkit-column-gap: 20px;
    column-count: 2;
    column-gap: 20px;
}

Here is a fiddle - although it's not supported in any version of IE yet. To support older browsers there are jQuery solutions, such as Columnizer jQuery Plugin, that you can use as well as, or instead of the CSS3 solution,

pconcepcion
  • 5,591
  • 5
  • 35
  • 53
ajcw
  • 23,604
  • 6
  • 30
  • 47
10

Using your markup, a CSS3 solution would look like this:

HTML

<div id="wrap">
    <div class="list_item">A</div>
    <div class="list_item">B</div>
    <div class="list_item">C</div>
    <div class="list_item">D</div>
    <div class="list_item">E</div>
    <div class="list_item">F</div>
    <div class="list_item">G</div>
    <div class="list_item">H</div>
</div>

CSS:

.list_item {
    float: left;
    margin: 5px;
    padding: 5px;
    width: 200px;
    border: 1px solid gray;
}
#wrap {
    width:460px;
    column-count:2;
    column-gap:20px;
    -moz-column-count:2;
    -moz-column-gap:20px;
    -webkit-column-count:2;
    -webkit-column-gap:20px;
}

With this method you get the added benefit of the column heights being equal, no matter the content of each inner <div>.

If it's not plainly obvious by all the vendor-specific prefixes, the browser support for this is restricted to modern browsers (the way I like it) so it's not really production-ready code (unless you like to be edgy).

Demo: jsfiddle.net/Marcel/tk2tS

Community
  • 1
  • 1
Marcel
  • 27,922
  • 9
  • 70
  • 85
  • I just noticed I didn't account for `border` in the `#wrap` width but that doesn't seem to matter too much. – Marcel Mar 30 '11 at 09:23
  • Can't resist upvoting (this is how it *should* be), but it's unfortunately just not a practical solution :( As you said, it doesn't work in [the most popular browser](http://gs.statcounter.com/). – thirtydot Mar 30 '11 at 09:43
  • I could not believe my eyes that this works in ie6 (emulator) – Rito Mar 30 '11 at 10:05
  • @Rito: The elements are not in the desired order in any version of IE. – thirtydot Mar 30 '11 at 14:58
1

I can't think of a pure CSS solution.

You said:

Note: I already solved it by splitting the list in two parts by PHP, but I want to know, if there is a HTML/CSS solution here.

So, you have the power of PHP. In that case, I would keep the code you already have, but output the elements in a different order:

See: http://jsfiddle.net/xyLkz/

<div class="list_item">A</div>
<div class="list_item">E</div>
<div class="list_item">B</div>
<div class="list_item">F</div>
<div class="list_item">C</div>
<div class="list_item">G</div>
<div class="list_item">D</div>
<div class="list_item">H</div>

How easy that will be depends on how your PHP is structured.

If you have everything in an array, then in this case, you would just have two loops (one outputting odd array elements, the other even ones). If you need support for n columns, that wouldn't be a problem either.

What would be a problem is if you're building the output "on-the-fly", inside the loop. In that case, you'd probably have to resort to buffering the output of each iteration of the loop into an array, and then doing the same double-loop process afterwards.

thirtydot
  • 224,678
  • 48
  • 389
  • 349
  • @Tomalak Geret'kal: But he *can* change it. If his current solution uses PHP to make two lists, then he can just as easily use it to output the elements in two loops. My solution is the only one that actually *works*. – thirtydot Mar 30 '11 at 09:44
  • @thirtydot: (a) Your solution is _not_ the only one that "works"; (b) Whether he can or not is besides the point... the question says that he doesn't want to. Valid answers do not involve changing the markup. – Lightness Races in Orbit Mar 30 '11 at 10:37
  • @Tomalak Geret'kal: The other answers only work in modern browsers, and not IE, which happens to be the [most popular browser worldwide](http://gs.statcounter.com/). Using a JavaScript library to replace the functionality is a bad idea - why do it client-side when you can do it server-side. The idea of answering a question is not to strictly adhere to the words in the question, but to find the **best solution** to the problem. I listed the possible downsides to my technique in my answer, so I think your downvote is unwarranted and highly annoying. – thirtydot Mar 30 '11 at 10:41
  • John's answer "works" just fine cross-browser, whether you think it's a "bad idea" or not ("why do it client-side when you can do it server-side" is hardly a rationale as to why it "doesn't work"). Although I agree that the best SO answers find the best solution to the problem, the problem here states _explicitly_ and _in no uncertain terms_ that the OP wants a solution without changing markup, and you have flagrantly ignored that. That's more annoying than losing a little bit of rep on 12.9k (blimey, how petty!). – Lightness Races in Orbit Mar 30 '11 at 11:10
  • @Tomalak Geret'kal: How about this then, if you want to be so pedantic about what was *explictly stated* in the question. `"but I want to know, if there is a HTML/CSS solution"` - a **HTML/CSS** solution - John's answer requires **JavaScript** to work cross-browser (like in Internet Explorer, **the most popular browser in the world**). Therefore, only my answer works. The OP is already using PHP to change his HTML, so he might as well change it in a different way. The change I'm suggesting is **logically sensible**, despite the OP having stated that he doesn't wish to change the markup. – thirtydot Mar 30 '11 at 11:22
  • @Tomalak Geret'kal: Also, I don't care about the reputation. I care that you're downvoting the most practical answer in the thread.. :/ – thirtydot Mar 30 '11 at 11:30
  • @thirtydot: He didn't say it had to be cross-browser. Who cares about IE?! :P Your definition of "the most practical" is flawed until you can prove that most of _the OP's users_ use IE, and/or that he cares. – Lightness Races in Orbit Mar 30 '11 at 12:02
  • @Tomalak Geret'kal: Are you serious?!? The logical assumption is that support for all **major market share** browsers is required, unless the OP has said (and here's your favourite word again) **explicitly** something like "I'm developing for WebKit browsers only", or "I don't care about users of Internet Explorer". He hasn't said *anything of the sort*. You think an answer that (in the words of @Marcel) contains "not really production-ready code" is better than one that Just Works? Why do they deserve upvotes, but mine deserves downvotes? They each have downsides. – thirtydot Mar 30 '11 at 12:08
  • @thirtydot: You're just being childish now. I don't understand why you're failing to comprehend that you wrote an answer that contravenes what the OP asked for. I'm done with this conversation. If you have a problem with the answer that myself and others have upvoted to a total of 5 (see, it's not just me) then I suggest you make explicit complaints on the relevant answer's comment thread. – Lightness Races in Orbit Mar 30 '11 at 12:30
  • @Tomalak Geret'kal: So you've run out of facts, so you're giving up the discussion; hey, whatever works for you. **Even I** voted up that answer, because (I agree with it and) **it is good**, but in a different way to my answer. I already did `"make explicit complaints on the relevant answer's comment thread"` - I said `"Can't resist upvoting (this is how it should be), but it's unfortunately just not a practical solution :( As you said, it doesn't work in the most popular browser."` - or did you also miss that comment? It wouldn't be the first thing you've missed in this question. – thirtydot Mar 30 '11 at 12:35
  • @Tomalak Geret'kal: My real irritation is that you're supposed to downvote answers that are [NOT USEFUL](http://stackoverflow.com/privileges/vote-down). From that page: `"Whenever you encounter an egregiously sloppy, no-effort-expended post, or an answer that is clearly and perhaps dangerously incorrect, vote it down!"` - would you say that my viable answer fits that profile? I didn't think so. Hence why I'm not dropping this argument. – thirtydot Mar 30 '11 at 12:39
  • @thirtydot: Then you can continue it on your own. – Lightness Races in Orbit Mar 30 '11 at 13:06
  • @Tomalak Geret'kal: Then I might have to spend some time reading your answers, and downvoting those that do not *explicitly* (in my opinion) adhere to the words in the question. That's what you've done in this question, and frankly: it's annoying. Now, I'm not actually likely to do that, but I sure do feel like doing it. I actually cannot believe how *pedantic* you are - it's insane. – thirtydot Mar 30 '11 at 13:28
1

@ silver

i try for side without using extra markup may it's useful to you

http://jsfiddle.net/sandeep/GGwPq/1/

sandeep
  • 91,313
  • 23
  • 137
  • 155
0

You don't need to use float for the items, but maybe for a box where the items are located in, try this:

<div style="float: left; width: 200px;">
    <div class="list_item">A</div>
    <div class="list_item">B</div>
    <div class="list_item">C</div>
    <div class="list_item">D</div>
</div>
<div style="float: left; width: 200px;">
    <div class="list_item">E</div>
    <div class="list_item">F</div>
    <div class="list_item">G</div>
    <div class="list_item">H</div>
</div>

.list_item {
    margin: 5px;
    padding: 5px;
    border: 1px solid gray;

    width: 200px;
    /*float: left;*/
}

Edit: now with 2 columns :)

Kevin Glier
  • 1,346
  • 2
  • 14
  • 30
  • This will output one column, but I would like see two columns – Silver Light Mar 30 '11 at 09:06
  • I edited my post, didn't read your text correctly, sry :S But now it should be the right solution – Kevin Glier Mar 30 '11 at 09:08
  • 1
    There is no other way? I mentioned in the question, that I cannot change the markup. – Silver Light Mar 30 '11 at 09:10
  • If you have 2 arrays in PHP, one with the values A, C, E, G and the other with B, E, F, H then you could add the items in a loop like this: foreach ($i = 0; $i < count($arr_div_left); $i++) { // use the array with the highest count echo '
    '.$arr_div_left[$i].'
    '; echo '
    '.$arr_div_right[$i].'
    ';}
    – Kevin Glier Mar 30 '11 at 09:25
  • But there is no HTML/CSS way for that. The PHP-way isn't that bad I think, but he have to create the 2 arrays first. Another way would be, to loop trough all the values and create 2 strings with the content for the 2 boxes. if ($i % 2 == 0) $add_to_box1 else $add_to_box2 – Kevin Glier Mar 30 '11 at 09:47
  • +1 to offset Mr Downvote-Answers-I-Don't-Like, and because I just noticed you had the "2 loops in PHP idea" before I did, which I think is the way to go. – thirtydot Mar 30 '11 at 09:59
  • Who is "Mr Downvote-Answers-I-Don't-Like"? It can't be me, I didn't vote for anything :P – Kevin Glier Mar 30 '11 at 10:14
  • @Kevin Glier: It's @Tomalak Geret'kal. I don't particularly like that he comes into a question, upvotes the two answers that aren't practical to actually use (CSS3 column-based, and the JavaScript alternative is even worse.. why do it client-side when you can do it server-side), and downvotes the two answers that suggest (even if your suggestion of this is only in a comment) using PHP to reorder the elements (a good solution, I think). – thirtydot Mar 30 '11 at 10:38