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.


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):


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/


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>


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/


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.


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/


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.