Comment faire en sorte qu'un élément de bloc en ligne remplisse le reste de la ligne?

186

Une telle chose est-elle possible en utilisant CSS et deux balises DIV inline-block (ou autre) au lieu d'utiliser une table?

La version du tableau est la suivante (bordures ajoutées pour que vous puissiez la voir):

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

Il produit une colonne de gauche avec une LARGEUR FIXE (pas un pourcentage de largeur) et une colonne de droite qui se développe pour remplir L'ESPACE RESTANT sur la ligne. Cela semble assez simple, non? De plus, puisque rien n'est "flottant", la hauteur du conteneur parent se développe correctement pour englober la hauteur du contenu.

--BEGIN RANT--
J'ai vu les implémentations "clear fix" et "Holy Grail" pour les mises en page multi-colonnes avec colonne latérale à largeur fixe, et elles sont nulles et compliquées. Ils inversent l'ordre des éléments, utilisent des largeurs en pourcentage ou utilisent des flottants, des marges négatives et la relation entre les attributs «gauche», «droite» et «marge» est complexe. En outre, les mises en page sont sensibles aux sous-pixels, de sorte que l'ajout d'un seul pixel de bordures, de remplissage ou de marges cassera l'ensemble de la mise en page et enverra des colonnes entières à la ligne suivante. Par exemple, les erreurs d'arrondi sont un problème même si vous essayez de faire quelque chose de simple, comme mettre 4 éléments sur une ligne, avec chacun une largeur de 25%.
--END RANT--

J'ai essayé d'utiliser "inline-block" et "white-space: nowrap;", mais le problème est que je n'arrive pas à obtenir le 2ème élément pour remplir l' espace restant sur la ligne. Définir la largeur sur quelque chose comme "width: 100% - (LeftColumWidth) px" fonctionnera dans certains cas, mais effectuer un calcul dans une propriété width n'est pas vraiment pris en charge.

Triynko
la source
1
Je ne pense pas qu'il y ait une manière sensée de faire cela, sauf de transformer cela en une display: table-*construction qui fonctionnera, mais qui n'est pas vraiment "plus sémantique" non plus (étant un cas terrible de divsoupe) et qui rompt la compatibilité avec IE6. Personnellement, je m'en tiendrai au <table>, à moins que quelqu'un n'arrive à trouver une idée simple et géniale qui fonctionne sans
Pekka
51
Ouais. Je continue à rencontrer tous ces arguments "éviter les tables" depuis l'aube de l'ère CSS, et ils sont formulés pour vous faire passer pour un crétin paresseux incompétent si vous utilisez toujours des tableaux pour les mises en page. Avance rapide d'une décennie, et c'est toujours une chimère idéaliste. Le fait est que la sémantique de mise en page de flux SUCK pour les mises en page fixes mais flexibles telles que les interfaces utilisateur et les formulaires. La vérité est que les gens intelligents utiliseront les tableaux là où cela leur convient, car ils ont épuisé toutes les solutions CSS possibles et se sont rendu compte qu'elles sont toutes imparfaites et beaucoup plus complexes que la simple utilisation d'une table.
Triynko le
4
Des flotteurs? Montrez-moi du code de travail, où les éléments de fin de ligne ne s'encapsulent pas de manière imprévisible et les bordures et les marges ne cassent pas la mise en page. C'est ce qui ne va pas avec eux. En outre, le conteneur parent automatiquement dimensionné se développe-t-il correctement pour englober des éléments flottants sans les hacks "clear fix"? Je ne pense pas.
Triynko le
Si vous avez au moins un élément non flottant dans votre conteneur parent, alors ce n'est pas vraiment un "hack" pour effacer les flottants, n'est-ce pas? N'oubliez pas que CSS a ses racines dans l'impression - voir css-tricks.com/containers-dont-clear-floats pour une bonne discussion sur les raisons pour lesquelles vous n'obtenez pas la compensation automatique.
Chowlett le
3
@Triynko: C'est ce que j'ai fait plus tôt: jsfiddle.net/thirtydot/qx32C - Je pense que cela touche la plupart de vos points. J'entendrai votre critique de cette démo que j'ai faite et j'essaierai de la réparer par la suite.
thirtydot

Réponses:

169

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


Pourquoi ai-je remplacé margin-left: 100pxpar overflow: hiddenon .right?

EDIT: Voici deux miroirs pour le lien ci-dessus (mort):

trentenaire
la source
60
Si vous vous appelez développeur Web, vous devez cliquer sur ce lien. Je l'ai fait, et je me sentais comme Jasmine lors d'un tour de tapis magique.
Chris Shouts
2
@ChrisShouts, c'est probablement la meilleure façon de décrire cela. Cette méthode n'a tout simplement aucun sens, mais là encore ... Une merveilleuse solution de contournement pour quelque chose que vous devriez pouvoir faire explicitement.
mjvotaw
14
Le débordement caché n'est pas une solution. Supposons que vous ne vouliez pas que le débordement du bon conteneur soit masqué. Cela ne fait pas que la taille du bon conteneur remplit l'espace restant sur la ligne. Voici un exemple de question datant de deux ans pour laquelle je n'ai toujours pas noté de réponse, car il n'y a toujours pas de réponse satisfaisante.
Triynko
3
Triynko: même si vous utilisez 'overflow: hidden', rien ne sera généralement caché (du moins si vous avez juste du texte). Le texte / les éléments à l'intérieur du div seront disposés de sorte qu'ils tiennent à l'intérieur du div (à moins que vous n'ayez un élément plus grand que le div, bien sûr).
CpnCrunch
1
@RMorrisey: Il en faut probablement juste box-sizing: border-boxsur le divs. Juste une supposition, puisque vous n'avez pas fourni de démonstration montrant le comportement que vous décrivez. Cela étant dit, la display: tablesolution basée sur la base est généralement meilleure . C'est une question très ancienne, mais je pense que j'essayais d'éviter tout ce qui a à voir avec les tableaux dans cette question en raison du comportement de OP.
thirtydot
65

Une solution moderne utilisant 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
la source
4
affichage flex et largeur 100% ..
je
10
lorsque vous utilisez flex, pourquoi ne pas utiliser à la flex: 1place de width: 100%?
Itai Bar-Haim
Pour ceux qui découvrent flexbox : flex: 1est un raccourci pour flex-grow: 1. Il est un attribut de combinaison: flex: <grow> <shrink> <basis>.
tanius
1
Juste une petite note que display: flex n'est pas pris en charge dans IE <11, et très bogué dans 11.
Eric Shields
1
@EricShields cela ne devrait empêcher personne d'utiliser Flexbox. Aujourd'hui, nous flexbugsvous savons.
Neurotransmetteur
47

Compatible avec les navigateurs modernes courants (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>

Frosty Z
la source
9
L'argument contre l'utilisation des tables n'a rien à voir avec ses caractéristiques de présentation. Cela a à voir avec un balisage ingérable, une confusion de style / document et une sémantique incorrecte. Aucun de ces arguments ne s'applique à display:table.
Rich Remer
Cela ne répond pas à la manière de inline-blockremplir le reste de la ligne.
Neurotransmetteur
1
@TranslucentCloud Je suis d'accord que ma réponse ne répond pas exactement au titre de la question, mais elle fournit un moyen de remplir la largeur disponible en utilisant divs, comme demandé dans le corps de la question.
Frosty Z
1
J'aime beaucoup cette solution. Vous n'êtes pas obligé d'utiliser des styles étranges qui proviennent de la logique CSS cachée (comme pour le débordement caché).
Chaoste
4

Vous pouvez utiliser calc (100% - 100px) sur l'élément fluide, avec display: inline-block pour les deux éléments.

Sachez qu'il ne doit pas y avoir d'espace entre les balises, sinon vous devrez également tenir compte de cet espace dans votre calcul.

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


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

Exemple rapide: http://jsfiddle.net/dw689mt4/1/

SuperIRis
la source
1

J'ai utilisé la flex-growpropriété pour atteindre cet objectif. Vous devrez définir display: flexpour le conteneur parent, puis vous devez définir flex-grow: 1pour le bloc que vous souhaitez remplir l'espace restant, ou tout flex: 1comme tanius mentionné dans les commentaires.

Vladislav Kovechenkov
la source
0

Si vous ne pouvez pas utiliser overflow: hidden(parce que vous ne voulez pas overflow: hidden) ou si vous n'aimez pas les hacks / solutions de contournement CSS, vous pouvez utiliser JavaScript à la place. Notez que cela peut ne pas fonctionner aussi bien car il s'agit de 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
la source