Skip to content

Step 1 of 5 · Reading · ~4 min

Read

Lists & Code

Tight vs Loose Lists

Two lists that differ by a single blank line produce different HTML. This is not a rendering quirk you can ignore: it is in the spec, every conforming parser does it, and it is the rule most weekend Markdown parsers get wrong. Your program will read one bullet list and decide, for the whole list, whether to print it tight or loose.

The same items, two shapes

Tight, with no blank line anywhere between the items, and the item text is bare:

<ul>
<li>alpha</li>
<li>beta</li>
</ul>

Loose, with one blank line somewhere between two items, and every item gains a paragraph:

<ul>
<li>
<p>alpha</p>
</li>
<li>
<p>beta</p>
</li>
</ul>

Note what changed: every item gained a <p> wrapper, not just the ones adjacent to the blank line. Looseness is a property of the whole list. That is what makes it awkward to implement: you cannot decide how to render item one until you have read item five.

What exactly makes a list loose?

Two conditions, either one is enough:

  1. Any two of its items are separated by a blank line.
  2. Any single item directly contains two block-level elements with a blank line between them. In this exercise that means two paragraphs: a - line, a blank line, then a line indented by two spaces.

And what does not count is just as important:

SituationVerdict
blank line between item one and item twoloose
an item holding two paragraphsloose
blank line before the first itemtight
blank line after the last itemtight: that blank just ends the list
indented lines with no blank line between themtight: they continue the same paragraph
blank line inside a sublistthe outer list stays tight and the sublist is loose

The sublist row catches people. Nesting means a document can hold a tight list whose child list is loose, side by side; the next lesson builds the recursion that makes that possible.

Rendering diagram…

Deciding in one pass

Collect first, decide second, render third. While reading, remember whether you just passed a blank line. When the next non-blank line arrives, look at what it is:

Held stateNext lineEffect
blank seen, items exist- next itemthe list is loose
blank seen indentedthe item gets a second paragraph; the list is loose
no blank indentedthe text joins the current paragraph with a space
blank seenend of inputnothing: trailing blanks never loosen a list

The last row is the whole trick. A trailing blank sets the flag, but no line ever follows it, so nothing is promoted.

Why the spec bothers

Tight lists render compactly because the item text is not a paragraph and gets no paragraph margin. Loose lists give every item full paragraph spacing, which is what you want when items are several sentences long or contain sub-blocks. The author signals the choice with whitespace; the parser has to honour it.

Common mistakes

  • Applying looseness only after the blank line. If the gap is between items two and three, items one and two must be wrapped too.
  • Counting the trailing blank line. A list that ends with an empty line is still tight.
  • Missing the second paragraph. A blank line inside an item makes the list loose even when the items themselves touch.
  • Printing <p> for tight items. Tight items are bare text.

Your exercise

Render one list, given as - item lines with optional two-space-indented continuation lines, as tight or loose. The starter reads the lines and prints what you return.

Up nextNested ContainersLists & Code

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…