Você pode fazer esse layout HTML sem usar tabelas?

102

Ok, tive um problema simples de layout há uma ou duas semanas. Ou seja, as seções de uma página precisavam de um cabeçalho:

+---------------------------------------------------------+
| Title                                            Button |
+---------------------------------------------------------+

Coisas muito simples. A coisa é que o ódio à mesa parece ter dominado o mundo da Web, do qual me lembrei quando perguntei Por que usar tags de listas de definições (DL, DD, DT) para formulários HTML em vez de tabelas? Agora, o tópico geral de tabelas vs divs / CSS foi discutido anteriormente, por exemplo:

Portanto, não se trata de uma discussão geral sobre CSS versus tabelas para layout. Esta é simplesmente a solução para um problema. Tentei várias soluções para o acima usando CSS, incluindo:

  • Flutue para a direita para o botão ou div que contém o botão;
  • Posição relativa ao botão; e
  • Posição relativa + absoluta.

Nenhuma dessas soluções foi satisfatória por diferentes motivos. Por exemplo, o posicionamento relativo resultou em um problema de índice z em que meu menu suspenso apareceu sob o conteúdo.

Então acabei voltando para:

<style type="text/css">
.group-header { background-color: yellow; width: 100%; }
.group-header td { padding: 8px; }
.group-title { text-align: left; font-weight: bold; }
.group-buttons { text-align: right; }
</style>
<table class="group-header">
<tr>
  <td class="group-title">Title</td>
  <td class="group-buttons"><input type="button" name="Button"></td>
</tr>
</table>

E funciona perfeitamente. É simples, tão compatível com as versões anteriores quanto possível (provavelmente funcionará até mesmo no IE5) e simplesmente funciona. Sem problemas com posicionamento ou flutuadores.

Então, alguém pode fazer o equivalente sem tabelas?

Os requisitos são:

  • Compatível com versões anteriores: para FF2 e IE6;
  • Razoavelmente consistente: em diferentes navegadores;
  • Centralizado verticalmente: o botão e o título têm alturas diferentes; e
  • Flexível: permite um controle razoavelmente preciso sobre o posicionamento (preenchimento e / ou margem) e estilo.

Por outro lado, encontrei alguns artigos interessantes hoje:

EDIT: Deixe-me elaborar sobre a questão do float. Este tipo de trabalho:

<html>
  <head>
    <title>Layout</title>
    <style type="text/css">
      .group-header, .group-content { width: 500px; margin: 0 auto; }
      .group-header { border: 1px solid red; background: yellow; overflow: hidden; }
      .group-content { border: 1px solid black; background: #DDD; }
      .group-title { float: left; padding: 8px; }
      .group-buttons { float: right; padding: 8px; }
    </style>
  </head>
  <body>
    <div class="group-header">
      <div class="group-title">This is my title</div>
      <div class="group-buttons"><input type="button" value="Collapse"></div>
    </div>
    <div class="group-content">
      <p>And it works perfectly. It's simple, as backward compatibile as it gets (that'll work probably even on IE5) and it just works. No messing about with positioning or floats.</p>
      <p>So can anyone do the equivalent without tables that is backwards compatible to at least FF2 and IE6?</p>
      <p>On a side note, I came across a couple of interesting articles today:</p>
    </div>
  </body>
</html>

Obrigado ao Ant P pela overflow: hiddenparte (ainda não entendi o porquê). É aqui que entra o problema. Digamos que eu queira que o título e o botão sejam centralizados verticalmente. Isso é problemático porque os elementos têm alturas diferentes. Compare isso com:

<html>
  <head>
    <title>Layout</title>
    <style type="text/css">
      .group-header, .group-content { width: 500px; margin: 0 auto; }
      .group-header { border: 1px solid red; background: yellow; overflow: hidden; }
      .group-content { border: 1px solid black; background: #DDD; }
      .group-header td { vertical-align: middle; }
      .group-title { padding: 8px; }
      .group-buttons { text-align: right; }
    </style>
  </head>
  <body>
    <table class="group-header">
    <tr>
      <td class="group-title">This is my title</td>
      <td class="group-buttons"><input type="button" value="Collapse"></td>
    </tr>
    </table>
    <div class="group-content">
      <p>And it works perfectly. It's simple, as backward compatibile as it gets (that'll work probably even on IE5) and it just works. No messing about with positioning or floats.</p>
      <p>So can anyone do the equivalent without tables that is backwards compatible to at least FF2 and IE6?</p>
      <p>On a side note, I came across a couple of interesting articles today:</p>
    </div>
  </body>
</html>

que funciona perfeitamente.

cletus
fonte
11
Ok, isso faz sentido "Que cor devo usar para o vim?" é votado a favor, meu problema de layout CSS específico é votado negativamente.
cletus
você pode fazer o que quiser sem mesa em nenhum caso. Além disso, por que diabos @SamB resolveu essa questão de 2 anos? DOH +
dinâmico
3
@ yes123: bem, o realce de sintaxe estava errado ...
SamB

Respostas:

50

Não há nada de errado em usar as ferramentas que estão disponíveis para fazer o trabalho de forma rápida e correta.

Neste caso, uma mesa funcionou perfeitamente.

Eu pessoalmente teria usado uma mesa para isso.

Acho que tabelas aninhadas devem ser evitadas, as coisas podem ficar confusas.

Gregor Brandt
fonte
21
Exceto quando você está usando uma tabela para layout de apresentação, em vez de dados tabulares, apenas porque é mais fácil no início, e nesse caso você está seguindo por um caminho escuro e perigoso.
One Crayon
9
Até a Amazon usa tabelas em certos casos. E stackoverflow.com também. Sou totalmente a favor de soluções de CSS quando elas realmente funcionam bem.
Nosredna
11
Nem amazon, agora stackoverflow são os pináculos do web design.
Bobby Jack
31
Eles podem não ser, mas estão trabalhando em soluções que atendem a dezenas de milhares de usuários.
17 de 26 de
22
Este meme anti-mesa é simplesmente estúpido. O único gerenciador de layout bidimensional para laout baseada em restrições flexíveis é a tabela; e se é apenas um complicado (com uma infinidade de col / rowspans), ou aninhados faz pouca diferença. Mas a realidade e os fatos nem sempre são armas boas o suficiente contra o fanatismo, ao que parece.
StaxMan
28

Basta flutuar para a esquerda e para a direita e definir para limpar ambos e pronto. Não há necessidade de mesas.

Edit: Eu sei que recebi muitos votos positivos para isso, e acreditei que estava certo. Mas há casos em que você simplesmente precisa ter tabelas. Você pode tentar fazer tudo com CSS e funcionará em navegadores modernos, mas se você deseja suportar os mais antigos ... Para não me repetir, aqui o tópico de estouro de pilha relacionado e discurso retórico no meu blog .

Edit2: Como os navegadores mais antigos não são mais tão interessantes, estou usando o bootstrap do Twitter para novos projetos. É ótimo para a maioria das necessidades de layout e usa CSS.

Milan Babuškov
fonte
2
Não controla a centralização vertical, então -1.
SamB
1
Tive um problema semelhante em que havia um logotipo à esquerda e alguns menus de texto à direita. Os menus tiveram que ser alinhados na linha de base do logotipo. Usando float: certo para os menus não funcionou. Isso os enviava para o canto superior direito e eles não estavam mais alinhados verticalmente com a linha de base do logotipo.
Jean-François Beauchamp
1
Acho que você pode resolver a centralização vertical definindo a altura da linha do Título como igual à altura do Botão.
igors
1
@igors, +1, você está certo. Lembre-se de que esta pergunta é de 2009.;)
Milan Babuškov
17

Esta é uma pergunta capciosa: parece terrivelmente simples até você chegar

Digamos que eu queira que o título e o botão sejam centralizados verticalmente.

Quero deixar registrado que sim, a centralização vertical é difícil em CSS. Quando as pessoas postam, e parece não ter fim no SO, "você pode fazer X em CSS", a resposta é quase sempre "sim" e suas reclamações parecem injustificadas. Nesse caso, sim, essa coisa em particular é difícil.

Alguém deve apenas editar a questão inteira para "a centralização vertical é problemática em CSS?".

AmbroseChapel
fonte
11
Esse é o meu problema com o argumento dos "inimigos da tabela": CSS pode fazer tudo o que as tabelas podem fazer ... exceto em alguns casos bastante simples, comuns e razoáveis ​​(como centralização vertical). CSS parece apenas uma promessa eleitoral que deu errado.
cletus
4
Meu ponto é que a centralização vertical é a ÚNICA coisa que é realmente difícil.
AmbroseChapel
3
CSS não foi feito para substituir tabelas; serve apenas para permitir que você resolva a maioria dos problemas comuns de layout sem tabelas. Se uma mesa funcionar, use uma mesa, assim como usaria uma caneta para desenhar em vez de uma marreta.
Aaron Digulla
16

Float title left, float button right e (aqui está a parte que eu não conhecia até recentemente) - faça o contêiner de ambos {overflow:hidden}.

Isso deve evitar o problema do índice z, de qualquer maneira. Se não funcionar e você realmente precisar do suporte IE5, vá em frente e use a mesa.


fonte
+1 Uau, o que há com o estouro escondido? Isso faz a diferença. Não tenho ideia do porquê.
cletus
Para ser honesto, eu também não entendi e não consegui encontrar nenhuma menção a ele nas especificações. Alguém me disse que essa é a maneira "certa", porém, depois que respondi a outra pergunta, sugerindo que eles usassem um elemento esclarecido para fazê-lo. Parece uma boa ideia para mim.
Os elementos flutuantes ainda precisam ser limpos para que o conteúdo que os segue flua corretamente. estouro: oculto; aborda apenas a altura do contêiner.
Zack The Human
2
"overflow: hidden" é um hack para obter AMBOS a 'expansão' de altura e limpeza. Os seguintes elementos IRÃO limpar essa caixa (em navegadores que implementam essa parte da especificação corretamente, pelo menos).
Bobby Jack
1
-1 para não lidar com centralização vertical, mas +2 para overflow:hidden.
SamB
7

Em CSS puro, uma resposta útil um dia será apenas usar "display:table-cell". Infelizmente, isso não funciona nos navegadores de nível A atuais, portanto, para todos os efeitos, você também pode usar uma tabela se quiser obter o mesmo resultado de qualquer maneira. Pelo menos você terá certeza de que funciona bem no passado.

Honestamente, use uma mesa se for mais fácil. Não vai doer.

Se a semântica e a acessibilidade do elemento da tabela realmente importam para você, há um rascunho de trabalho para tornar sua tabela não semântica:

http://www.w3.org/TR/wai-aria/#presentation

Eu acho que isso requer um DTD especial além do XHTML 1.1, o que apenas agitaria todo o debate text/htmlvs application/xml, então não vamos lá.

Então, para o seu problema de CSS não resolvido ...

Para alinhar verticalmente dois elementos em seu centro: isso pode ser feito de algumas maneiras diferentes, com alguns hackeamentos CSS obtusos.

Se você puder se ajustar às seguintes restrições, há uma maneira relativamente simples:

  • A altura dos dois elementos é fixa.
  • A altura do contêiner é fixa.
  • Os elementos serão estreitos o suficiente para não se sobrepor (ou podem ser configurados para uma largura fixa).

Então você pode usar o posicionamento absoluto com margens negativas:

.group-header { height: 50px; position: relative; }
.group-title, .group-buttons { position: absolute; top: 50%; }
# Assuming the height of .group-title is a known 34px
.group-title { left: 0; margin-top: -17px; }
# Assuming the height of .group-buttons is a known 38px
.group-buttons { right: 0; margin-top: -19px; }

Mas isso é inútil na maioria das situações ... Se você já sabe a altura dos elementos, então você pode apenas usar flutuadores e adicionar margem suficiente para posicioná-los conforme necessário.

Aqui está outro método que usa a linha de base do texto para alinhar verticalmente as duas colunas como blocos embutidos. A desvantagem aqui é que você precisa definir larguras fixas para as colunas para preencher a largura a partir da borda esquerda. Como precisamos manter os elementos travados em uma linha de base do texto, não podemos apenas usar float: certo para a segunda coluna. (Em vez disso, temos que deixar a primeira coluna larga o suficiente para empurrá-la.)

<html>
  <head>
    <title>Layout</title>
    <style type="text/css">
      .group-header, .group-content { width: 500px; margin: 0 auto; }
      .group-header { border: 1px solid red; background: yellow; }
      .valign { display: inline-block; vertical-align: middle; }
      .group-content { border: 1px solid black; background: #DDD; }
      .group-title { padding: 8px; width: 384px; }
      .group-buttons { padding: 8px; width: 84px; text-align: right; }
    </style>
    <!--[if lt IE 8]>
    <style type="text/css">
      .valign { display: inline; margin-top: -2px; padding-top: 1px; }
    </style>
    <![endif]-->
  </head>
  <body>
    <div class="group-header">
      <div class="valign">
        <div class="group-title">This is my title.</div>
      </div><!-- avoid whitespace between these! --><div class="valign">
        <div class="group-buttons"><input type="button" value="Collapse"></div>
      </div>
    </div>
    <div class="group-content">
      <p>And it works perfectly, but mind the hacks.</p>
    </div>
  </body>
</html>

O HTML: adicionamos wrappers .valign ao redor de cada coluna. (Dê a eles um nome mais "semântico" se isso o deixar mais feliz.) Eles precisam ser mantidos sem espaços em branco ou então os espaços de texto os separarão. (Eu sei que é uma merda, mas isso é o que você ganha sendo "puro" com a marcação e separando-a da camada de apresentação ... Ha!)

O CSS: usamos vertical-align:middlepara alinhar os blocos à linha de base do texto do elemento group-header. As diferentes alturas de cada bloco ficarão centradas verticalmente e empurrarão para fora a altura de seu contêiner. As larguras dos elementos precisam ser calculadas para caber na largura. Aqui, eles são 400 e 100, sem o preenchimento horizontal.

As correções do IE: o Internet Explorer exibe apenas blocos embutidos para elementos embutidos nativamente (por exemplo, span, não div). Mas, se dermos o div hasLayout e depois exibi-lo embutido, ele se comportará como um bloco embutido. O ajuste da margem serve para corrigir uma lacuna de 1px no topo (tente adicionar cores de fundo ao título do .group para ver).

Andrew Vit
fonte
1
Hmm o display: as tags table-X parecem ter o propósito de fazer o layout usando tabelas, mas sem usar tags de tabela?
Marinheiro Danubiano
3

Eu recomendaria não usar uma tabela neste caso, porque não se trata de dados tabulares; é puramente de apresentação ter o botão localizado na extremidade direita. Isso é o que eu faria para duplicar a estrutura da sua tabela (mude para um H # diferente para se adequar a onde você está na hierarquia do seu site):

<style>
  .group-header { background: yellow; zoom: 1; padding: 8px; }
  .group-header:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
  /* set width appropriately to allow room for button */
  .group-header h3 { float: left; width: 300px; }
  /* set line-height or margins to align with h3 baseline or middle */
  .group-header input { float: right; }
</style>

<div class="group-header">
  <h3>This is my title</h3>
  <input type="button" value="Collapse"/>
</div>

Se você deseja um alinhamento vertical verdadeiro no meio (ou seja, se o texto envolve o botão ainda está alinhado no meio em relação a ambas as linhas do texto), então você precisa fazer uma tabela ou trabalhar algo com position: absolutee margens. Você pode adicionar position: relativeao seu menu suspenso (ou mais provavelmente ao seu pai) para colocá-lo no mesmo nível de ordenação dos botões, permitindo que você o coloque acima deles com z-index, se for o caso.

Observe que você não precisa width: 100%do div porque é um elemento em nível de bloco e zoom: 1faz com que o div se comporte como se tivesse um clearfix no IE (outros navegadores pegam o clearfix real). Você também não precisa de todas essas classes estranhas se estiver direcionando as coisas um pouco mais especificamente, embora possa precisar de um div de invólucro ou extensão no botão para facilitar o posicionamento.

One Crayon
fonte
Sua solução não funciona no IE6 por causa da pseudo classe: after.
Sebastian Hoitz
1
Ele funciona no IE 6, graças ao zoom: 1in .group-header, que dispara o hasLayout e faz com que o IE 6 se comporte da mesma forma como se tivesse o elemento: after ativo.
One Crayon
2

Faça um double float em um div e use o clearfix. http://www.webtoolkit.info/css-clearfix.html Você tem alguma restrição de preenchimento / margem?

<div class="clearfix">
   <div style="float:left">Title</div>
   <input type="button" value="Button" style="float:right" />
</div>
bendewey
fonte
Eu tenho um requisito de centralização vertical (e um pouco mais de preenchimento). Acho que esclareci isso depois que você postou.
cletus
2
<div class="group-header">
    <input type="button" name="Button" value="Button" style="float:right" />
    <span>Title</span>
</div>
Omer Bokhari
fonte
1

Eu escolhi usar o Flexbox porque tornou as coisas muito mais fáceis.

Você basicamente precisa ir até o pai dos filhos que deseja alinhar e adicionar display:box(prefixados, é claro). Para fazê-los sentar nas laterais, use justify-content . Espaçar entre é a coisa certa quando você tem elementos que precisam ser alinhados ao final, como neste caso (ver link) ...

Em seguida, o problema do alinhamento vertical. Como criei o pai dos dois elementos, você deseja alinhar um Flexbox. Agora é fácil de usaralign-items: center .

Em seguida, adicionei os estilos que você queria antes, removi o float do título e do botão no cabeçalho e adicionei um preenchimento:

.group-header, .group-content {
    width: 500px;
    margin: 0 auto;
}
.group-header{
    border: 1px solid red;
    background: yellow;
    overflow: hidden;
    display: -webkit-box;
    display: -moz-box;
    display: box;
    display: -webkit-flex;
    display: -moz-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-justify-content: space-between;
    -moz-justify-content: space-between;
    -ms-justify-content: space-between;
    -o-justify-content: space-between;
    justify-content: space-between;
    webkit-align-items: center;
    -moz-align-items: center;
    -ms-align-items: center;
    -o-align-items: center;
    align-items: center;
    padding: 8px 0;
}
.group-content{
    border: 1px solid black;
    background: #DDD;
}
.group-title {
    padding-left: 8px;
}
.group-buttons {
    padding-right: 8px
}

Veja a demonstração

user3522940
fonte
1

Eu concordo que realmente só se deve usar tabelas para dados tabulares, pela simples razão de que as tabelas não aparecem até que o carregamento seja concluído (não importa o quão rápido seja; é mais lento que o método CSS). No entanto, sinto que esta é a solução mais simples e elegante:

<html>
    <head>
        <title>stack header</title>
        <style type="text/css">
            #stackheader {
                background-color: #666;
                color: #FFF;
                width: 410px;
                height: 50px;
            }
            #title {
                color: #FFF;
                float: left;
                padding: 15px 0 0 15px;
            }
            #button {
                color: #FFF;
                float: right;
                padding: 15px 15px 0 0;
            }
        </style>
    </head>

    <body>
        <div id="stackheader">
        <div id="title">Title</div>
        <div id="button">Button</div>
        </div>
    </body>
</html>

A função do botão e qualquer detalhe extra podem ser estilizados a partir desta forma básica. Desculpas pelas tags ruins.

Galen777
fonte