Como fazer um elemento de bloco embutido preencher o restante da linha?

186

Isso é possível usando CSS e duas tags DIV de bloco embutido (ou o que seja) em vez de usar uma tabela?

A versão da tabela é esta (bordas adicionadas para que você possa vê-lo):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head></head>
<body>
<table style="width:100%;">
<tr>
<td style="border:1px solid black;width:100px;height:10px;"></td>
<td style="border:1px solid black;height:10px;"></td>
</tr>
</table>
</body>
</html>

Produz uma coluna esquerda com uma LARGURA FIXA (não uma largura percentual) e uma coluna da direita que se expande para preencher O ESPAÇO RESTANTE na linha. Parece bem simples, certo? Além disso, como nada é "flutuado", a altura do contêiner pai expande-se adequadamente para abranger a altura do conteúdo.

--BEGIN RANT
- Vi as implementações "clear fix" e "holy grail" para layouts de várias colunas com coluna lateral de largura fixa, e elas são péssimas e complicadas. Eles invertem a ordem dos elementos, usam larguras de porcentagem ou flutuam, margens negativas e o relacionamento entre os atributos "esquerdo", "direito" e "margem" é complexo. Além disso, os layouts são sensíveis a subpixels, de forma que a adição de um único pixel de bordas, preenchimento ou margens interrompa todo o layout e envia colunas inteiras para a próxima linha. Por exemplo, erros de arredondamento são um problema, mesmo se você tentar fazer algo simples, como colocar 4 elementos em uma linha, com a largura de cada um configurada para 25%.
--END RANT--

Eu tentei usar "inline-block" e "white-space: nowrap;", mas o problema é que simplesmente não consigo obter o segundo elemento para preencher o espaço restante na linha. Definir a largura para algo como "width: 100% - (LeftColumWidth) px" funcionará em alguns casos, mas executar um cálculo em uma propriedade width não é realmente suportado.

Triynko
fonte
1
Eu não acho que exista uma maneira sensata de fazer isso, exceto transformar isso em uma display: table-*construção que funcionará, mas também não é "mais semântica" (sendo um caso terrível de divsopa) e quebra a compatibilidade com o IE6. Eu, pessoalmente, iria ficar com o <table>, a menos que alguém consegue chegar a uma idéia simples gênio que funciona sem
Pekka
51
Sim. Eu continuo me deparando com todos esses argumentos "evitar tabelas" desde o início da era do CSS, e eles são redigidos para fazer você parecer um idiota preguiçoso incompetente se você ainda usa tabelas para layouts. Avanço rápido de uma década, e ainda é um sonho idealista. O fato é que a semântica do layout de fluxo SUGA para layouts fixos, mas flexíveis, como interfaces e formulários do usuário. A verdade é que as pessoas inteligentes usarão as tabelas onde for conveniente, porque esgotaram todas as soluções CSS possíveis e perceberam que são todas imperfeitas e significativamente mais complexas do que apenas usar uma tabela.
Triynko
4
Flutua? Mostre-me o código de trabalho, em que os elementos de fim de linha não se ajustam de maneira imprevisível e as bordas e margens não quebram o layout. Isso é o que há de errado com eles. Além disso, o contêiner pai de tamanho automático se expande adequadamente para abranger elementos flutuantes sem os hacks de "correção clara"? Eu acho que não.
Triynko
Se você tem pelo menos um elemento não flutuante no contêiner pai, então não é realmente um "hack" para limpar os flutuadores, agora é? Lembre-se de que o CSS tem suas raízes na impressão - consulte css-tricks.com/containers-dont-clear-floats para uma boa discussão sobre por que você não recebe a limpeza automática.
Chowlett
3
@Triynko: Foi o que fiz anteriormente: jsfiddle.net/thirtydot/qx32C - Acho que atinge a maioria dos seus pontos. Ouvirei sua crítica da demonstração que fiz e tentarei corrigi-la depois.
precisa saber é o seguinte

Respostas:

169

Veja: http://jsfiddle.net/qx32C/36/

.lineContainer {
    overflow: hidden; /* clear the float */
    border: 1px solid #000
}
.lineContainer div {
    height: 20px
} 
.left {
    width: 100px;
    float: left;
    border-right: 1px solid #000
}
.right {
    overflow: hidden;
    background: #ccc
}
<div class="lineContainer">
    <div class="left">left</div>
    <div class="right">right</div>
</div>


Por que eu substituir margin-left: 100pxcom overflow: hiddenon .right?

EDIT: Aqui estão dois espelhos para o link acima (morto):

trinta dias
fonte
60
Se você se chama desenvolvedor da Web, precisa clicar nesse link. Eu fiz, e me senti como Jasmine em um passeio mágico no tapete.
Chris Shouts
2
@ ChrisShouts, essa é provavelmente a melhor maneira de descrever isso. Esse método simplesmente não faz sentido, mas, novamente ... Uma solução maravilhosa para algo que você deve ser capaz de fazer explicitamente.
Mjvotaw
14
O estouro oculto não é uma solução. Suponha que você não queira ocultar o excesso do contêiner certo. Isso não faz com que o tamanho do contêiner certo preencha o espaço restante na linha. Este é um exemplo de pergunta de dois anos para a qual ainda não marquei uma resposta, porque ainda não há uma resposta satisfatória.
Triynko
3
Triynko: mesmo que você esteja usando 'overflow: hidden', nada ficará oculto (pelo menos se você tiver apenas texto). O texto / elementos dentro da div serão organizados de forma que caibam dentro da div (a menos que você tenha um elemento maior que a div, é claro).
CpnCrunch
1
@RMorrisey: Provavelmente só precisa de um pouco box-sizing: border-boxsobre o divs. Apenas um palpite, já que você não forneceu uma demonstração mostrando o comportamento que descreve. Dito isto, a display: tablesolução baseada geralmente é melhor . Essa é uma pergunta muito antiga, mas acho que estava tentando evitar algo relacionado às tabelas nesta questão devido ao comportamento do OP.
thirtydot
65

Uma solução moderna usando o flexbox:

.container {
    display: flex;
}
.container > div {
    border: 1px solid black;
    height: 10px;
}

.left {
   width: 100px;
}

.right {
    width: 100%;
    background-color:#ddd;
}
<div class="container">
  <div class="left"></div>
  <div class="right"></div>
</div>

http://jsfiddle.net/m5Xz2/100/

Panu Horsmalahti
fonte
4
exibir flex e largura de 100% .. tenho que lembrar
dreamerkumar
10
ao usar o flex, por que não usar em flex: 1vez de width: 100%?
Itai Bar-Haim
Para quem é novo no flexbox : flex: 1é uma abreviação de flex-grow: 1. É um atributo de combinação: flex: <grow> <shrink> <basis>.
21135 tanius
1
Apenas uma nota rápida que display: Flex não é suportado no IE <11, e muito buggy em 11.
Eric Shields
1
@EricShields isso não deve impedir ninguém de usar o Flexbox. Hoje em dia flexbugsvocê sabe.
Neurotransmitter
47

Compatível com os navegadores modernos comuns (IE 8+): http://jsfiddle.net/m5Xz2/3/

.lineContainer {
    display:table;
    border-collapse:collapse;
    width:100%;
}
.lineContainer div {
    display:table-cell;
    border:1px solid black;
    height:10px;
}
.left {
    width:100px;
}
 <div class="lineContainer">
    <div class="left">left</div>
    <div class="right">right</div>
</div>

Z gelado
fonte
9
O argumento contra o uso de tabelas não tem nada a ver com suas características de apresentação. Tem a ver com marcação incontrolável, confusão de estilo / documento e semântica inadequada. Nenhum desses argumentos se aplica a display:table.
Rich Remer
Isso não responde como inline-blockpreencher o restante da linha.
Neurotransmitter
1
@TranslucentCloud Concordo que minha resposta não responde exatamente ao título da pergunta, mas fornece uma maneira de preencher a largura disponível usando divs, conforme solicitado no corpo da pergunta.
gelado Z
1
Eu gosto muito desta solução. Você não é forçado a usar alguns estilos estranhos que surgem da lógica CSS oculta (como no caso de estouro oculto).
Chaoste 12/12/19
4

Você pode usar calc (100% - 100px) no elemento fluido, juntamente com display: bloco em linha para ambos os elementos.

Esteja ciente de que não deve haver espaço entre as tags; caso contrário, você terá que considerar esse espaço no seu cálculo também.

.left{
    display:inline-block;
    width:100px;
}
.right{
    display:inline-block;
    width:calc(100% - 100px);
}


<div class=“left”></div><div class=“right”></div>

Exemplo rápido: http://jsfiddle.net/dw689mt4/1/

SuperIRis
fonte
1

Eu usei flex-growpropriedade para atingir esse objetivo. Você precisará definir display: flexpara o contêiner pai, depois precisará definir flex-grow: 1o bloco que deseja preencher o espaço restante, ou exatamente flex: 1como o tanius mencionado nos comentários.

Vladislav Kovechenkov
fonte
0

Se você não puder usar overflow: hidden(porque não deseja overflow: hidden) ou se não gostar de hacks / soluções alternativas em CSS, poderá usar JavaScript. Observe que pode não funcionar tão bem porque é JavaScript.

var parent = document.getElementsByClassName("lineContainer")[0];
var left = document.getElementsByClassName("left")[0];
var right = document.getElementsByClassName("right")[0];
right.style.width = (parent.offsetWidth - left.offsetWidth) + "px";
window.onresize = function() {
  right.style.width = (parent.offsetWidth - left.offsetWidth) + "px";
}
.lineContainer {
  width: 100% border: 1px solid #000;
  font-size: 0px;
  /* You need to do this because inline block puts an invisible space between them and they won't fit on the same line */
}

.lineContainer div {
  height: 10px;
  display: inline-block;
}

.left {
  width: 100px;
  background: red
}

.right {
  background: blue
}
<div class="lineContainer">
  <div class="left"></div>
  <div class="right"></div>
</div>

http://jsfiddle.net/ys2eogxm/

Nick Manning
fonte