24

I want this HTML:

<ol style="list-style:decimal;">
<li>Apples</li>
<li>Oranges</li>
</ol>

to render like this:

Q1. Apples
Q2. Oranges

Ie, I want to prefix "Q" to each number.

I've tried CSS like this:

ol li::before {
  content: "Q";
}

but that renders like this:

1. QApples
2. QOranges

I've also tried using list-style: numbered inside;, but that just shifts the list to the right with the same results. I can't find any way to reference the numbers in order to style them with CSS. This seems like such a simple, common scenario, yet I can't find any way to accomplish it with straightforward CSS (without CSS counters, JavaScript, etc).

ma11hew28
  • 121,420
  • 116
  • 450
  • 651
Triynko
  • 18,766
  • 21
  • 107
  • 173

3 Answers3

46

The only pure CSS way is with counters:

ol {
    counter-reset: item;
    list-style-type: none;
}

ol li:before {
    content: 'Q' counter(item, decimal) '. ';
    counter-increment: item;
}

You cannot achieve this besides using CSS counters (which were designed specifically for such use cases!) or JavaScript.

By the way, it's decimal, not numbered.

Wouter
  • 1,829
  • 3
  • 28
  • 34
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • Thank you, this is probably exactly what I'm looking for and it's relatively simple. I'm not necessarily opposed to using the counter, if it's actually this simple. My only reservation is... what's the browser support like for this? – Triynko Apr 06 '11 at 14:47
  • @Gaby: Oops, I missed that. Thanks for the upvote though. @Triynko: Well, admittedly IE support is pretty poor... you can test it here http://jsfiddle.net/BoltClock/9VdB3 – BoltClock Apr 06 '11 at 14:47
  • 2
    Also, thanks for the correction on using "decimal" rather than "number" (I edited my original post to correct this); however, in this particular case, it actually needs to be "none", since the numbering is coming from the content style. In that sense, this solution dodges the original question, since it's still not doing anything with the numbered list items, although it achieves the desired results. I'm marking this as the answer unless someone discovers some magical "ol:listnumber:before" selector, haha. – Triynko Apr 06 '11 at 14:55
  • 1
    +1. I wouldn't ever believe that this could work, but I tried it and all modern browsers showed the content correctly. – Damb Apr 06 '11 at 14:59
  • 4
    I had to change `list-style-type: decimal;` on the `ol` to be `list-style-type: none;` in order to not get double numbers. – baacke Jan 16 '14 at 16:51
  • Seems to be supported by all browsers for quite a while now, including IE8+: http://caniuse.com/#feat=css-counters – konrad Feb 15 '17 at 10:53
  • Is it possible to mix numbering styles using counter(s)? Like if I wanted to have a nested numbering like 5a. 5b. 5c.ii? – B T Oct 19 '17 at 21:10
  • 1
    Thanks for the edit, @Wouter. It was rejected but I uh... used my mod powers to approve it. I really should've fixed it when baacke mentioned it like 6 years ago. – BoltClock Mar 10 '20 at 03:15
  • @BoltClock: haha :) Thx – Wouter Mar 10 '20 at 08:17
3

There is a, fragile, non-counter method, but it's prone to breaking:

ol {
    list-style-type: decimal;
    margin: 0 0 0 2em;
}

li {
    position: relative;
}

ol li:first-letter {
    color: #f90;
    float: left;
    position: relative;
    margin-left: -2em;
}

JS Fiddle demo.

David Thomas
  • 249,100
  • 51
  • 377
  • 410
  • Yeah, I'm trying to avoid unstable/complex/not-well-supported solutions. The counter solution is stable/simple/well-supported. The fragility of this example rests in that it requires the list number prefix to be a particular size (although using a relative unit like EM instead of PX probably helps insulate it against breaking from font-size changes). I had thought of a similar solution using li:before {content}, but using hard-coded offsets won't support variable-length prefix strings. Plus 1 for implementing it anyway! – Triynko Apr 06 '11 at 15:16
1

Given this HTML:

<ol class="q">
  <li>Apples</li>
  <li>Oranges</li>
</ol>

you could (1) use the @counter-style CSS at-rule:

@counter-style q {
  system: extends decimal;
  prefix: "Q";
}

ol.q {
  list-style: q;
}

(See W3C: CSS Counter Styles Level 3: 3.1.7. Building from Existing Counter Styles: the extends system.) or (2) use CSS counters and the ::marker CSS pseudo-element:

ol.q {
  counter-reset: q;
}

ol.q > li {
  counter-increment: q;
}

ol.q > li::marker {
  content: "Q" counter(q) ". ";
}

Either way, you could set the list-style-position CSS property via the list-style CSS shorthand property to the value inside in order to make the rendered HTML appear like that of BoltClock's answer.

HTML edits: I removed style="list-style:decimal;" because I think that's the default for ol elements. I added class="q" so that the styling only applies to specific lists. I indented each li element by two spaces because I prefer that style.

ma11hew28
  • 121,420
  • 116
  • 450
  • 651