5
votes

Comment aplatir les divs imbriqués pour les afficher dans une grille CSS?

Je génère une table (avec vue.js) à partir d'un objet supposé avoir deux colonnes de large. Chacune des colonnes provient de la clé et de la valeur de l'objet. Cela équivaut au HTML réel suivant:

<div id="table">
  <div>
    <div>
      this is something long on the first row
    </div>
    <div>
      short 1st row
    </div>
  </div>
  <div>
    <div>
      wazaa 2nd row
    </div>
    <div>
      wazii 2nd row
    </div>
  </div>
</div>

J'utilise la grille CSS pour formater ces div en une grille 2x2, ce que je m'attendais à être

XXX

Le code pour faire ça:

#table {
  display: grid;
  grid-template-columns: auto 1fr;
}
this is something long on the first row | short 1st row
wazaa 2nd row                           | wazii 2nd row

Le résultat n'est pas celui que j'attends: les deux div les plus profonds se comportent comme ils le devraient en dehors d'un affichage grid : ils s'empilent au-dessus de chacun autre.

Je voulais qu'ils héritent du comportement de la grille: s'aligner en fonction des modèles de colonnes au fur et à mesure. Comment y parvenir?


3 commentaires

Vous devrez déplier la couche intermédiaire de l'imbrication

, car c'est ce que la grille CSS ne peut pas gérer.


Ouais, cela nécessitera probablement un script. Pourquoi annulez-vous la structure créée par VueJS? Pourquoi ne pas créer la vue appropriée en premier lieu?


Vous ne créez pas de table, vous créez des div. Les divisions n'ont aucune signification sémantique alors qu'une table a une certaine signification. Donc, si vous voulez afficher des données tabulaires, vous devez vraiment utiliser une

, si vous voulez simplement styliser un contenu non lié, utilisez des divs avec display: grid.


3 Réponses :


3
votes

Vous pouvez utiliser display: contents ( https: // caniuse.com/#feat=css-display-contents ) pour surmonter ce problème:

<div id="table">
  <div>
    <div>
      this is something long on the first row
    </div>
    <div>
      short 1st row
    </div>
  </div>
  <div>
    <div>
      wazaa 2nd row
    </div>
    <div>
      wazii 2nd row
    </div>
  </div>
</div>
#table {
  display: table;
}

#table > div {
  display:table-row;
}
#table > div > div {
  display:table-cell;
  padding:5px;
}
#table > div > div:first-child {
  white-space:nowrap;
  width:10%;
}

Ou utilisez le tableau d'affichage comme ci-dessous:

<div id="table">
  <div>
    <div>
      this is something long on the first row
    </div>
    <div>
      short 1st row
    </div>
  </div>
  <div>
    <div>
      wazaa 2nd row
    </div>
    <div>
      wazii 2nd row
    </div>
  </div>
</div>
#table {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-gap:10px;
}

#table > div {
  display:contents;
}


1 commentaires

@Woj Assurez-vous de lire les informations du site caniuse, car le support est limité.



1
votes

Si possible, je vous conseillerais de changer votre code Vue.js pour ne pas générer le niveau div imbriqué inutile, et en faire ceci:

<div id="table">
  <div>
    <div>
      this is something long on the first row
    </div>
    <div>
      short 1st row
    </div>
  </div>
  <div>
    <div>
      wazaa 2nd row
    </div>
    <div>
      wazii 2nd row
    </div>
  </div>
</div>
#table {
  display: grid;
  grid-template-columns: auto 1fr;
}
#table > div { border: 1px dotted black }

Si ce n'est pas possible, vous pouvez utiliser Javascript pour réaliser la même chose, mais côté client. Vous pouvez également utiliser display: contents du réponse de @Temani mais la prise en charge du navigateur est plutôt limitée avec des résultats éventuellement bogués.


Si vous préférez une solution Javascript à la place, vous pouvez utiliser ceci:

(function() {
  var table = document.getElementById("table");
  var divs = [...table.childNodes]; // use ... to enumerate the items immediately
  for (var i = 0; i < divs.length; i++) {
    var div = divs[i];
    while (div.childNodes.length > 0)
      table.appendChild(div.childNodes[0]);
    div.remove();
  }
})()
<div id="table">
  <div>
    this is something long on the first row
  </div>
  <div>
    short 1st row
  </div>
  <div>
    wazaa 2nd row
  </div>
  <div>
    wazii 2nd row
  </div>
</div>
#table {
  display: grid;
  grid-template-columns: auto 1fr;
}
#table > div { border: 1px dotted black; }


0 commentaires

3
votes

Les propriétés de la grille ne s'appliquent pas à vos divs de contenu, car ces divs sont hors de portée.

Le formatage de la grille est limité à la relation parent-enfant. Cela signifie qu'un conteneur de grille est toujours le parent et un élément de grille est toujours l'enfant. Les descendants d'un conteneur de grille au-delà des enfants ne font pas partie de la disposition de la grille et n'accepteront pas les propriétés de la grille.

Parce que vos divs de contenu sont deux niveaux plus bas que le conteneur de grille ( #table ), ce qui en fait des petits-enfants et non des enfants, ce ne sont pas des éléments de la grille et n'accepteront pas les propriétés de la grille.

Plus de détails: Les propriétés de la grille ne fonctionnent pas sur les éléments à l'intérieur du conteneur de la grille


Il existe des exceptions à la règle ci-dessus, mais elles n'ont pas beaucoup ou pas de support de navigateur.

display: contents est traité dans une autre réponse à ce message . Cela permet à un élément d'être ignoré en tant que bloc conteneur par le parent, de sorte que le parent reconnaîtra ses petits-enfants comme des enfants normaux. Mais pour l'instant, cette méthode est effectivement inutile à des fins de production, car elle a une un support de navigateur faible a >.

La solution la plus appropriée dans ce cas serait display: subgrid , qui permet aux descendants d'un conteneur de grille au-delà des enfants (c'est-à-dire les enfants des éléments de la grille) de respecter les lignes du conteneur. Mais cette fonctionnalité ne prend pas en charge le navigateur.

Plus de détails: Positionnement du contenu des éléments de la grille dans le conteneur principal (fonction de sous-grille)


Si vous voulez une solution CSS pure, peut-être qu'une combinaison de grille et de flex peut vous aider.

Voici un concept général. Aucune modification du code HTML.

<div id="table">
  <div>
    <div>
      this is something long on the first row
    </div>
    <div>
      short 1st row
    </div>
  </div>
  <div>
    <div>
      wazaa 2nd row
    </div>
    <div>
      wazii 2nd row
    </div>
  </div>
</div>
#table {
  display: grid;
  grid-template-columns: 1fr;
}

#table > div {
  display: flex;
}

#table > div > div {
  flex: 1;
}


0 commentaires