views:

81

answers:

2

While composing documentation, I created an outline using ordered lists within ordered lists and applied a pseudo-legal-style row numbering using CSS. The default behavior of lists is to right-align numbers and left align text; however, the CSS2 snippet I'm using is changing that behavior so that numbers are left-aligned and text, though left-aligned flows incorrectly. See the following examples:

Default behavior (Number 10 highlights the desired alignments):

 1. Item
 2. Item
    1. Item
    2. Item
       1. Item
       2. Item
 3. Item
 ...
10. Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
    Nunc et diam sem.   Pellentesque vitae dolor id eros commodo 
    dapibus tristique sit amet eros. Pellentesque turpis turpis.

Styled behavior (Number 10 highlights the undesirable alignments):
Using a derived CSS2 snippet from http://www.w3.org/TR/CSS2/generate.html

OL { counter-reset: item }
LI { display: block }
LI:before { content: "("counters(item, ".") ") "; counter-increment: item }

Results:

 (1) Item
 (2) Item
     (2.1) Item
     (2.2) Item
           (2.2.1) Item
           (2.2.2) Item
 (3) Item
 ...
 (10) Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
 Nunc et diam sem.   Pellentesque vitae dolor id eros commodo 
 dapibus tristique sit amet eros. Pellentesque turpis turpis.

I see that the LI { display: block } is suppressing the default numbering and LI:before is prefixing "normal" text with counter values. How can I have both legal-style numbering and desired alignment of numbers and text?

Here's a full document showing the issue:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml"&gt;
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Outline</title>
<style type="text/css">
ol {
counter-reset: item;
list-style-position: outside
}
li {
display: block;
padding-left: 10px;
}
li:before {
content: "("counters(item, ".") ") ";
counter-increment: item
}
</style>
</head>

<body>
<h1>Outline</h1>
<ol>
  <li>Item</li>
  <li>Item
    <ol>
      <li>Item</li>
      <li>Item
        <ol>
          <li>Item</li>
          <li>Item</li>
        </ol>
      </li>
    </ol>
  </li>
  <li>Item</li>
  <li>Item</li>
  <li>Item</li>
  <li>Item</li>
  <li>Item</li>
  <li>Item</li>
  <li>Item</li>
  <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
    Nunc et diam sem.   Pellentesque vitae dolor id eros commodo 
    dapibus tristique sit amet eros. Pellentesque turpis turpis.</li>
</ol>
</body>
</html>
A: 

Specifying list-style-position: outside and a proper padding on the li elements should do it.

You
Thanks, but that didn't work. See the full document I added.
Michael Prescott
A: 

A slightly awkward solution might be:

ol {
    width: 10em;
    counter-reset: item;
    list-style-position: outside;
}

li {
    position: relative;
    left: 2em;
    display: block;
    list-style-position: outside;
}

li:before {
    content: "("counters(item, ".") ") ";
    counter-increment: item;
    position: absolute;
    left: -2.5em;
}

li li:before {
    left: -2.5em;
}

li li li:before {
    left: -3em;
}

This just uses position: relative; to allow the li text to be moved to the right (left: 2em;) while positioning the li:before text absolutely and moving it to the left.

The awkward part comes from having to specify different left: values for the li:before, li li:beforeandli li li:before` so it's not quite as simple as it might be.

There's a demo of what I came up with over at: http://jsbin.com/asaru3


Edited in response to comments from OP:

Thanks, I believe I understand how that works. To continue the pattern, I'd have to create "li li li li" for a list that was 4 levels deep, right? Also, I don't see that the numbers are left-aligned. Is there a way to get at those value and apply similar repositioning or alignment to just them?

I mean the numbers are NOT right-aligned.

To the first question 'to continue the pattern, I'd have to create "li li li [li:before]" for a list...4 levels deep?" Yeah, which is one of the reasons I think it's an awkward solution. Albeit it does work.

To address the latter question, I believe that you want the numbers to align along their right edge?

If you revise the css for li:before:

li:before {
    content: "("counters(item, ".") ") ";
    counter-increment: item;
    position: absolute;
    left: -2.5em;
    display: block;
    width: 2em; /* to give the same dimensions to all counter 'blocks' */
    text-align: right; /* does exactly what you'd think =) */
}

With this approach bear in mind that the size of the contents of li:before must be less than the left: positioning of the li, otherwise there'll be overlap of the counter and the content.

Be aware that as the counter grows in size its width should also be amended for li li:before, li li li:before as before.

Demo at: http://jsbin.com/ovuru3

David Thomas
Thanks, I believe I understand how that works. To continue the pattern, I'd have to create "li li li li" for a list that was 4 levels deep, right? Also, I don't see that the numbers are left-aligned. Is there a way to get at those value and apply similar repositioning or alignment to just them?
Michael Prescott
I mean the numbers are NOT right-aligned.
Michael Prescott
Thanks again. I've just purchased a highly recommended book about CSS and have a handful of good resources, but nothing beats having a professional provide a good example.
Michael Prescott
...or enthusiastic amateur in this case, but thank you! And you are, certainly, welcome =)
David Thomas