HTML : Aligner le dernier élément d'une liste
L'alignement à gauche du dernier élément d'une liste, une façon simple de procéder pour en venir à bout... définitivement.
html
css
jquery
Coup de coeur tiré de SOF* concernant un problème récurrent en CSS, l'alignement des listes, et en particulier, l'alignement du dernier élément (à gauche) dans un container dont on ne connait pas forcément les dimensions, élément qui a tendance à se balader un peu n'importe où, sauf là où on voudrait qu'il soit, sauf à se lancer dans des calculs, sauf à..., bref, LE pénible.
Je vous fais cadeau des bidouillages habituels, et des float
divers et variés, commençons par le basique de chez basique que nous allons modifier ; sans surprise, brut de chez brut, c'est moche :
<!--
#container{width:398px;height: 150px;border: 1px #808201 solid;background: #D7D88D;}
.child{width:78px;height:40px;border: red 1px solid;background: #DFA7A7;}
-->
<div id="container">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
Attaquons tout d'abord à la main, histoire de débroussailler cette jungle.
On va mettre un display:inline-block
sur les div enfants de façon à obtenir cet alignement ; ça marche mais l'alignement laisse à désirer, et sans connaître au préalable nos dimensions, ça ne sera jamais centré. (ex: si on rajoute un text-align:center
, ça ruine tout notre travail.)
Avec flex et justify-content:space-around
(ou autre valeur désirée) le début de la magie opère, c'est centré, mais la ou les dernières div se retrouvent au milieu, comme avec le text-align:center
du dessus, c'est là où nous faisons intervenir le "coup de coeur" : en rajoutant à la suite des div présentes (les .child
) autant de div qu'espérées en première ligne maximum, en leur donnant la même largeur et une hauteur à 0 => la hauteur à zéro est capitale.
On peut même bidouiller avec les marges, l'important étant que les div rajoutées aient la même largeur, + bords+marges, que les div "normales", comme ceci:
#container{width:378px;height: 150px;border: 1px #808201 solid;background: #D7D88D;overflow:hidden;display:flex;flex-wrap:wrap; justify-content:space-around;}
.child{width:78px;height:40px;border: red 1px solid;background: #DFA7A7;margin-top:20px; }
<div id="container">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div style="width: 80px;height:0;"></div>
<div style="width: 80px;height:0;"></div>
<div style="width: 80px;height:0;"></div>
<div style="width: 80px;height:0;"></div>
</div>
On remarque que, quel que soit le nombre de div alignées sur le premier rang, ça marche très bien pour 5, 4, 3 etc...
Ce qu'on peut déjà en conclure, c'est que si vous êtes sûr que jamais (au grand jamais) votre container ne dépassera une valeur donnée (et donc connue), vous pouvez vous arrêtez là : le nombre attendu de div en ligne est également connu de fait.
Le problème se pose quand la largeur du container devient plus importante que la largeur cumulée des n div + 1 largeur de div (et que vous ne voulez pas centrer à gauche) les div "fantômes" remontant en première ligne dès que la place devient suffisante et de fait, la réalignant avec elles, donc mal, pour ne pas dire : n'importe comment. (En fait, l'alignement est très propre, mais ce qu'on voit est moche.)
- En évitant de surcharger le code en dur avec des valeurs qu'on ignore.
- En positionnant les .child sans connaître la dimension initiale du container
- En automatisant le placement des div en fonction de la taille (ici en la modifiant, plus grande ou plus petite, nos div doivent toujours être alignées) ; voici d'ores et déjà le résultat, on remarque (de façon réjouie) que les div restent alignées même pendant les modifications de taille.
Et voici les codes :
#container{width:378px;padding:10px;height: 150px;border: 1px #808201 solid;background: #D7D88D;overflow:hidden;display:flex;flex-wrap:wrap; justify-content:space-around;}
.child{width:78px;height:40px;border: red 1px solid;background: #DFA7A7;margin:5px; }
.new{width:80px;height:0;margin:5px;}
<div id="container">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
padding
au container et des margin
aux enfants (y compris aux div fantômes), et le HTML ne comprend que les div requises. (Au passage, leur nombre n'a aucune importance, on va gérer ça en-dessous)et le JQuery :
var le = $(".child").length; // Nombre de .child
var childWi = $(".child").width() + 10; // largeur d'une .child (hors-tout hein !)
var parWi = $("#container").width() + 2; // largeur du container (toujours hors-tout)
var maxLign = parseInt(parWi / childWi); // Nbr de .child sur une ligne (parseInt pour récupérer un int)
Ajout(); // on initialise le nombre de div fantômes
$("#container").resizable({ //pour les besoins de cet article, resizable
resize: function(e,evS) { // récupe des modifications de taille "on the fly" **
Resiz(evS.size.width); // on expédie la nouvelle taille à Resiz()
}
});
function Ajout(){
if(!$(".new")[0]) { // on vérifie qu'il n'y a pas déjà des .new (sinon il va en mettre un paquet avec Resiz()
for(var i=0; i<maxLign;i++){ // et tant que i augmente vers le nombre de divs max en une ligne
$("#container").append('<div class="new"></div>'); // on en ajoute (pardi, vu qu'on est là pour ça)
}
}
}
function Resiz(newWi) {
if(newWi > (childWi * le) + childWi) { // si la nouvelle taille du container est sup. à la largeur des .child + 1,
$("div .new").remove(); // on lourde sauvagement toutes les .new.
} else { // autrement
Ajout(); // on les rajoute piteusement
}
}
Voilà l'idée, on peut donc aligner dans une div de taille inconnue des enfants à la seule condition qu'ils soient tous de la même taille (ce qui semble logique en fait).
Je suppose également (je n'ai pas essayé) qu'on doit pouvoir se contenter d'une seule .new dont on modifierait la taille à la demande, voire même d'un pseudo-élément ::after
, histoire de grappiller quelques octets...
Si vous remarquez une erreur, ou pour toute question, n'hésitez pas à me contacter !
* https://stackoverflow.com/
** C'est pour le fun ici, mais à chaque fois, on allume Resiz(), ce qui consomme énormément de ressources : il vaudra mieux de loin s'intéresser à stop
si c'est possible (à la place de resize
)
Pas encore de commentaire