Mettre un div à l'intérieur d'une ancre est-il toujours correct?

530

J'ai entendu dire que mettre un élément de bloc à l'intérieur d'un élément en ligne est un péché HTML:

<a href="http://www.mydomain.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>

Mais qu'en est-il si vous stylisez l'ancre extérieure comme display:blockdans la feuille de style? Est-ce toujours faux? La spécification HTML 4.01 sur les éléments de niveau bloc et en ligne semble le penser:

Les feuilles de style permettent de spécifier le rendu des éléments arbitraires, notamment si un élément est rendu en bloc ou en ligne. Dans certains cas, comme un style en ligne pour les éléments de liste, cela peut être approprié, mais de manière générale, les auteurs sont découragés de remplacer l'interprétation conventionnelle des éléments HTML de cette manière.

Quelqu'un a-t-il d'autres conseils à ce sujet?

À M
la source
@DisgruntledGoat - Merci pour le lien - j'aurais aimé voir ça plus tôt :-)
Tom
L'élément ancre et / ou lien est un contrôle d'automatisation du navigateur. Et par conséquent, il a un rendu et un comportement prédéfinis par le navigateur. Pour envelopper un véritable élément html simple: div à l'intérieur d'une plage est cependant un péché. La raison derrière le fait qu'une balise n'ajoute aucun comportement de niveau est une exigence pour baliser des parties de texte sans perturber le flux du document, et non parce qu'elles sont censées être des éléments en ligne. De ce point de vue, A, est une balise de ne rien faire. Son existence dépasse le problème et n'est pas un péché, mais peut contribuer à la laideur et / ou à l'ambiguïté du code.
Bekim Bacaj
Tous ceux qui vérifient ici à l'avenir, veuillez noter que même si les balises d'ancrage SONT capables de contenir des éléments de niveau bloc en dehors de HTML5, elles ne peuvent pas contenir d'élément de niveau bloc qui contient d'autres balises d'ancrage! Parce que fondamentalement, les balises d'ancrage ne peuvent pas contenir d'autres balises d'ancrage. Vous pouvez en savoir plus à ce sujet ici: stackoverflow.com/questions/13052598/…
aderchox

Réponses:

748

Selon la version de HTML à laquelle vous répondez:

  • HTML 5 indique que l'<a>élément "peut être enroulé autour de paragraphes entiers, de listes, de tableaux, etc., même de sections entières, tant qu'il n'y a pas de contenu interactif à l'intérieur (par exemple des boutons ou d'autres liens)".

  • HTML 4.01 spécifie que les<a>éléments ne peuvent contenir que des éléments en ligne . A<div>est un élément de bloc , il peut donc ne pas apparaître à l'intérieur d'un<a>.

    Bien sûr, vous êtes libre de styliser un élément en ligne de telle sorte qu'il semble être un bloc, ou bien de styliser un bloc afin qu'il soit rendu en ligne. L'utilisation des termes inlineet blocken HTML fait référence à la relation entre les éléments et la structure sémantique du document, alors que les mêmes termes en CSS sont davantage liés au style visuel des éléments. Si vous faites en sorte que les éléments en ligne s'affichent en bloc, c'est très bien.

    Cependant, vous devez vous assurer que la structure du document a toujours un sens lorsque CSS n'est pas présent, par exemple lorsqu'il est accessible via une technologie d'assistance telle qu'un lecteur d'écran - ou même lorsqu'il est examiné par le puissant Googlebot.

NickFitz
la source
4
Il existe une DTD pour 4.01 sur w3.org/TR/REC-html40/sgml/dtd.html . A peut contenir% inline%; % inline% est un tas de choses différentes (vous pouvez suivre les liens) mais DIV n'en fait pas partie. Ainsi, un A avec un DIV à l'intérieur n'est pas validable en XML. Je pense que DTD exprime assez bien les intentions du comité, alors je dirais: Non.
Carl Smotricz
2
@Ewan: le premier lien dans ma réponse est vers la section pertinente de HTML 4.01.
NickFitz
62
J'étais sur le point d'abandonner la possibilité de le faire dans un projet jusqu'à ce que je lise la dernière ligne sur HTML5, c'est bon à savoir, merci.
Elaine Marley
16
Le réseau de développeurs Mozilla ( developer.mozilla.org/en-US/docs/Web/HTML/Element/a ) reflète le fait que les éléments HTML5 <a> prennent désormais en charge les éléments de contenu de flux comme <div>, <ul> ou <table> .
AxeEffect
12
Sous HTML5, un un élément est considéré comme transparent , ce qui signifie qu'il peut contenir l' écoulement des éléments (lecture par défaut = bloc ) uniquement si le parent de l' un élément peut contenir l' écoulement des éléments. Sinon, seuls les éléments de phrasé (lire par défaut = en ligne ) sont autorisés. Ainsi, si le a est sous une forme ou un div , il peut contenir un div , mais à l'intérieur d'un p , il ne peut pas. Voir w3.org/TR/html-markup/terminology.html
Patanjali
81

Non, il ne sera pas validé, mais oui, cela fonctionnera généralement dans les navigateurs modernes. Cela étant dit, utilisez une travée à l'intérieur de votre ancre, et placez-la display: blockégalement, cela fonctionnera certainement partout et cela validera!

Eloff
la source
7
Si vous définissez display: block, n'est-ce pas, techniquement, un élément de bloc?
WhyNotHugo
20
@hugo Est-ce techniquement important?
Andy Chase
5
Eh bien, HTML 4.01 spécifie que les aéléments ne peuvent contenir que des éléments en ligne. Si vous faites d'un spanélément un élément de bloc, il ne devrait pas, techniquement, être à l'intérieur d'une ancre.
WhyNotHugo
22
@Hugo: Il semble que la restriction dans HTML4 soit sémantique, pas de présentation. Sémantiquement, a <div>est au niveau du bloc et a <span>est en ligne, même si le CSS d'accompagnement du document en décide autrement.
Roy Tinker
Ajouté style = "display: block;" dans la balise span et cela a fonctionné comme un charme. Je viens de jouer avec un rembourrage pour obtenir le résultat souhaité
Harif87
31

Le document du W3C n'utilise pas de concepts comme faux et péché , mais il utilise ceux comme fournir les moyens , peut être approprié et découragé .

En fait, dans le deuxième paragraphe de la section 4 , la spécification 4.01 détaille ses mots comme suit

Les mots clés "DOIT", "NE DOIT PAS", "OBLIGATOIRE", "DOIT", "NE DOIT PAS", "DEVRAIT", "NE DEVRAIENT PAS", "RECOMMANDÉ", "MAI" et "FACULTATIF" dans ce document sont à interpréter comme décrit dans [RFC2119]. Cependant, pour plus de lisibilité, ces mots n'apparaissent pas dans toutes les lettres majuscules de cette spécification.

Dans cet esprit, je pense que la déclaration définitive se trouve dans 7.5.3 Éléments de niveau bloc et en ligne , où elle dit

Généralement, les éléments en ligne peuvent contenir uniquement des données et d'autres éléments en ligne.

La condition "généralement" semble introduire suffisamment d'ambiguïté pour dire que HTML 4.01 permet aux éléments en ligne de contenir des éléments de bloc.

Certes, CSS2 a une valeur de propriété d'affichage, inline-block , qui semble être adaptée à l'objectif que vous décrivez. Je ne sais pas si cela a été largement soutenu, mais il semble que quelqu'un ait anticipé le besoin de ce type de comportement.

La DTD semble être moins indulgente ici, mais le texte de la DTD s'en remet à la spécification:

La spécification HTML 4.01 inclut des contraintes syntaxiques supplémentaires qui ne peuvent pas être exprimées dans les DTD.

Dans un autre commentaire, vous suggérez de rendre un bloc actif en l'enveloppant dans une ancre. Je ne crois pas que HTML l'interdit, et CSS le permet clairement. Donc, pour répondre à la question du titre de savoir si elle est jamais correcte, je dis oui. Selon les normes, c'est parfois correct.

Ewan Todd
la source
2
Vous m'avez eu jusqu'à ce que vous parliez de doctype.
Robert Harvey
Pas doctype, doctype.com
Ewan Todd
Vous avez probablement raison - j'aurais dû utiliser doctype.com. Opps - je vais essayer de me souvenir pour la prochaine fois. PHP -> SO, HTML -> doctype.com
Tom
2
Mon avis est qu'il n'y a pas d'option "voter pour fermer comme il appartient sur doctype.com" (et il ne devrait pas y en avoir).
Robert Harvey,
7
Je suis d'accord avec Rob - Stack Overflow est pour la programmation. HTML / CSS est certainement une programmation à mon avis.
DisgruntledGoat
13

Avec la spécification HTML5 ... Il est maintenant possible de mettre un élément de niveau bloc à l'intérieur d'un élément en ligne. Alors maintenant, il est parfaitement approprié de mettre un «div» ou «h1» à l'intérieur d'un élément «a».

Abir
la source
1
Uniquement à l'intérieur des éléments de flux (par défaut = bloc ) ou des éléments transparents (comme a ) avec des parents qui autorisent les éléments de flux . Par exemple, p n'autorise pas les éléments de flux (comme div ), mais uniquement les éléments de phrasé (par défaut = en ligne ), donc un a à l' intérieur d'un p ne peut pas contenir de div . Cependant, un a à l' intérieur d'un div peut contenir p s, div s ou tout autre élément de flux .
Patanjali
4

Vous ne pouvez pas mettre à l' <div>intérieur <a>- ce n'est pas du (X) HTML valide.

Même si vous créez un span avec display: block, vous ne pouvez toujours pas y mettre d'éléments de niveau bloc: le (X) HTML doit toujours obéir à la (X) HTML DTD (quelle que soit celle que vous utilisez), peu importe la façon dont le CSS modifie les choses.

Le navigateur l'affichera probablement comme vous le souhaitez, mais cela ne le rend pas correct.

Greg
la source
4

Il existe une DTD pour HTML 4 sur http://www.w3.org/TR/REC-html40/sgml/dtd.html . Cette DTD est la forme traitable par machine de la spécification, avec la limitation qu'une DTD régit XML et HTML 4, en particulier la saveur "transitoire", permet beaucoup de choses qui ne sont pas du XML "légal". Pourtant, je considère qu'il est proche de codifier l'intention des spécificateurs.

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

J'interpréterais les balises répertoriées dans cette hiérarchie comme étant le total des balises autorisées.

Bien que la spécification puisse dire «éléments en ligne», je suis presque sûr que ce n'est pas prévu que vous pouvez contourner l'intention en déclarant que le type d'affichage d'un élément de bloc est en ligne. Les balises en ligne ont une sémantique différente, peu importe comment vous pouvez en abuser.

D'un autre côté, je trouve fascinant que l'inclusion de specialsemble permettre l'imbrication d' Aéléments. Il y a probablement une formulation forte dans la spécification qui interdit cela même si elle est syntaxiquement correcte, mais je ne poursuivrai pas cela car ce n'est pas le sujet de la question.

Carl Smotricz
la source
Savez-vous ce que cela - - signifie. J'ai essayé de trouver une explication mais je n'ai pas pu en trouver une.
Ewan Todd,
4

Les éléments de niveau bloc comme <div>peuvent être enveloppés par des <a>balises en HTML5. Bien que a <div>soit considéré comme un conteneur / emballage pour le contenu de flux et que <a>les s soient considérés comme du contenu de flux selon MDN . Sémantiquement, il peut être préférable de créer des éléments en ligne qui agissent comme des éléments de niveau bloc.

Beepye
la source
1
Comme un des éléments sont transparents , que si l'élément parent de l' un permet l' écoulement (par défaut en tant que bloc ) éléments.
Patanjali
2

Si vous voulez éviter le problème sémantique de placer des divs à l'intérieur des balises d'ancrage, placez simplement la balise d'ancrage au même niveau que les divs, enveloppez-les toutes avec un conteneur avec position: relative, définissez la position de votre balise d'ancrage: absolue et développez-la pour remplissez le récipient. De plus, si ce n'est pas à la fin du flux de contenu, assurez-vous d'y insérer un z-index pour le placer au-dessus du contenu.

Comme suggéré, j'ai ajouté un code de balisage:

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

Et le css:

.div__container {
  position: relative; 
}
.div__container a {
  position: absolute;
  top: 0;
  bottom: 0;      
  left: 0;
  right: 0;
  z-index: 999;
}
Eugen
la source
1
Bien que votre réponse soit correcte, il serait utile de l'illustrer avec du balisage.
datashaman
1

Si vous allez faire l'effort de faire un <a>bloc, pourquoi ne pas le mettre <a>à l'intérieur, étant un élément de bloc, cela vous donnera le même effet.

Dave
la source
36
Parce que je pourrais vouloir que l'ancre entoure plusieurs divs.
Tom
1

Si vous le changez en élément de style bloc, alors non, ce n'est plus «faux», mais il ne sera probablement pas validé. Mais cela n'a pas beaucoup de sens de faire ce que vous faites. Vous devez soit conserver la balise d'ancrage en tant qu'élément de niveau bloc sans div interne, soit placer la div à l'extérieur.

Chris
la source
1

C'est faux. Utilisez une envergure .

Jon Hadley
la source
4
rofl c'est la même chose que d'utiliser un div. je pense avoir vu cela (avec divs) sur blip.tv mais comme d'autres mentionnent son mauvais selon spec block = block si div ou span ou quoi que ce soit pareil!
James Mitch
0

Je pense que la plupart du temps, lorsque les gens posent cette question, ils ont construit un site avec uniquement des divs, et maintenant l'un des div doit être un lien.

J'ai vu quelqu'un utiliser une image vide transparente, PNG, à l'intérieur d'une balise d'ancrage juste pour créer un lien à l'intérieur d'un div, et l'image avait la même taille que le div.

Assez triste en fait ... mais ça marche ...

user1081070
la source
0

vous pouvez y parvenir en ajoutant le pseudo-élément ":: before"

Astuce CSS pure;)

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
la source
-9

Tout comme un FYI.

Si votre objectif est de rendre votre div cliquable, vous pouvez utiliser jQuery / Java Script.

Définissez votre div comme ceci:

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

Votre jQuery serait alors implémenté comme suit:

 <script type="text/javascript">

    $(document).ready(function () {

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

Cela fonctionnerait également pour plusieurs divs - selon le commentaire de Tom dans ce fil

résoudre
la source
17
C'est horrible, il ne peut pas être utilisé avec un clavier, vous ne pouvez pas voir le lien en survol. Cela fonctionne presque comme un lien, mais ce n'est pas un vrai lien. Vous ne pouvez pas non plus cliquer dessus avec le bouton du milieu, ou faire un clic droit dessus comme lien.
WhyNotHugo
1
Il a certainement ses utilités. Vous pouvez placer une ancre à l'intérieur du div et faire rediriger le div-click vers l'emplacement de l'ancre enfant. En plaçant le curseur sur le div sur le pointeur, vous avez ainsi l'apparence d'une ancre, plus une solution de secours valide avec uniquement l'ancre à l'intérieur du div si javascript n'est pas autorisé ou pour des raisons d'accessibilité. Vous obtenez un html sémantiquement et syntaxiquement correct, et vous n'avez pas à jouer avec des modifications douteuses du style d'affichage.
Pedery
Si vous avez un div qui contient un lien, vous pouvez demander à un gestionnaire de clics d'attraper l'événement, de trouver l'ancre (assurez-vous qu'il n'y en a qu'un), puis de l'utiliser. Accessible via la balise d'ancrage normale. Cela permettrait d'avoir un ensemble de chiffres avec image et légende et un lien "en savoir plus" - par exemple. Pensées?
Julix