web-dev-qa-db-fra.com

La disposition CSS multi-colonnes des éléments de liste ne s'aligne pas correctement dans Chrome

Je construis un système de menus présenté à l'utilisateur en format multi-colonnes. La propriété column-count de CSS3 m'obtient à 90%, mais j'ai des difficultés avec l'alignement sous Chrome.

Le menu est relativement simple:

  • une liste non ordonnée divisée en plusieurs colonnes par la propriété column-count
  • les colonnes doivent se remplir séquentiellement, donc column-fill: auto
  • les éléments de menu sont représentés sous forme d'éléments de liste
  • chaque élément de la liste a une balise d'ancrage cliquable, entièrement étendue via display: block

Le problème d'alignement que je rencontre est particulièrement perceptible avec une bordure supérieure et des couleurs d'arrière-plan sur chaque élément de la liste. Dans Firefox, les éléments de la liste sont toujours bien alignés sur chaque colonne, sans jamais déborder dans la colonne précédente/suivante. Dans Chrome, l'alignement correspond à un craps, qui varie en fonction du nombre d'éléments de la liste et des propriétés de remplissage/marge.

J'ai posté le code d'un simple cas de test ici: http://Pastebin.com/Ede3JwdG

Le problème doit apparaître immédiatement: dans Chrome, le premier élément de la deuxième colonne de la liste est redéfini dans la première. Lorsque vous supprimez des éléments de la liste (cliquez dessus), vous pouvez voir que l'alignement se dégrade davantage.

J'ai essayé de peaufiner le remplissage/la marge des éléments de la liste, mais en vain: Chrome semble avoir un algorithme imparfait pour ce qui est du flux de contenu sur une mise en page à plusieurs colonnes.

La raison principale pour laquelle je n'ai pas abandonné complètement le compte de colonnes (en faveur de la génération manuelle/Columnizer/etc.) Est que le système de menus implique également une fonctionnalité de glisser-déposer sur plusieurs sous-menus, et que les données de menu sont disposées En tant que hiérarchie cohésive basée sur des listes, le code est propre.

Existe-t-il un moyen de résoudre le problème d'alignement dans Chrome ou dois-je tout simplement abandonner nombre de colonnes pour le moment?

AJOUTÉE:

44
Ben D

Chaque élément de la colonne doit être affiché sous forme de "bloc en ligne". Cela résoudra votre problème sans avoir besoin d’utiliser jQuery.

De plus, chaque élément peut être spécifié avec width: 100% afin de lui permettre d'utiliser toute la largeur des lignes.

Voici un exemple de travail:

$(document).ready(function() {
    for( var i = 0; i < 24; i++ ) {
        $("ul.newslist").append("<li><a href='#'>Item</a></li>");
    }
    $("ul.newslist > li").click(function() {
        $(this).remove();
    })
});
ul.newslist {
    columns: 5;
    background-color: #ccc;
    padding: 16px 0;
    list-style: none;
}

ul.newslist > li {
    display: inline-block;
    width: 100%;
    border-top: 1px solid #000;
}

ul.newslist > li > a {
    display: block;
    padding: 4px;
    background-color: #f6b;
    text-decoration: none;
    color: inherit;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="newslist"></ul>

45
asiby

J'ai réussi à équilibrer des colonnes inégales alignées verticalement en appliquant les propriétés margin-* aux éléments contenus dans le conteneur multicolonne.

.content {
  column-width: 15em; /* or could be column-count, however you want to set up multi columns */
}
.content > section {
  -webkit-margin-before: 0;
  -webkit-margin-after: 0;
}
19
kmerc

J'ai également joué, et plusieurs sources que j'ai consultées en ligne font penser qu'il s'agit d'un problème connu avec webkit. Une bonne ventilation peut être trouvée ici: http://zomigi.com/blog/deal-breaker-problems-with-css3-multi-columns/

Un jour, CSS 3!

Peut-être essayez-vous un plugin jQuery du type http://welcome.totheinter.net/columnizer-jquery-plugin/ ?

16
Jack Lawson

En ce qui concerne les marges verticales. Vous pouvez remplacer margin par pseudo-élément. Ensuite, réglez sa hauteur sur la valeur de marge souhaitée. Vous devez également définir -webkit-column-break-inside: avoid; sur l'élément contenant le pseudo-élément afin qu'il ne soit pas déplacé vers une autre colonne. Ne le faites que pour le kit Web à l'aide de CSS-hack (non recommandé) ou de js-detection (meilleure méthode). Voici CSS: 

.element {
  -webkit-column-break-inside: avoid;
}
.element:after {
  content: '';
  display: block;
  height: 20px;
}
13
Andrey

J'avais des problèmes d'alignement vertical sur une liste à plusieurs colonnes. Il s'est avéré que le problème était que j'utilisais le remplissage en bas de ma liste. J'ai changé le style de li pour utiliser une marge inférieure à la place, et les colonnes alignées à nouveau en haut.

5
Julie Olson

J'ai résolu ce problème en supprimant les marges verticales sur les éléments enfants, puis en augmentant la hauteur de ligne des enfants pour répliquer l'espacement souhaité.

J'ai également remarqué que je pouvais résoudre ce problème d'alignement vertical en supprimant les marges enfants et en le convertissant en rembourrage pour petits-enfants.

2
Eleanor Zimmermann

Mon résultat souhaité était de vouloir obtenir une longue liste de liens à afficher sur 3 colonnes. Le simple fait d'utiliser column-break-inside:avoid; seul ne fonctionnait pas dans Webkit.

HTML

<div class="links">
  <ol>
    <li><a>link</a></li> <!-- x 50 -->
  </ol>
</div>

css:

.links ol {
  -webkit-column-count: 3;
  -moz-column-count: 3;
  column-count: 3;
}

.links li {
  display: block;
  border: 1px solid $background-colour; //to appear invisible
  -moz-column-break-inside:avoid;
  -webkit-column-break-inside:avoid;
  column-break-inside:avoid;
}

.links a {
  display: block;
  margin-bottom: 10px;
}

Solution (bizarrerie si vous voulez)

J'ai ajouté une bordure de 1px autour des éléments de la liste qui semblait contenir les marges de ses enfants et chaque colonne alignée ensuite en haut.

Edit: Cela ne semble être nécessaire que si vous utilisez le border-box global

html {
  box-sizing: border-box;
}
*, *:before, *:after {
  box-sizing: inherit;
}
1
Kiee

Je me bats aussi avec cela, pour un système de reporting avec beaucoup de données et de titres avec padding/margin que j'ai besoin de mettre sur plusieurs colonnes pour des écrans plus larges.

J'ai travaillé sur mon premier gros problème, le remplissage de l'élément de titre initial, avec la pseudo-classe :first-child (elle est incluse dans une règle @media pour les écrans larges non illustrés ici):

La définition des colonnes:

.dimSlider .multicol {
  -moz-columns: 4;
  -webkit-columns: 4;
  columns: 4;
}

Annuler le remplissage sur le dessus lorsque vous êtes dans .multicol

.dimSlider .multicol h3 {
  padding-top: 0;
}

Annulation du remplissage et de la marge pour le premier élément (color: blue; permet de voir si la règle est capturée):

.dimSlider .multicol .criteria:first-child h3 {
  padding: 0 2%;
  margin: 0;
  color: blue;
}

Jusqu'ici, cela semble beaucoup plus net dans mon Firefox. Je verrai s'il y a encore du bricolage à faire, mais actuellement dans Firefox, le texte semble aligné en haut, ce qui est le plus important. 

EDIT: Le problème semble bien pire avec les navigateurs Webkit. Pour le résoudre entièrement, j'ai modifié le modèle afin d'avoir un <div></div> autour de toutes les sections intitulées afin que je puisse ajouter du padding/margin à la fin des divs et non au début des titres. Désormais, dans les navigateurs Webkit, tout semble aller bien.

En passant, utiliser des mesures en pourcentages sur plusieurs colonnes est assez délicat, car le pourcentage semble calculé en fonction de la largeur de la colonne et non de la largeur globale de l'élément parent. J'ai changé cela en ajoutant un rembourrage dans l'élément parent des colonnes.

Mais la plus grande difficulté est que Firefox ne prend en charge aucune propriété de colonne ou étendue, donc lorsque j'ai très peu de contenu, il est néanmoins réparti sur les colonnes, comme une ou deux lignes sur chacune. Encore une fois, Smarty à la rescousse:

{if $element|@count <= 10}
<div class="nocol"> 
{/if} 

Jusqu'à présent, cela fonctionne maintenant pour moi ...

0
Joel.O