Search code examples
htmlnewlinewhitespacew3c

Why does a PRE element with newlines do not produce blank lines in the output?


Example 1

pre {
  background: lightblue;
}
<pre>
<code>
foo
</code>
</pre>

Blank lines appear above and below foo. This is expected because there are newlines in the PRE element.

Example 2

pre {
  background: lightblue;
}
<pre><code>
foo
</code></pre>

A blank line appears above foo but not below it. Why?

Example 3

pre {
  background: lightblue;
}
<pre><code>foo</code></pre>

There are no blank lines before or after foo anymore because there is no newline in the HTML code.

Example 4

pre {
  background: lightblue;
}
<pre>
<code>foo</code>
</pre>

There are newlines after <pre> and before </pre>. So I was expecting blank lines before and after foo in the output. Why are there no blank lines in this example?

Question

  1. Why only one blank line appears in example 2?
  2. Why are there no blank lines in the output of example 4?

Solution

  • Example 1 has similarities to example 4. I'll come back to this...

    Examples 2 and 3 are the basic cases. In example 2, ignoring the code tags, you have the pre start tag, a new line character that creates the blank line, "foo", a new line character that ends that line and then immediately the pre end tag. Note that a single space before the end tag is sufficient to create a blank line under the "foo" line.

    Example 3 contains no new lines at all. But pre is, by default, a block level element so "foo" appears on a line of its own anyway. Nothing more to say about this.

    Example 4 is like example 2 except that the code tags have moved lines. This exposes a particular oddity of the HTML parser. The HTML parsing algorithm says:

    ↪ A start tag whose tag name is one of: "pre", "listing"

    If the stack of open elements has a p element in button scope, then close a p element.

    Insert an HTML element for the token.

    If the next token is a U+000A LINE FEED (LF) character token, then ignore that token and move on to the next one. (Newlines at the start of pre blocks are ignored as an authoring convenience.)

    Set the frameset-ok flag to "not ok".

    So the initial new line character, which immediate follows the pre start tag, gets dropped on the floor and there is no blank line before the "foo" line. Whereas in Example 2 the code start tag is the token which immediately follows the pre start tag, causing the new line character which follows that to not be ignored.

    Example 1 is likewise. The initial new line following the pre start tag is ignored, the new line following the 'codestart tag creates a blank line, then the foo line and its new line character, then the new line following the 'code end tag creates a blank line below the "foo" line, and them the pre element ends.