Is putting a div inside an anchor ever correct?

Viewed 355923

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?

16 Answers

Update in Jul, 2022: latest HTML5 version

  • Nothing is wrong with placing a div inside a tag. In fact, you can place just about anything inside a tag as long as they are categorized as transparent, except that no descendant may be interactive content (eg: buttons or inputs) or an a element, and no descendant may have a specified tabindex attribute. Please refer to their documentation: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#properties.
  • If you inspect Angular Material official website, you can tell that they are indeed using div inside a element.

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>

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;
}

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.

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>

Related