1

I want to format my unordered list into two sections of text. I've been trying to find out how to do this with Google. but everyone seems interested in making their lists flow left to right, which is not what I want to do. What I'm looking for is a way to make the following:

 Food                Calories

 Fruit
    -Apple            90
    -Grape            5
    -Berries          
       -Strawberry    16
       -Blueberry     9
 Vegetable
    -Cucumber         12
    -Onions            
       -Red           29
       -White         34
       -Vidalia       47

Is this possible with an unordered list and CSS? I'd prefer not to use a table for this, since I'd like to make the <li> expand and contract.

EDIT: Hopefully it looks more like an expand/contract hierarchy now than strictly tabular data. I understand that it's possible to do this with a table, it just seems less natural to present a hierarchy that way.

1
  • 1
    Tables can be set to percentage widths. And this looks like tabular data to me. Commented Nov 19, 2012 at 17:03

6 Answers 6

5

With the following HTML you can do this (and, frankly, with other HTML you could do this...) but you should use tables.

Anyway, that said, the HTML I'm working with:

<ul>
    <li class="head">
        <span class="col1">Food</span>
        <span class="col2">Calories</span>
    </li>
    <li>Fruits
        <ul>
            <li>
                <span class="col1">Apple</span>
                <span class="col2">90</span>
            </li>
            <li>
                <span class="col1">Grape</span>
                <span class="col2">5</span>
            </li>
            <li>
                <span class="col1">strawberry</span>
                <span class="col2">16</span>
            </li>
        </ul></li>
    <li>Vegetable
        <ul>
            <li>
                <span class="col1">Cucumber</span>
                <span class="col2">12</span>
            </li>
            <li>
                <span class="col1">Onion</span>
                <span class="col2">29</span>
            </li>
        </ul></li>
</ul>​

And the CSS:

li.head {
    font-weight: bold;
}
span.col1,
span.col2 {
    display: inline-block;
    width: 48%;
}

ul > li > ul > li {
    padding-left: 10%;
    height: 0;
    line-height: 0;
    overflow: hidden;
    -webkit-transition: all 1s linear;
}

ul > li:hover > ul > li {
    height: 2em;
    line-height: 2em;
    -webkit-transition: all 1s linear;
}

ul > li > ul > li span:first-child::before {
    content: '-';
    width: 40%;
}

li li:nth-child(odd) span {
    background-color: #aaf;
}
​

JS Fiddle demo.

To allow for keyboard navigation, and showing the nested foods/calorie values in response to tab-events, I've amended the HTML a little to wrap the fruits and vegetable text with an a element:

<ul>
    <li class="head">
        <span class="col1">Food</span>
        <span class="col2">Calories</span>
    </li>
    <li><a href="#">Fruits</a>
        <ul>
            <li>
                <span class="col1">Apple</span>
                <span class="col2">90</span>
            </li>
            <li>
                <span class="col1">Grape</span>
                <span class="col2">5</span>
            </li>
            <li>
                <span class="col1">strawberry</span>
                <span class="col2">16</span>
            </li>
        </ul></li>
    <li><a href="#">Vegetable</a>
        <ul>
            <li>
                <span class="col1">Cucumber</span>
                <span class="col2">12</span>
            </li>
            <li>
                <span class="col1">Onion</span>
                <span class="col2">29</span>
            </li>
        </ul></li>
</ul>​

With the following CSS:

li.head {
    font-weight: bold;
}

li a {
    color: inherit;
    text-decoration: none;
}

span.col1,
span.col2 {
    display: inline-block;
    width: 48%;
}

ul > li > ul > li {
    padding-left: 10%;
    height: 0;
    line-height: 0;
    overflow: hidden;
    -moz-transition: all 1s linear;
    -ms-transition: all 1s linear;
    -o-transition: all 1s linear;
    -webkit-transition: all 1s linear;
    transition: all 1s linear;
}

ul > li a:focus + ul > li,
ul > li:hover > ul > li {
    height: 2em;
    line-height: 2em;
    -moz-transition: all 1s linear;
    -ms-transition: all 1s linear;
    -o-transition: all 1s linear;
    -webkit-transition: all 1s linear;
    transition: all 1s linear;
}

ul > li > ul > li span:first-child::before {
    content: '-';
    width: 40%;
}

li li:nth-child(odd) span {
    background-color: #aaf;
}
​

JS Fiddle demo.

Both of these, however, assume that you want to hide automatically, and show based on user-interaction. If that assumption's incorrect then the transitions aren't necessary.

Incidentally, an accordion-like table solution:

<table>
    <colgroup>
        <col class="foods" />
        <col class="calories" />
    </colgroup>
    <thead>
        <tr>
            <th>Food</th>
            <th>Calories</th>
        </tr>
    </thead>
    <tbody>
        <tr class="header">
            <td colspan="2">Fruits</td>
        </tr>
        <tr>
            <td>Apple</td>
            <td>90</td>
        </tr>
        <tr>
            <td>Grape</td>
            <td>5</td>
        </tr>
        <tr>
            <td>Strawberry</td>
            <td>16</td>
        </tr>
    </tbody>
    <tbody>
        <tr class="header">
            <td colspan="2">Vegetable</td>
        </tr>
        <tr>
            <td>Cucumber</td>
            <td>12</td>
        </tr>
        <tr>
            <td>Onion</td>
            <td>29</td>
        </tr>
    </tbody>
</table>

CSS:

.foods,
.calories {
    width: 8em;
}

tbody tr.header {
    height: 2em;
    line-height: 2em;
}

tbody tr,
tbody tr td {
    max-height: 0;
    line-height: 0;
    overflow: hidden;
    -moz-transition: all 1s linear;
    -ms-transition: all 1s linear;
    -o-transition: all 1s linear;
    -webkit-transition: all 1s linear;
    transition: all 1s linear;
}

tbody tr td:first-child {
    padding-left: 2em;
}

tbody tr.header td {
    padding: 0;
}

tbody:hover tr {
    height: 2em;
    max-height: 2em;
    line-height: 2em;
    -moz-transition: all 1s linear;
    -ms-transition: all 1s linear;
    -o-transition: all 1s linear;
    -webkit-transition: all 1s linear;
    transition: all 1s linear;
}
​

JS Fiddle demo.

This makes the same assumptions as previously, that you want to control the visibility by hovering over the header to show the hidden content.

And, just for kicks, adding keyboard-navigation (with tab), using the tabindex attribute on the tr.header elements:

<table>
    <colgroup>
        <col class="foods" />
        <col class="calories" />
    </colgroup>
    <thead>
        <tr>
            <th>Food</th>
            <th>Calories</th>
        </tr>
    </thead>
    <tbody>
        <tr class="header" tabindex="1">
            <td colspan="2">Fruits</td>
        </tr>
        <!-- unchanged from the previously-posted table mark-up -->
    </tbody>
    <tbody>
        <tr class="header" tabindex="2">
            <td colspan="2">Vegetable</td>
        </tr>
        <!-- unchanged from the previously-posted table mark-up -->
    </tbody>
</table>

​And CSS:

/* Other CSS remains the same */
tr.header:focus ~ tr,
tbody:hover tr {
    height: 2em;
    max-height: 2em;
    line-height: 2em;
    -moz-transition: all 1s linear;
    -ms-transition: all 1s linear;
    -o-transition: all 1s linear;
    -webkit-transition: all 1s linear;
    transition: all 1s linear;
}

tr.header:focus {
    outline: none;
    font-style: italic;
    background-color: #ffa;
}
​

JS Fiddle demo.

Sign up to request clarification or add additional context in comments.

4 Comments

Wow, this is the most thorough answer I've ever received. I also didn't know that you could do the animated hide/reveal with pure CSS. I award you all the points I'm capable of offering (which is only one, sadly). Thank you!
Thank you kindly! And I'm glad to have been of help! =)
How can you do this using tables in a way that preserves the hierarchical structure, so that you don't have to compute which rows to show/hide? (Also, I'm interested in doing this for an arbitrary number of columns, which CSS doesn't seem well suited for.)
@Michael: without having some idea of the HTML you'd be using I'm afraid I can't really answer that; you may want to consider asking a new question to address any complexities that you don't feel this answer addresses.
2

This is really tabular data so a table would be okay to use.

However you could do this: http://jsfiddle.net/eFmtR/

ul {
 width:300px;
}
ul li {
 width:150px;
 float:left;
 text-align:center;
}

strong {
 font-weight:bold;
}


<ul>
 <li><strong>Food</strong></li>
 <li><strong>Calories</strong></li>
 <li>list item</li>
 <li>list item</li>
 <li>list item</li>
 <li>list item</li>
 <li>list item</li>
 <li>list item</li>
 <li>list item</li>
 <li>list item</li>
</ul>

1 Comment

This is still the same approach everyone on Google has, they're trying to make columns by flowing it left to right and wrapping it. I'm looking for a way to have the columns defined in a single <li> tag
2

Try to do like this. I've used the same technique to do a fluid restaurant menu.

ul { width:20em;} 
ul:first-child {font-weight: 700}
ul ul {font-weight: 400}

ul span:first-child { padding-left:1em;}
ul span + span { float:right;}

<ul>
    <li>fruit</li>
    <ul>
        <li><span>apple</span><span>90</span></li>
        <li><span>grappe</span><span>5</span></li>
        <li><span>strawberry</span><span>16</span></li>
        <li><span>etc</span><span>5.25</span></li>        
    </ul>
    <li>vegetable</li>
    <ul>
        <li><span>cucumber</span><span>12</span></li>
        <li><span>Onion</span><span>29</span></li>   
    </ul>    
</ul>

see it here : DEMO

1 Comment

is it possible to expand this to an arbitrary number of columns?
1

I would do something like this:

CSS

  .foods{border:1px solid red;overflow: hidden;width:310px;}
        ul li{list-style: none;}
        ul li.dash:before{content:"-";}
            .fruit{float:left;width:150px;}
            .calories{float:left;width:150px;}

HTML

<div class="foods">
        <div class="fruit">
            <h3>Food</h3>

                <h3>Fruits</h3>
                <ul>
                    <li class="dash">Apple</li>
                    <li class="dash">Grape</li>
                    <li class="dash">Strawberry</li>
                </ul>
                <h3>Vegetable</h3>
                    <ul>
                    <li class="dash">Cucumber</li>
                    <li class="dash">Onion</li>

                </ul>


        </div>
        <div class="calories">
            <h3>Calories</h3>
            <div>
                <h3>&nbsp;</h3>
                <ul>
                    <li>90</li>
                    <li>15</li>
                    <li>16</li>
                </ul>
                <h3>&nbsp;</h3>
                <ul>
                    <li>12</li>
                    <li>29</li>

                </ul>
            </div>
        </div>
    </div>

DEMO

Comments

0

I know what you are trying to achieve however you could implement jQuery to do this but it would be dependent on your usage. The answer from @BillyMoat would deal with showing the results in two columns, but if you want them to expand/collapse you could deploy jQuery Accordion: http://docs.jquery.com/UI/API/1.8/Accordion

Comments

0

One JavaScript-free solution you could try using is the new column-count CSS property. Watch out for IE though, it's not going to be supported unless they're at IE10+: http://caniuse.com/multicolumn

ul {
     -webkit-column-count: 3; /* Beware of IE Problems */
}

This might not perfectly "split" your data, but it's worth exploring for others coming to this page.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.