-3

I need HTML to produce output similar to:

1.     Some title

1.1    blah blah

       (a)    blah blah blah

       (b)    blah blah

1.2    blah blah

I believe that because of the need for parenthesis round the letters that I cannot use the ordered list tag for this. Obviously it can be done with a table, but I'd much rather use CSS. However I'm at a loss as to how to do this.

If lines wrap to the next line, they should continue under the text like an ordered list would.

UPDATE I have tried

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

and HTML such as:

xxx
<ol>
    <li>one
        <ol>
            <li>onedotone</li>
            <li>onedottwo
                <ol>
                    <li>A</li>
                </ol>
            </li>
        </ol>
    <li>two</li>
</ol>

produces this

xxx
    1 one
           1.1 onedotone
           1.2 onedottwo
                  (a) A
    2 two

Unfortunately, my requirements are exactly as stated in the original question. So my CSS fails in these areas.

  1. There needs to be a full stop after 1 and after 2 but not after 1.1 and 1.2
  2. 1 and 1.1 should not be indented and the text for both of them needs to be aligned to the same place. So the word onedotone needs to be exactly below the word one. Also there needs to be a bigger gap than one space between the number and the text.
  3. The (a) needs to line up with the words onedottwo, and again there needs to be a bigger gap than one space between (a) and A.

padding-left is not the answer, as it does not help line up the text after the numbers, You get

1 one
1.1 onedotone

instead of

1.     one
1.1    onedotone

This is beyond my CSS capabilities. Unless anyone has the expertise to point me in the right direction, I fear that I will have to fall back on using a table.

Harry
  • 87,580
  • 25
  • 202
  • 214
Steve Waring
  • 2,882
  • 2
  • 32
  • 37
  • 3
    post your relative code please. – Alex Char Nov 18 '14 at 15:10
  • you design a css for a list tag – akshay koli Nov 18 '14 at 15:13
  • Related question and answers - http://stackoverflow.com/questions/1632005/ordered-list-html-lower-alpha-with-right-parentheses and http://stackoverflow.com/questions/4098195/can-ordered-list-produce-result-that-looks-like-1-1-1-2-1-3-instead-of-just-1 – Harry Nov 18 '14 at 15:14
  • @akshaykoli Can you correct my CSS please, it is beyond me. – Steve Waring Nov 18 '14 at 18:30
  • 1
    @Harry Thanks very much, that was very helpful as far as lists go. If I did not have the indentation issues, etc it would be a solution. Because of the very specific requirements I suspect I need to enter the numbers and letters myself and use CSS to format it without using `
      `. But perhaps someone can work out how to get the lists spot on.
    – Steve Waring Nov 18 '14 at 18:34
  • since you are already doing stuff like this "OL LI OL LI OL LI" you might as well target each indentation level and style it the way you want... – MimiEAM Nov 18 '14 at 18:59
  • @MimiEAM I don't know how to style the indentation level so that the numbers and the text lines up as in my diagrams above. This is so easy in a table. Three columns. Things like 1. and l.1 go in col 1 and the text in col2 with colspan=2. For the (a) and (b) they go in columns 2 and the text in column 3. I don't mind entering the numbers in the table columns. I just thought it would be better to use styling, but I can't work out how to do it. The question has been marked down, but the links given do not go anyway to answering the specific question I asked. – Steve Waring Nov 18 '14 at 19:20

1 Answers1

2

Below is a sample on how the desired result can be achieved using <ol> (ordered lists) and CSS counters. It has a bit of a hack-ish feel about it because of the expectation that when a line is wrapped around, it should not start from under the numberings. Otherwise, I feel this method is much better than manually keying in the numbers (or) using tables.

Consistent spacing between the numbering and text is obtained by setting a width to the li:before pseudo-element and making its display as display: inline-block. Modify the width based on how much spacing is required. Note that when modifying the width, the margin-left and padding-left also have to be modified accordingly to maintain the styling.

CSS Counters have reasonably good browser support also.

.level1, .level2, .level3 {
    list-style-type: none;
}
.level1 {
    counter-reset: level1; /* first level counter - for 1, 2, 3 */
}
.level2 {
    counter-reset: level2; /* second level counter - for 1.1, 1.2 */
}
.level3 {
    counter-reset: level3; /* third level counter - for (a), (b) */
}
li {
    display: block;
}
li:not(:last-child):after, li > ol:before{
    content: " ";
    display: block;
    position: relative;
    height: 20px; /* this is filler where height should be equal to required line height */
    left: 0px; top: 100%;
}
.level1, .level2, .level3 {
    margin: 0;
    padding: 0;
}
.level1 > li, .level3 > li {
    padding-left: 40px;
}
li:before {
    margin-left: -40px;
    /* following 2 props are for consistent spacing between numbering and text */
    width: 40px;
    display: inline-block;
}
.level1 > li{
    font-weight: bold;
}
.level1 > li:before, .level1 > li * {
    font-weight: normal;
}
.level1 > li:before {
    content: counter(level1)"."; /* display current item number + dot */
    counter-increment: level1; /* increment counter everytime a new element of that level is encountered */
}
.level2 > li:before {
    content: counter(level1)"." counter(level2); /* format level 1 counter + dot + level 2 counter */
    counter-increment: level2;
}
.level3 > li:before {
    content: "(" counter(level3, lower-latin)") "; /* format ( + level3 counter + ) */
    counter-increment: level3;
}
<ol class='level1'>
    <li>one
        <ol class='level2'>
            <li>one dot one - has some really really lengthy text which wraps around to the next line when it overflows the width.</li>
            <li>one dot two
                <ol class='level3'>
                    <li>A</li>
                    <li>B - has some really really lengthy text which wraps around to the next line when it overflows the width.</li>
                </ol>
            </li>
        </ol>
    </li>
    <li>two - has some really really lengthy text which wraps around to the next line when it overflows the width.</li>
</ol>

Feedback to comments:

  1. The {content: "\a"; white-space: pre;} trick does not quite work with inline-block elements. The inner level li tags are inline-block in our case (for reasons explained above in 2nd paragraph) and hence that particular trick doesn't work. The alternate is to insert a blank filler line with height of the line equal to the required line-height and position it below the li tag. Note that the selector used is li:not(:last-child):after because we don't need an extra line break after the last li (if we do not do it, we will have double line space after the inner li ends). This is a CSS3 selector and so might not work with lower versions of IE. If you need to support those versions also then we would need to tweak it further (or simpler would be to use br).

  2. You were on the correct path here, but the :before pseudo-element (which has the numbering) is not on the element with class='level1'. It was on the .level1 > li and hence doing a reset of font-weight for selector .level1 > li:before, .level1 > li * would fix it. As you would have already known/guessed, .level1 > li * means every element under the level one li.

Harry
  • 87,580
  • 25
  • 202
  • 214
  • 1
    I'm reading this on my phone at the moment. I will test this later today. Thank you. – Steve Waring Nov 19 '14 at 12:47
  • This is almost perfect. I took the line height out as I don't wan't line height. What I was trying to suggest in the original request was a line break after each li element. I have tried `li:nth-child(1):after {content:"\a"; white-space: pre}` with `li ol:before {content:"\a"; white-space: pre}` and it almost works, but there is no break between 1.1 and 1.2 and no break between the (a) and the (b). I can manually add the `
    ` but if your CSS wizardry can fix this it would be brilliant.
    – Steve Waring Nov 19 '14 at 20:16
  • One last ask. I did not put it in the original request, but the text (but not the number) of the level 1 items should be {font-weight: bold}. I can easily add a span but wondered if I could get this to work without. I tried `.level1 {font-weight: bold}` `.level1:before {font-weight: normal}` `.level2, .level3 {font-weight: normal}` This almost works but the number in level 1 is still bold. – Steve Waring Nov 19 '14 at 20:54
  • @SteveWaring: I had updated the answer with solution to the two points. – Harry Nov 20 '14 at 13:29