Block Level Elements Inside Inline Elements

Can inline elements contain block elements?

Leaving aside the fact that LI and P are both block level ...

It's never valid to do so, but in behavioural terms, sometimes you can nest a block level element inside a inline level one, but it depends on the browser parser.

For example, in FireFox 3.x, with this markup

<!DOCTYPE html>
<i>
foo
<div>bar</div>
baz
</i>

will display foo, bar, and baz all in italics.

But this markup, replacing the inline element <i> with inline element <var> (which also has italics as its default rendering)

<!DOCTYPE html>
<var>
foo
<div>bar</div>
baz
</var>

will only display foo in italics.

JSFiddle for this

Other browsers do not behave the same. Which is one reason why you should stick to using valid markup.

Are block-level elements allowed inside inline-level elements in HTML5?

yes what you've written is valid in HTML5, but it's not all inline elements, I think it's just <a> 's it applies to..

Reference: “Block-level” links in HTML5

Tip: if using this set the <a> to display: block; or there may be unintended visual styling results : Source: Test Case

Update:

It is "disallowed" for other "block in inline" combinations where "default styles are likely to lead to confusion" - explanation is here:

Cases where the default styles are likely to lead to confusion

Certain elements have default styles
or behaviors that make certain
combinations likely to lead to
confusion. Where these have equivalent
alternatives without this problem, the
confusing combinations are disallowed.

For example, div elements are rendered
as block boxes, and span elements as
inline boxes. Putting a block box in
an inline box is unnecessarily
confusing; since either nesting just
div elements, or nesting just span
elements, or nesting span elements
inside div elements all serve the same
purpose as nesting a div element in
a span element
, but only the latter
involves a block box in an inline box,
the latter combination is disallowed.

Block element inside inline-block acting strangely in Firefox

Yes, interesting question. First we need understand that the default vertical alignment of inline-block elements is baseline, and the baseline of each such element is the baseline of the last line box in them.

In the second div with class "b", the inner div itself contains a line box to hold the '/' character. That then provides the baseline for the second div with class "b".

That baseline must align level with the baseline of the first div with class "b". The question becomes: where is the baseline of the last line box in that div?

By making the input element itself display:block, Firefox¹ takes the view that the input element is "replaced", it's contents are opaque to CSS, therefore no line box is ever created by the input element. So the last line of the first div with class "b" is the one containing the label, and that is aligned level with the line of the '/' character.

Chrome takes a different view. Chrome treats the input element as having an internal structure visible to CSS, so the innards of the element form a line box, whose baseline then becomes the baseline of the first div with class "b", and it is that which aligned level with the '/' character.

When you add `overflow:hidden', it affects the baseline of the inline-blocks such that their baselines cease to be the baseline of their last contained line box, and becomes the bottom margin edge of the element.


Which behaviour is correct is unclear. It depends on history and the somewhat adulterated notion of replaced elements. In the early days of browsers, the rendering of some elements was delegated to external systems, either the underlying operating system or a plug-in. In particular, this was true of the input element, where rendering was done by O/S calls. The O/S had no notion of CSS, so rules had to be defined to allow the effectively black boxes to interact with the rest of the page. Such elements were classified as "replaced" elements.

Note the way this is defined. There is no official list of elements that are replaced elements, an element is a replaced element if the browser chooses to delegate its rendering to a system outside the CSS world, so in theory you could have two browsers, one delegating the rendering of an element and one natively rendering it, and from the CSS rules get quite different interactions.

As browsers progressed, they stopped delegating their rendering of the input element and rendered it themselves, in the process making the renderings CSS aware. This causes a problem because extant web pages, which assume that the input elements will be rendered using the replaced elements' rules, can become unusable. If a browser allowed that to happen, it would lose market share. So for the most part, to avoid this, the browsers implement those elements' layouts to interact with the page as if they were replaced elements, even though in reality they are not.

How far they go in this respect is not well specified. The HTML5 spec does not recognise the form controls as replaced elements, and suggests that they be rendered as inline-block, which would make Chrome's behaviour correct, but there are many ways in which all the browsers including Chrome simply don't behave that way. From a backward compatibility perspective with old web content, the Firefox behaviour is more reliable.

Until the layout of form controls is specified much more tightly than is the case currently, it is impossible to conclusively say which behaviour is correct.


¹For me, IE11 behaves like Firefox. Opera 28 (blink engine like Chrome) behaves like Chrome. Opera 12 (presto engine) behaves like Firefox.

Is it possible for an inline element to validly have a block level element descendant?

The W3C validator (in XHTML mode) lists the following elements as valid between a <span> and a <p>:

  • object
  • ins
  • del
  • map
  • button

A page using these as inline-to-block spanners validates in XHTML Strict, but not in HTML 5. Of these tags, I would favor object, since it has the least semantic baggage.

HTML 5 seems to have discarded the inline vs. block distinction in favor of a more complex system, in which there are several different categories of element, and which children an element can have depends on what its ancestors are. Of these elements, ins, del and map now accept the same kind of children that their parent element accepts, and button only accepts "phrasing content" (the closest thing to inline elements). The error message for object doesn't make much sense, but as near as I can gather, it's inheriting the parent element's restrictions while also imposing some restrictions of its own.

As near as I can tell, there's no way to escape from phrasing content once you're in it (short of an iframe and a new document), so the answer to this question is no, can't be done in HTML5 (as of this writing).

How to put a block-level element inside an inline element?

You already know that it's invalid HTML. So, to conform to the standard practice and still achieve what you want reuse your spanclass CSS to define a new CSS class as

spanclass, divlikespanclass {
/* span css data */
}

and change your HTML to

<div class="divlikespanclass">
<div class="divclass">Content</div>
</div>

or, simply

<div class="divclass divlikespanclass">Content</div>

EDIT : (in response to OP's comments; not recommended though)

Re-declare <SPAN> as

<!ELEMENT SPAN - - ((%inline;) | DIV)*  -- generic language/style container -->

or, to apply to all inline elements change

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

Why is block level element contained inside inline-block level element displayed as inline?

There's no place for your span element to take the entire width of the page. Technically, you are rendering a block level element inside an inline block element. So your block level element does take 100% of the parent width.

Since there is no width defined for the parent inline-block, it takes whatever space it gets inside the inline-block element. To demonstrate this, if I assign some width to the inline-block element of yours, the span will take all the available width of the parent element.

a {
display: inline-block;
padding: 1em 7em;
width: 400px; /* define some width here to the parent */
background-color: green;
}

span {  background-color: red;  display: block;}a{  display: inline-block;  padding: 1em 7em;  width: 400px;  background-color: green;}
<a>  <span> close </span></a>

Why should we not place block elements inside inline elements

If I place a div element inside an anchor element, it invalidates my HTML.

This is not true as of HTML5.

What is the reason of not placing block level elements inside inline elements?

The HTML specification describes which elements may contain other elements. "Flow content" can often contain "Flow Content", or "Phrasing Content", but even this is not always the case. For example, a p element is a block level element, but it may only contain "Phrasing Content".



Related Topics



Leave a reply



Submit