List rendering is the most common source of 'it looks different on GitHub' bugs.
The core rule: a list item's content column is set by the marker plus the spaces after it. For - foo it is column 2; for 10. foo column 4. Anything that belongs to the item, such as a second paragraph, a code block or a sub-list, must be indented to at least that column.
Consequences:
- A sub-list under
1. itemneeds three spaces, not two; under- item, two suffice. Using four everywhere usually works, but more than the content column plus three makes the line an indented code block. - After a list marker you can use 1 to 4 spaces. With 5 or more, the item starts with an indented code block.
- Changing the bullet character (
-to*) or the ordered delimiter (.to)) starts a new list.
Tight vs loose: if any items are separated by blank lines, or an item contains blocks separated by blank lines, the list is loose and every item's text is wrapped in <p>, giving more spacing. One stray blank line changes the spacing of the whole list.
Starting number: only the first item's number matters, up to 9 digits. To interrupt a paragraph, an ordered list must start with 1, so a sentence that wraps onto a line beginning 14. doesn't become a list. A bullet list can interrupt a paragraph, but an empty list item cannot.
Example
1. Install
- sub-item: three spaces align with "Install"
2. Configure
A second paragraph in item 2 (makes the list loose).
an indented code block inside the item (3 + 4 spaces)
- tight item
- tight item
* a new list, because the marker changed
The meeting ran until
14. this is not a list: only 1. can interrupt a paragraphRemember
- Item content starts at marker width plus following spaces; nested blocks indent to that column
- Blank lines between items or blocks make the whole list loose
- Only a list starting at 1 can interrupt a paragraph
Watch out for
- Indenting a sub-list under a numbered item with two spaces, which some renderers treat as a sibling item.