How can I prefix ordered list item numbers with a static string using CSS?

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).


Solution 1:

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.

Solution 2:

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.

Solution 3:

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.