Nesting Block Level Elements Inside the ≪P≫ Tag... Right or Wrong

Nesting block level elements inside the p tag... right or wrong?

Syntactically, a div inside a p is invalid in all standards of HTML. Moreover, when using a conforming HTML parser, it is impossible to place a <div> element inside a <p> in the DOM because the opening <div> tag will automatically close the <p> element.

Semantically, the correct choice depends on the content that you are marking up. You will need to show at least a sample full paragraph and possibly the content surrounding it to be sure of providing sufficient information for the correct semantic mark-up to be determined.

However, given that both <div> and <span> are semantics free, and that CSS in no way can ever change that, if you are certain that the contents of the <p> tag truly form a paragraph, and that <span style="display: block"> gets you the presentational effect that you are seeking, then that is valid HTML and would be a wholly appropriate solution.

Why p nested in span leads for a block element?

You simply cannot nest a p element inside a span element. The span element's content model should be phrasing content, which excludes elements such as p and heading elements. Since the span element's end tag is not omissible (i.e. it is required), the p element's start tag does not implicitly close the span element, so you get a validation error. However, browsers try to recover from the error, and they still render the p element as a block element.

To avoid this type of error in the future, I recommend validating HTML code using the W3C's HTML Validator and consulting the consulting the HTML5 specification (or a similar reference) about content models.

div nested in p

The <div> tag, like <p> is a block level element, which means that it is designed to contain it's own block of with newlines around it. Trying to nest a <div> inside of a <p> is not likely to do what you want as it doesn't make much sense. A <p> is a paragraph, and it should contain no block level elements. This question may would be related:

https://stackoverflow.com/questions/4291467/nesting-block-level-elements-inside-the-p-tag-right-or-wrong

Try using <span> instead, because <span> is an inline element, which is designed to be displayed inside of a paragraph. If you really do need multiple block level elements there, consider not using the <p> there at all, or using them as the inner most block level element rather than an outer element.

Nesting p won't work while nesting div will?

Because a paragraph is a paragraph .. and that's how HTML is defined (and HTML is not XML).

Any <p> (or other block-level element) will implicitly close any open <p>.

Per 9.3.1 Paragraphs: the P element of the HTML 4.01 specification:

The P element represents a paragraph. It cannot contain block-level elements (including P itself).


Note that this is how the HTML is parsed and that even a <div> would have implicitly closed the paragraph!

However, a <span> with display:block; would not have closed the <p> as a <span> is not a block-level element.

That is, the CSS is irrelevant at this stage of the HTML processing and the CSS is irrelevant to the DOM/parser when determining if an element is a block-level element or not. Consider the case when CSS is applied dynamically or through a not-yet-loaded-stylesheet: the applied CSS does not alter the DOM.


While the HTML5 (working-draft) specification does not include the language above in the HTML4 specification, it does go on to define a paragraph as a container for phasing content and further has a section on paragraphs.

The accepted answer to List of HTML5 elements that can be nested inside P element? says that <p> elements cannot nest in HTML5. The key phrase from the documentation is: "Runs of phrasing content [which does not include <p> elements] form paragraphs". Furthermore, HTML5, trying to be backwards-compatible in many aspects, has a rationale on "Restrictions on content models and on attribute values":

Certain elements are parsed in somewhat eccentric ways (typically for historical reasons), and their content model restrictions are intended to avoid exposing the author to these issues.

This behavior is referenced from a HTML5 WG wiki entry on flow content:

HTML5's restrictions on nesting of p elements and on what p elements may contain, are due to, quote: “peculiarities of the parser” that causes p to be auto-closed ..

Why can't I nest div inside p?

In the beginning, there was the Standard Generalized Markup Language (SGML). SGML defined some aspects of the syntax like punctuation and tags, but each user application defined parts of the syntax such as tag names, attributes, nesting.

Decades later, SGML was simplified to create the XML standard. The way XML is used today for many application-specific data formats is similar to how SGML was used in the past. SGML and XML are essentially meta-languages - they are a syntax template for many application-specific languages.

HTML was initially designed as an application of SGML, hence understanding the history of HTML requires knowledge of some rules of SGML. SGML was intended to be editable in a text editor, so it included many features that reduced code to make human writing and reading more convenient. Just a few examples:

  • Some elements like <br> are self-terminating, thus never have a corresponding </br> end tag.
  • Some elements like <tbody> are implicitly inserted, e.g. <table><tr><td></td></tr></table> becomes <table><tbody><tr><td></td></tr></tbody></table>.
  • Some elements like <p> cannot nest in each other, so starting one will terminate the old one: <p><p> becomes <p></p><p></p>.

These element/tag-level syntax features are enabled/disabled through the SGML declaration and document type definition (DTD). HTML up to version 4.01 certainly had a DTD, and this was considered as the source of truth on how a parser should interpret markup code. The DTD can also tell us things like (not an exhaustive list):

  • What attributes each element is allowed to have.
  • Whether an attribute is optional, required, or has a default value.
  • Distinctions between PCDATA and CDATA, which affects how characters are escaped.
  • Exactly what elements are allowed to nest within what.

The DTD is where we can find our answer, at least historically speaking for HTML 4.01 Strict:

<!ELEMENT P - O (%inline;)*            -- paragraph -->

<!ENTITY % inline "#PCDATA | %fontstyle; | %phrase; | %special; | %formctrl;">

<!ENTITY % fontstyle
"TT | I | B | BIG | SMALL">

<!ENTITY % phrase "EM | STRONG | DFN | CODE |
SAMP | KBD | VAR | CITE | ABBR | ACRONYM" >

<!ENTITY % special
"A | IMG | OBJECT | BR | SCRIPT | MAP | Q | SUB | SUP | SPAN | BDO">

<!ENTITY % formctrl "INPUT | SELECT | TEXTAREA | LABEL | BUTTON">

The code above says that a <p> element can only contain %inline content, which is further defined as any of #PCDATA, %fontstyle, %phrase, %special, %formctrl. The definitions of the latter 4 are a set of 31 elements like <tt>, <strong>, <img>, <textarea>, etc. Notice that these so-called inline elements do not include block elements like <div>, <ul>, and so on - so in other words, <p> cannot contain <div>.

I don't know how the details of how the SGML parser behaves in every situation, but it looks like when one element is not allowed to contain another, the first element is terminated and then the second element begins. This explains why <p><div></div></p> becomes <p></p><div></div><p></p>.

Fast forward to HTML5, which is not based on SGML anymore. Although HTML5 is a bespoke, one-of-a-kind syntax standard, it is intended to be backward-compatible with HTML 4. HTML5 replicates the semantics of correct HTML 4 code, and additionally mandates a uniform way to parse erroneous markup code ("tag soup") so that all browsers behave the same. So the interpretation of <p><div></div></p> is still unchanged from the SGML days.

For <p> in particular, the rule is explained very clearly here here:

A p element's end tag can be omitted if the p element is immediately followed by an address, article, aside, blockquote, details, div, ...

Also, <p> is only allowed to contain "phrasing content" (note the lack of <div>):

Phrasing content is the text of the document, as well as elements that mark up that text at the intra-paragraph level. Runs of phrasing content form paragraphs.
a, abbr, area (if it is a descendant of a map element), audio, b, bdi, bdo, br, button, canvas, cite, code, data, datalist, del, dfn, em, embed, i, [...], autonomous custom elements, text

Floating a block-level element inside a paragraph

My friend, Pavel Panchekha, found another method that doesn't need to change <p> to <div>: use <object> instead of <span>:

p {  font-family: Arial;  position: relative;  padding-right: 120px;}
.note-num { font-size: 10px; margin: 0 1px 0 -3px;}
.note-content { position: absolute; right: 0; font-size: 12px; max-width: 100px;}
.note-content ul { margin: 0; padding: 0;}
<p>  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.  <sup class="note-num">1</sup>  <object class="note-content">    <ul><li>Block Note</li></ul>  </object>  Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>

Putting div inside p is adding an extra p

From the fine specification:

p – paragraph

[...]

Permitted contents

Phrasing content

And what is this Phrasing content?

Phrasing content:

Consists of phrasing elements intermixed with normal character data.

Normal character data is just that: unmarked up text. Phrasing elements are:

a or em or strong ... [a bunch of other elements none of which are div]

So, <p><div></div></p> is not valid HTML. Per the tag omission rules listed in the spec, the <p> tag is automatically closed by the <div> tag, which leaves the </p> tag without a matching <p>. The browser is well within its rights to attempt to correct it by adding an open <p> tag after the <div>:

<p></p><div></div><p></p>

You can't put a <div> inside a <p> and get consistent results from various browsers. Provide the browsers with valid HTML and they will behave better.

You can put <div> inside a <div> though so if you replace your <p> with <div class="p"> and style it appropriately, you can get what you want.

Your reference at about.com disagrees with the specification at w3.org. Your reference is misleading you.



Related Topics



Leave a reply



Submit