607

I've heard that putting a block element inside a inline element is a HTML sin:

<a href="http://example.com">
    <div>
        What we have here is a problem. 
        You see, an anchor element is an inline element,
        and the div element is a block level element.
    </div>
</a>

But what about if you style the outer anchor as display:block in the stylesheet? Is it still wrong? The HTML 4.01 spec on block-level and inline elements seems to think so:

Style sheets provide the means to specify the rendering of arbitrary elements, including whether an element is rendered as block or inline. In some cases, such as an inline style for list elements, this may be appropriate, but generally speaking, authors are discouraged from overriding the conventional interpretation of HTML elements in this way.

Does anyone have any further tips about this issue?

Community
  • 1
  • 1
Tom
  • 14,041
  • 16
  • 64
  • 80
  • 3
    See also: http://stackoverflow.com/questions/1091739/html-div-in-link-problem . – DisgruntledGoat Dec 01 '09 at 19:55
  • @DisgruntledGoat - Thanks for the link - wish I'd seen that sooner :-) – Tom Dec 01 '09 at 21:08
  • The anchor and\or link element is a browser automation control. And therefore it has a browser predefined rendering and behavior. To wrap a genuine plain html element: div inside a span however is a sin. The reason behind the fact that A tag doesn't add any level behavior is a requirement in marking up parts of text without disturbing the document flow, not because they are meant to be inline elements. From that pov, A, is a do nothing tag. Its existence is beyond the issue and not a sin, but may contribute to code ugliness and\or ambiguity. – Bekim Bacaj Dec 20 '16 at 00:21
  • 1
    Everyone else who checks here in the future, please note that while anchor tags ARE able to contain block level elements isnide them in HTML5, they cannot contain a block level element that contains other anchor tags! Because basically, anchor tags cannot have other anchor tags inside them whatsoever. You can read more on that here: https://stackoverflow.com/questions/13052598/creating-anchor-tag-inside-anchor-tag – aderchox Mar 21 '20 at 15:14

16 Answers16

856

Depending on the version of HTML you're catering to:

  • HTML 5 states that the <a> element "may be wrapped around entire paragraphs, lists, tables, and so forth, even entire sections, so long as there is no interactive content within (e.g. buttons or other links)".

  • HTML 4.01 specifies that <a> elements may only contain inline elements. A <div> is a block element, so it may not appear inside an <a>.

    Of course you are at liberty to style an inline element such that it appears to be a block, or indeed style a block so that it is rendered inline. The use of the terms inline and block in HTML refers to the relationship of the elements to the semantic structure of the document, whereas the same terms in CSS are related more to the visual styling of the elements. If you make inline elements display in a blocky manner, that's fine.

    However you should ensure that the structure of the document still makes sense when CSS is not present, for example when accessed via an assistive technology such as a screen reader - or indeed when examined by the mighty Googlebot.

Peter Majeed
  • 5,304
  • 2
  • 32
  • 57
NickFitz
  • 34,537
  • 8
  • 43
  • 40
  • Can you explain where the HTML 4.01 spec "specifies that elements may only contain inline elements"? I can't find it. – Ewan Todd Dec 01 '09 at 18:55
  • 4
    There is a DTD for 4.01 at http://www.w3.org/TR/REC-html40/sgml/dtd.html . A can contain %inline%; %inline% is a bunch of different stuff (you can follow the links) but DIV is not among them. Thus, an A with a DIV inside is not XML-validatable. I think that DTD expresses the intentions of the committee pretty well, so I'd say: No. – Carl Smotricz Dec 01 '09 at 19:18
  • 2
    @Ewan: the first link in my answer is to the relevant section of HTML 4.01. – NickFitz Dec 02 '09 at 10:46
  • 2
    `<!ELEMENT A - - (%inline;)* -(A)` to be specific, the `(%inline;)*` part of the spec says only contain inline elements. More on reading DTD docs: http://www.w3schools.com/dtd/dtd_elements.asp – Brian Chavez Jul 13 '11 at 09:26
  • 66
    I was about to ditch the possibility to do this in a project until I read the last line about HTML5, that's good to know, thanks. – Elaine Marley May 08 '12 at 14:34
  • 1
    If you do `
    ` is a div then valid inside an `a`?
    – AaronLS Feb 08 '13 at 23:18
  • 19
    The Mozilla Developer Network (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) reflects the fact HTML5 elements now supports flow content elements like
    ,
      or .
    – AxeEffect Dec 05 '13 at 17:44
  • 2
  • 1
    Anyone reading this answer should click on the links he provided, hypertext on "HTML 4.01" and "HTML 5." Reading the actual docs will enable you to have an answer not based on opinion. – aaron-coding Feb 12 '15 at 18:20
  • i also found that Chrome doesn't properly see it as a link. It doesn't show on the status bar the address. – pcarvalho Feb 17 '15 at 01:30
  • as some other people have mentioned, read the HTML5 spec (at this point you should hopefully be able to use that..if not...i'd find a new job =P) and look for the "code example" at the bottom of the anchor spec. It explicitly wraps an anchor tag around a `section` which contains a `h1` and `p` tags. According to the spec, this should be totally valid. – hellatan Jun 15 '15 at 14:21
  • 1
    wrapping a div in an anchor tag worked for me on an IE9 windows 7 virtual machine. – Kevin Wheeler Jul 07 '15 at 01:43
  • 23
    Under HTML5, an *a* element is classed as *transparent*, which means it can contain *flow* elements (read *default=block*) ONLY if the parent of the *a* element can contain *flow* elements. Otherwise, only *phrasing* elements (read *default=inline*) are allowed. Thus, if the *a* is in a *form* or *div*, it can contain a *div*, but inside a *p*, it can't. See http://www.w3.org/TR/html-markup/terminology.html – Patanjali Oct 24 '16 at 01:00
  • Yes, as @Patanjali mentioned, an `a` inside `p` will cause problem and separate into two `p`s before and after the `a` and its descendents. (The link has changed to https://www.w3.org/TR/2012/WD-html-markup-20120329/terminology.html ) – chenghuayang Aug 17 '21 at 14:30
  • Most up to date link for a element on HTML 5 is [here](https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-a-element). ( https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-a-element ) – vee Feb 01 '22 at 16:04
83

No it won't validate, but yes it generally will work in modern browsers. That being said, use a span inside your anchor, and set display: block on it as well, that will definitely work everywhere, and it will validate!

dtbarne
  • 8,110
  • 5
  • 43
  • 49
Eloff
  • 20,828
  • 17
  • 83
  • 112
35

The W3C doc doesn't use concepts like wrong and sin, but it does use those like provide the means, may be appropriate and discouraged.

Actually, in the second paragraph of section 4, the 4.01 spec itemizes its words as follows

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119]. However, for readability, these words do not appear in all uppercase letters in this specification.

With that in mind, I believe the definitive statement is in 7.5.3 Block-level and inline elements, where it says

Generally, inline elements may contain only data and other inline elements.

The condition "generally" appears to introduce enough ambiguity to say that HTML 4.01 does allow inline elements to contain block elements.

Certainly, CSS2 has a display property value, inline-block, that appears to be suited to the purpose you describe. I'm not sure if it was ever widely supported, but it seems that someone anticipated the need for that kind of behavior.

The DTD appear to be less forgiving here, but the text of the DTD defers to the spec:

The HTML 4.01 specification includes additional syntactic constraints that cannot be expressed within the DTDs.

In another comment, you suggest that you want to make a block active by wrapping it in an anchor. I don't believe HTML prohibits that, and CSS clearly allows it. So to answer the title question about whether it is ever correct, I say yes. By the standards, it is sometimes correct.

Ewan Todd
  • 7,315
  • 26
  • 33
  • 2
    You had me until you mentioned doctype. – Robert Harvey Dec 01 '09 at 18:34
  • You're probably right - I should have used doctype.com. Opps - I'll try to remember for next time around. PHP -> SO, HTML -> doctype.com – Tom Dec 01 '09 at 18:41
  • I'm don't have a strong preference of forum for this question. I'm interested in Robert Harvey's take on doctype, though. – Ewan Todd Dec 01 '09 at 18:46
  • 2
    My take is there's not a "vote to close as belongs on doctype.com" option (nor should there be). – Robert Harvey Dec 01 '09 at 19:00
  • 7
    I agree with Rob - Stack Overflow is for programming. HTML/CSS is certainly programming in my view. – DisgruntledGoat Dec 01 '09 at 19:58
  • Writing standards seems to be an exercise in how many weasel words can be packed into a single document, and how many creative ways can they be combined to produce the most ambiguity... – Eloff Jul 15 '11 at 00:13
18

With HTML5 specification... It is now possible to put a block-level element inside of an inline element. So now it's perfectly appropriate to put a 'div' or 'h1' inside of an 'a' element.

Abir
  • 181
  • 1
  • 2
  • 9
    Only inside *flow* (default = *block*) elements, or *transparent* elements (like *a*) with parents that allow *flow* elements. For example, *p* doesn't allow *flow* elements (like *div*), but only *phrasing* elements (default = *inline*), so an *a* inside a *p* cannot contain a *div*. However, an *a* inside a *div* can contain *p*s, *div*s or any other *flow* element. – Patanjali Oct 24 '16 at 01:11
18

Update in Jan, 2023: latest HTML5 version

This is an example I took from their website:

<a href="/components/badge">
  <div class="mat-list-item-content">
    <div mat-ripple="" class="mat-ripple mat-list-item-ripple"></div>
    <div class="mat-list-text"></div>
  </div>
</a>
KienHT
  • 1,098
  • 7
  • 11
7

Block level elements like <div> can be wrapped by <a> tags in HTML5. Although a <div> is considered to be a container/wrapper for flow content and <a>'s are considered flow content according to MDN. Semantically it may be better to create inline elements that act as block level elements.

Beepye
  • 328
  • 2
  • 11
  • 1
    As *a* elements are *transparent*, only if the parent element of the *a* allows *flow* (default as *block*) elements. – Patanjali Oct 24 '16 at 01:14
5

You can't put <div> inside <a> - it's not valid (X)HTML.

Even though you style a span with display: block you still can't put block-level elements inside it: the (X)HTML still has to obey the (X)HTML DTD (whichever one you use), no matter how the CSS alters things.

The browser will probably display it as you want, but that doesn't make it right.

Greg
  • 316,276
  • 54
  • 369
  • 333
5

If you want to avoid the semantic trouble of placing divs inside anchor tags, just place the anchor tag on the same level as the divs, wrap them all with a container with position: relative, make your anchor tag position: absolute and expand it to fill the container. Also if it's not on the end of the content flow make sure you throw a z-index in there to place it above the content.

As suggested I have added a markup code:

<div class="div__container>
  <div class="div__one>
  </div>
  <div class="div__two">
  </div>
  <a href="#"></a>
</div>

And the css:

.div__container {
  position: relative; 
}
.div__container a {
  position: absolute;
  top: 0;
  bottom: 0;      
  left: 0;
  right: 0;
  z-index: 999;
}
Eugen
  • 145
  • 2
  • 2
4

There's a DTD for HTML 4 at http://www.w3.org/TR/REC-html40/sgml/dtd.html . This DTD is the machine-processable form of the spec, with the limitation that a DTD governs XML and HTML 4, especially the "transient" flavor, permits a lot of things that are not "legal" XML. Still, I consider it comes close to codifying the intent of the specifiers.

<!ELEMENT A - - (%inline;)* -(A)       -- anchor -->

<!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">

I would interpret the tags listed in this hierarchy to be the total of tags allowed.

While the spec may say "inline elements," I'm pretty sure it's not intended that you can get around the intent by declaring the display type of a block element to be inline. Inline tags have different semantics no matter how you may abuse them.

On the other hand, I find it intriguing that the inclusion of special seems to allow nesting A elements. There's probably some strong wording in the spec that disallows this even if it's XML-syntactically correct but I won't pursue this further as it's not the topic of the question.

Carl Smotricz
  • 66,391
  • 18
  • 125
  • 167
2

you can achieve this by adding "::before" Pseudo-element

Pure CSS Trick ;)

a:before{
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1;
  pointer-events: auto;
  content: "";
  background-color: rgba(0,0,0,0);
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet"/>
<div class="card" style="width: 18rem;">
  <img src="https://via.placeholder.com/250" class="card-img-top" alt="...">
  <div class="card-body">
    <h5 class="card-title">Card with stretched link</h5>
    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
    <a href="#" class="btn btn-primary stretched-link">Go somewhere</a>
  </div>
</div>
AkshayKumar
  • 125
  • 1
  • 2
2

Anything works ... until you nest them.

You can stuff in tables and divs and birds and bees, and the browser will patiently play along. But as soon as you put another <a> tag inside, it will break them apart, putting the inner tag after the closing of the outer one. It's worth a try, even in the F12 console, you'll be surprised how strict your browser can be when it doesn't like something.

So there is NO SUCH THING as:

<a href="#1">
    <a href="#2"> Now what </a>
</a>

Instead, it will become:

<a href="#1"></a>
<a href="#2"> Now what </a>

The same thing happens with <p> and a few others; in fact, there's a Stacko article about this - Can I nest these tags? - and the only answer has the key, look for the bulleted list at the "HTML specifications indicate" part. The pickiest ones are clearly a and p, with honorable mentions like h1..h6. (Now let's be honest: have you ever used a p tag specifically because it gave you something no one else could?... Thought so. I'd just ditch it.)

TL;DR - you can't put a inside a.

dkellner
  • 8,726
  • 2
  • 49
  • 47
1

If you're going to go to the effort of making <a> block, why not put <a> inside the div, being a block element it'll give you the same effect.

Dave
  • 698
  • 4
  • 12
1

If you change it to a block-style element, then no, it's no longer 'wrong', but it probably won't validate. But it doesn't make much sense to do what you're doing. You should either just keep the anchor tag as a block level element with no inner div, or put the div on the outside.

Chris
  • 758
  • 7
  • 8
0

I think that most of the time when people ask this question, they have build a site with only divs, and now one of the div needs to be a link.

I seen someone use a transparent empty image, PNG, inside an anchor tag just to make a link inside a div, and the image was the same size as the div.

Pretty sad actually...but it works...

-2

It's wrong. Use a span.

Community
  • 1
  • 1
Jon Hadley
  • 5,196
  • 8
  • 41
  • 65
  • 4
    rofl thats the same thing as using a div. i think i have seen this done (with divs) on blip.tv but as others mention its wrong according to spec block=block if div or span or whatever its the same! – James Mitch Feb 01 '13 at 23:42
-12

Just as an FYI.

If your goal is to make your div clickable you can use jQuery / Java Script.

Define your div like so:

<div class="clickableDiv" style="cursor:pointer">
  This is my div. Try clicking it!
</div>

Your jQuery would then be implemented like so:

 <script type="text/javascript">

    $(document).ready(function () {

        $("div.clickableDiv").click(function () {
            alert("Peekaboo"); 
        });
    });
</script>

This would also work for multiple divs - as per Tom's comment in this thread

solveig
  • 81
  • 7
  • 19
    This is horrible, it can't be used with a keyboard, you can't see the link on-hover. It works almost-like-a-link, but isn't a real link. You can't middle click it either, or right click on it as a link either. – WhyNotHugo Aug 10 '12 at 14:45
  • 1
    It certainly has its uses. You could put an anchor inside the div and have the div-click redirect to the child anchor's location. By setting the cursor on the div to pointer you thus have the look and feel of an anchor, plus a valid fallback solution with only the anchor inside the div if javascript is not allowed or for accessability reasons. You get semantically and syntactically correct html, and you don't have to fiddle with questionable alterations of the display style. – Pedery Sep 16 '13 at 09:04
  • If you have a div that contains a link you could have a click handler catch the event, find the anchor (make sure there's only one) and then use that. Accessible via the normal anchor tag. This would allow having a bucket of figures with image and caption and "read more" link - for example. Thoughts? – Julix Nov 24 '17 at 03:07