Colocar uma div dentro de uma âncora é sempre correto?

530

Ouvi dizer que colocar um elemento de bloco dentro de um elemento embutido é um pecado em 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>

Mas e se você estilizar a âncora externa como display:blockna folha de estilo? Ainda está errado? A especificação do HTML 4.01 nos elementos em nível de bloco e inline parece pensar o seguinte:

As folhas de estilo fornecem os meios para especificar a renderização de elementos arbitrários, incluindo se um elemento é renderizado como bloco ou embutido. Em alguns casos, como um estilo embutido para elementos da lista, isso pode ser apropriado, mas de um modo geral, os autores são desencorajados a substituir a interpretação convencional dos elementos HTML dessa maneira.

Alguém tem mais alguma dica sobre esse problema?

Tom
fonte
3
Consulte também: stackoverflow.com/questions/1091739/html-div-in-link-problem .
DisgruntledGoat
@DisgruntledGoat - Obrigado pelo link - desejo que eu tinha visto que, mais cedo :-)
Tom
O elemento âncora e \ ou link é um controle de automação do navegador. E, portanto, possui uma renderização e comportamento predefinidos pelo navegador. Para envolver um elemento html simples e genuíno: div dentro de um intervalo, no entanto, é um pecado. A razão por trás do fato de que uma tag não adiciona nenhum comportamento de nível é um requisito para marcar partes do texto sem perturbar o fluxo do documento, não porque elas devem ser elementos embutidos. A partir desse ponto de vista, A, é uma etiqueta de não fazer nada. Sua existência está além da questão e não é pecado, mas pode contribuir para codificar a feiúra e a ambiguidade.
Bekim Bacaj
Todos os outros que verificarem aqui no futuro, observe que, embora as tags âncora PODEM conter elementos no nível do bloco, não estejam em HTML5, elas não podem conter um elemento no nível do bloco que contenha outras tags âncora! Porque, basicamente, os tags âncora não podem ter outros tags âncora dentro deles. Você pode ler mais sobre isso aqui: stackoverflow.com/questions/13052598/…
aderchox

Respostas:

748

Dependendo da versão do HTML que você está atendendo:

  • O HTML 5 afirma que o<a>elemento "pode ​​ser agrupado em parágrafos, listas, tabelas e assim por diante, até seções inteiras, desde que não exista conteúdo interativo (por exemplo, botões ou outros links)".

  • O HTML 4.01 especifica que os<a>elementos podem conter apenas elementos embutidos . A<div>é um elemento de bloco , portanto, pode não aparecer dentro de um<a>.

    É claro que você tem a liberdade de estilizar um elemento embutido, de modo que ele pareça ser um bloco, ou mesmo estilizar um bloco para que ele seja renderizado embutido. O uso dos termos inlinee blockno HTML refere-se ao relacionamento dos elementos com a estrutura semântica do documento, enquanto os mesmos termos no CSS estão mais relacionados ao estilo visual dos elementos. Se você exibir elementos inline de uma maneira em blocos, tudo bem.

    No entanto, você deve garantir que a estrutura do documento ainda faça sentido quando o CSS não estiver presente, por exemplo, quando acessado por meio de uma tecnologia de assistência, como um leitor de tela - ou mesmo quando examinado pelo poderoso Googlebot.

NickFitz
fonte
4
Existe um DTD para 4.01 em w3.org/TR/REC-html40/sgml/dtd.html . A pode conter% inline%; % inline% é um monte de coisas diferentes (você pode seguir os links), mas o DIV não está entre eles. Portanto, um A com um DIV interno não é validável por XML. Eu acho que DTD expressa as intenções da comissão de muito bem, então eu diria: Não.
Carl Smotricz
2
@ Ewan: o primeiro link na minha resposta é para a seção relevante do HTML 4.01.
31410 NickFitz
62
Eu estava prestes a abandonar a possibilidade de fazer isso em um projeto até ler a última linha sobre HTML5, é bom saber disso, obrigado.
Elaine Marley
16
A Mozilla Developer Network ( developer.mozilla.org/en-US/docs/Web/HTML/Element/a ) reflete o fato de os elementos HTML5 <a> agora suportarem elementos de conteúdo de fluxo como <div>, <ul> ou <table> .
AxeEffect
12
Sob HTML5, um um elemento é classificado como transparente , o que significa que ele pode conter de fluxo de elementos (leitura padrão = bloco ) somente se o pai do um elemento pode conter fluir elementos. Caso contrário, apenas os elementos de expressão (leitura padrão = inline ) são permitidos. Assim, se o a está em uma forma ou div , pode conter um div , mas dentro de um p , não pode. Veja w3.org/TR/html-markup/terminology.html
Patanjali
81

Não, não validará, mas sim, geralmente funcionará em navegadores modernos. Dito isto, use um espaço dentro da sua âncora e defina display: block-o também, que definitivamente funcionará em qualquer lugar e será validado!

Eloff
fonte
7
Se você definir display: block, tecnicamente, ele não se torna um elemento de bloco?
WhyNotHugo
20
@hugo Isso importa tecnicamente?
Andy Chase
5
Bem, o HTML 4.01 especifica que os aelementos podem conter apenas elementos embutidos. Se você transformar um spanelemento em um elemento de bloco, tecnicamente não deverá estar dentro de uma âncora.
WhyNotHugo
22
@ Hugo: Parece que a restrição no HTML4 é semântica, não de apresentação. Semanticamente, a <div>é no nível do bloco e a <span>é in-line, mesmo que o CSS que acompanha o documento determine o contrário.
Roy Tinker
Estilo adicionado = "display: block;" na tag span e funcionou como um encanto. Só jogou com estofamento para obter o meu resultado desejado
Harif87
31

O documento do W3C não usa conceitos como errado e pecado , mas usa aqueles que fornecem os meios , podem ser apropriados e desencorajados .

Na verdade, no segundo parágrafo da seção 4 , a especificação 4.01 especifica suas palavras da seguinte maneira

As palavras-chave "DEVEM", "NÃO DEVEM", "NECESSÁRIO", "DEVEM", "NÃO DEVEM", "DEVEM", "NÃO DEVEM", "RECOMENDADO", "PODE" e "OPCIONAL" neste documento são para ser interpretado como descrito em [RFC2119]. No entanto, para facilitar a leitura, essas palavras não aparecem em todas as letras maiúsculas nesta especificação.

Com isso em mente, acredito que a declaração definitiva está no 7.5.3 Elementos em nível de bloco e em linha , onde diz

Geralmente, os elementos embutidos podem conter apenas dados e outros elementos embutidos.

A condição "geralmente" parece apresentar ambiguidade suficiente para dizer que o HTML 4.01 permite que os elementos embutidos contenham elementos de bloco.

Certamente, o CSS2 possui um valor de propriedade de exibição, bloco em linha , que parece ser adequado ao objetivo que você descreve. Não tenho certeza se isso foi amplamente suportado, mas parece que alguém antecipou a necessidade desse tipo de comportamento.

O DTD parece menos tolerante aqui, mas o texto do DTD é diferente das especificações:

A especificação HTML 4.01 inclui restrições sintáticas adicionais que não podem ser expressas nas DTDs.

Em outro comentário, você sugere que deseja ativar um bloco envolvendo-o em uma âncora. Não acredito que o HTML proíba isso, e o CSS claramente permita. Então, para responder à pergunta do título sobre se alguma vez está correta, eu digo que sim. Pelos padrões, às vezes é correto.

Ewan Todd
fonte
2
Você me teve até mencionar o doctype.
314 Robert Harvey
Não doctype, doctype.com
Ewan Todd
Você provavelmente está certo - eu deveria ter usado o doctype.com. Opps - vou tentar me lembrar da próxima vez. PHP -> SO, HTML -> doctype.com
Tom
2
Minha opinião é que não há uma opção "votar para fechar como pertence no doctype.com" (nem deve haver).
Robert Harvey
7
Eu concordo com Rob - Stack Overflow é para programação. HTML / CSS certamente está programando na minha opinião.
DisgruntledGoat
13

Com a especificação HTML5 ... Agora é possível colocar um elemento no nível do bloco dentro de um elemento embutido. Portanto, agora é perfeitamente apropriado colocar um 'div' ou 'h1' dentro de um elemento 'a'.

Abir
fonte
1
Somente elementos de fluxo interno (padrão = bloco ) ou elementos transparentes (como a ) nos pais que permitem elementos de fluxo . Por exemplo, p não permite elementos de fluxo (como div ), mas apenas elementos de expressão (padrão = inline ); portanto, um a dentro de um p não pode conter uma div . No entanto, um a dentro de uma div pode conter p s, div s ou qualquer outro elemento de fluxo .
Patanjali
4

Você não pode colocar <div>dentro <a>- não é HTML (X) válido.

Mesmo que você estilize um span com display: block, você ainda não pode colocar elementos no nível do bloco: o HTML (X) ainda precisa obedecer ao DTD (X) HTML (o que você usar), não importa como o CSS altera as coisas.

O navegador provavelmente o exibirá como você deseja, mas isso não o torna correto.

Greg
fonte
4

Há um DTD para HTML 4 em http://www.w3.org/TR/REC-html40/sgml/dtd.html . Essa DTD é a forma processável por máquina da especificação, com a limitação de que uma DTD governa XML e HTML 4, especialmente o sabor "transitório", permite muitas coisas que não são XML "legais". Ainda assim, considero que chega perto de codificar a intenção dos especificadores.

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

Eu interpretaria as tags listadas nesta hierarquia como o total de tags permitidas.

Embora a especificação possa dizer "elementos inline", tenho certeza de que não é possível que você possa contornar a intenção declarando o tipo de exibição de um elemento de bloco como inline. As tags embutidas têm semânticas diferentes, não importa como você as abuse.

Por outro lado, acho intrigante que a inclusão de specialparece permitir Aelementos de aninhamento . Provavelmente, existe alguma redação forte na especificação que não permite isso, mesmo que seja sintaticamente correta em XML, mas não vou aprofundar isso, pois esse não é o tópico da pergunta.

Carl Smotricz
fonte
Você sabe o que - - significa. Tentei encontrar uma explicação, mas não consegui encontrar.
Ewan Todd
4

Elementos no nível do bloco, como <div>podem ser agrupados por <a>tags em HTML5. Embora um <div>é considerado como um recipiente / invólucro para o conteúdo de fluxo e <a>'s são considerados conteúdo de fluxo de acordo com a MDN . Semanticamente, pode ser melhor criar elementos embutidos que atuam como elementos no nível do bloco.

Beepye
fonte
1
Como um elementos são transparentes , apenas se o elemento pai do a uma permite o fluxo (como padrão de bloco ) elementos.
Patanjali
2

Se você quiser evitar o problema semântico de colocar divs dentro de tags de âncora, basta colocar a tag de âncora no mesmo nível que as divs, envolvê-las todas com um contêiner com position: relative, fazer sua posição de tag de âncora: absoluta e expandir para encher o recipiente. Além disso, se não estiver no final do fluxo de conteúdo, lance um índice z para colocá-lo acima do conteúdo.

Como sugerido, eu adicionei um código de marcação:

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

E o css:

.div__container {
  position: relative; 
}
.div__container a {
  position: absolute;
  top: 0;
  bottom: 0;      
  left: 0;
  right: 0;
  z-index: 999;
}
Eugen
fonte
1
Embora sua resposta possa estar correta, ajudaria se você a ilustrasse com a marcação.
Datashaman 17/10/19
1

Se você for fazer o esforço de criar um <a>bloco, por que não colocar <a>dentro da div, sendo um elemento do bloco, ele dará o mesmo efeito.

Dave
fonte
36
Porque eu posso querer que a âncora inclua várias divs.
Tom
1

Se você alterá-lo para um elemento de estilo de bloco, então não, não está mais 'errado', mas provavelmente não será validado. Mas não faz muito sentido fazer o que você está fazendo. Você deve manter a tag de âncora como um elemento de nível de bloco sem div interna ou colocar a div externa.

Chris
fonte
1

Está errado. Use um espaço .

Jon Hadley
fonte
4
rofl é a mesma coisa que usar uma div. Eu acho que já vi isso feito (com divs) no blip.tv, mas como outros mencionam o erro de acordo com spec block = block se div ou span ou o que for igual!
James Mitch
0

Acho que na maioria das vezes, quando as pessoas fazem essa pergunta, elas constroem um site com apenas divs e agora uma das div precisa ser um link.

Eu vi alguém usar uma imagem vazia transparente, PNG, dentro de uma tag anchor apenas para criar um link dentro de uma div, e a imagem tinha o mesmo tamanho da div.

Muito triste, na verdade ... mas funciona ...

user1081070
fonte
0

você pode conseguir isso adicionando o pseudoelemento ":: before"

Truque CSS puro;)

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
fonte
-9

Assim como um FYI.

Se seu objetivo é tornar seu div clicável, você pode usar o jQuery / Java Script.

Defina sua div assim:

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

Seu jQuery seria então implementado da seguinte maneira:

 <script type="text/javascript">

    $(document).ready(function () {

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

Isso também funcionaria para várias divs - conforme o comentário de Tom neste tópico

resolveig
fonte
17
Isso é horrível, não pode ser usado com um teclado, você não pode ver o link ao passar o mouse. Funciona quase como um link, mas não é um link real. Você também não pode clicar no meio ou clicar com o botão direito do mouse como um link.
WhyNotHugo
1
Certamente tem seus usos. Você pode colocar uma âncora dentro da div e fazer com que o clique div seja redirecionado para o local da âncora filha. Ao definir o cursor na div como ponteiro, você tem a aparência de uma âncora, além de uma solução de fallback válida apenas com a âncora dentro da div, se o javascript não for permitido ou por razões de acessibilidade. Você obtém o html semântico e sintaticamente correto e não precisa mexer nas alterações questionáveis ​​do estilo de exibição.
Pedery
Se você tem uma div que contém um link, um manipulador de cliques captura o evento, encontre a âncora (verifique se há apenas uma) e use-a. Acessível através da etiqueta de ancoragem normal. Isso permitiria ter um balde de figuras com imagem e legenda e o link "leia mais" - por exemplo. Pensamentos?
Julix