J'ai un tas de blocs de même taille définis à display:inline-block
à l'intérieur d'un div qui a text-align:center
défini pour aligner les blocs.
| _____ _____ _____ _____ |
| | | | | | | | | |
| | 1 | | 2 | | 3 | | 4 | |
| |_____| |_____| |_____| |_____| |
| _____ _____ _____ _____ |
| | | | | | | | | |
| | 5 | | 6 | | 7 | | 8 | |
| |_____| |_____| |_____| |_____| |
| |
Les blocs remplissent la division horizontalement et, à mesure que la fenêtre du navigateur se réduit, certains blocs se cassent en nouvelles lignes, créant ainsi plus de lignes et moins de colonnes. Je veux que tout reste toujours centré, avec la dernière rangée alignée à gauche, comme ceci:
| _____ _____ _____ |
| | | | | | | |
| | 1 | | 2 | | 3 | |
| |_____| |_____| |_____| |
| _____ _____ _____ |
| | | | | | | |
| | 4 | | 5 | | 6 | |
| |_____| |_____| |_____| |
| _____ _____ |
| | | | | |
| | 7 | | 8 | |
| |_____| |_____| |
| |
Ce qui se passe actuellement est la suivante:
| _____ _____ _____ |
| | | | | | | |
| | 1 | | 2 | | 3 | |
| |_____| |_____| |_____| |
| _____ _____ _____ |
| | | | | | | |
| | 4 | | 5 | | 6 | |
| |_____| |_____| |_____| |
| _____ _____ |
| | | | | |
| | 7 | | 8 | |
| |_____| |_____| |
| |
Je ne peux pas ajouter de divs de remplissage supplémentaires comme une suggestion, car il pourrait y avoir un nombre quelconque de blocs et le nombre de lignes et de colonnes varie en fonction de la largeur du navigateur. Je ne peux pas non plus appeler directement le bloc 7 pour la même raison. Les blocs doivent toujours rester centrés quel que soit le nombre de colonnes.
Voici un stylo pour mieux démontrer:
http://codepen.io/anon/pen/IDsxn
Est-ce possible? Je pense que ça devrait l'être. Je préférerais ne pas utiliser flexbox car c'est seulement ie10 +, et je voudrais ie9 +. J'aimerais vraiment une solution CSS pure, mais si vous me dites que JS est le seul moyen, j'aimerais voir cela en action.
Pour référence - des questions similaires, bien qu'aucune n'ait été expliquée à fond:
Comment aligner la dernière ligne/gauche dans une flexbox à plusieurs lignes
CSS - Aligner à gauche la dernière ligne d'images dans un div centré
Centrer plusieurs blocs en ligne avec CSS et aligner la dernière ligne à gauche
Voici une solution JavaScript très simple (et quelques modifications mineures dans votre CSS):
Cela fonctionne bien pour moi.
CSS:
.container {
margin: 0 auto;
max-width:960px;
background-color: gold;
}
.block {
background-color: #ddd;
border:1px solid #999;
display: block;
float: left;
height: 100px;
margin: 4px 2px;
width: 100px;
}
JavaScript:
$(document).ready(function(){
setContainerWidth();
});
$(window).resize(function(){
setContainerWidth();
});
function setContainerWidth()
{
$('.container').css('width', 'auto'); //reset
var windowWidth = $(document).width();
var blockWidth = $('.block').outerWidth(true);
var maxBoxPerRow = Math.floor(windowWidth / blockWidth);
$('.container').width(maxBoxPerRow * blockWidth);
}
jQuery est obligatoire :)
Cette grille adaptive est beaucoup plus simple: moins de balisage et moins de CSS, ce qui facilite son implémentation sur un site de production et son adaptation à vos besoins.
= >> DEMO << = (redimensionne la fenêtre de résultat pour voir l'effet)
html, body {
margin:0;
padding:0;
}
#container{
font-size:0;
margin:0 auto;
width:1000px;
}
.block {
font-size:20px;
width: 150px;
height: 150px;
margin:25px;
background: gold;
display:inline-block;
}
@media screen and (max-width: 430px) {
#container{
width:200px;
}
}
@media screen and (min-width: 431px) and (max-width: 630px) {
#container{
width:400px;
}
}
@media screen and (min-width: 631px) and (max-width: 830px) {
#container{
width:600px;
}
}
@media screen and (min-width: 831px) and (max-width: 1030px) {
#container{
width:800px;
}
}
<div id="container">
<div class="block">1</div>
<div class="block">2</div>
<div class="block">3</div>
<div class="block">4</div>
<div class="block">5</div>
<div class="block">6</div>
<div class="block">7</div>
<div class="block">8</div>
<div class="block">9</div>
<div class="block">10</div>
<div class="block">11</div>
<div class="block">12</div>
<div class="block">13</div>
</div>
Ça implique :
4 requêtes de support pour des blocs de 200 pixels de large et un conteneur extensible jusqu'à 1 000 pixels. En fonction de la largeur de vos éléments de grille et de la largeur totale de votre conteneur, vous devrez peut-être en faire plus ou plus.
suppression des espaces blancs entre les éléments inline-block (dans la démonstration suivante, j'ai utilisé la technique de la taille de la police mais vous pouvez en utiliser d'autres (voir Comment supprimer l'espace entre les éléments inline-block? for other techniques)
marges fixes entre blocs
Le nombre de blocs d'une ligne s'adapte à la taille du conteneur. La propriété text-align
reste à la valeur par défaut left
de sorte que les derniers éléments soient alignés à gauche.
= >> DEMO << = (vous devez redimensionner la fenêtre de résultat sous 750px pour la voir en action)
html, body {
margin:0;
padding:0;
min-width:150px;
}
.wrap {
float:left;
position:relative;
}
.foto {
width: 150px;
height: 150px;
background: gold;
position:absolute;
}
#warning{display:none;}
@media screen and (min-width: 631px) {
.wrap {
width:20%;
padding-bottom:25%;
}
.wrap:nth-child(4n+2), .wrap:nth-child(4n+3){
}
.wrap .foto {
top:-75px;
margin-top:100%;
right:-30px;
}
.wrap:nth-child(4n+2){
margin:0 5% 0 7.5%;
}
.wrap:nth-child(4n+3){
margin-right:7.5%;
}
.wrap:nth-child(4n+2) .foto{
left:50%;
margin-left:-75px;
}
.wrap:nth-child(4n+3) .foto{
right:50%;
margin-right:-75px;
}
.wrap:nth-child(4n) .foto{
left:-30px;
}
#container{
margin-top:-45px;
}
}
@media screen and (min-width: 481px) and (max-width: 631px) {
.wrap {
width:25%;
padding-bottom:33.3%;
}
.wrap:nth-child(3n+2){
margin:0 12.5%;
}
.wrap .foto {
top:-75px;
margin-top:100%;
right:-37px;
}
.wrap:nth-child(3n+2) .foto{
left:50%;
margin-left:-75px;
}
.wrap:nth-child(3n) .foto{
left:-37px;
}
#container{
margin-top:-37px;
}
}
@media screen and (min-width: 331px) and (max-width: 480px) {
.wrap {
width:33.3%;
padding-bottom:50%;
clear:left;
}
.wrap:nth-child(even) {
float:right;
clear:right;
}
.wrap .foto {
top:-75px;
margin-top:100%;
right:-50px;
}
.wrap:nth-child(even) .foto {
left:-50px;
}
.wrap:nth-child(4n+3) .foto, .wrap:nth-child(4n+4) .foto {
bottom:-75px;
margin-bottom:100%;
}
#container{
margin-top:-25px;
}
}
@media screen and (max-width: 330px) {
.wrap {
width:50%;
padding-bottom:100%;
clear:left;
}
.wrap:nth-child(odd) .foto {
right:-75px;
bottom:0;
bottom:-75px;
margin-bottom:100%;
}
.wrap:nth-child(even) .foto {
top:0px;
right:-75px;
top:-75px;
margin-top:100%;
}
}
@media screen and (min-width: 751px) {
#warning{
color:#fff;
display:block;
position:fixed;
width:100%;
height:50%;
top:25%;
left:0;
background:#000;
text-align:center;
font-size:30px;
}
<div id="container">
<div class="wrap"><div class="foto">1</div></div>
<div class="wrap"><div class="foto">2</div></div>
<div class="wrap"><div class="foto">3</div></div>
<div class="wrap"><div class="foto">4</div></div>
<div class="wrap"><div class="foto">5</div></div>
<div class="wrap"><div class="foto">6</div></div>
<div class="wrap"><div class="foto">7</div></div>
<div class="wrap"><div class="foto">8</div></div>
<div class="wrap"><div class="foto">9</div></div>
<div class="wrap"><div class="foto">10</div></div>
<div class="wrap"><div class="foto">11</div></div>
<div class="wrap"><div class="foto">12</div></div>
<div class="wrap"><div class="foto">13</div></div>
<div class="wrap"><div class="foto">14</div></div>
<div class="wrap"><div class="foto">15</div></div>
</div>
<!-- FOLLOWING JUST FOR THE DEMO -->
<div id="warning">I haven't written the code for windows bigger than 751px.<br/>
You must resize this window under 751px.</div>
Cette technique implique:
position:absolute;
:nt-child()
css selectorIl centre les blocs dans leur conteneur et donne la même marge en haut/gauche/serré/bas de tous les blocs + côtés du conteneur. Comme cette solution utilise des éléments flottants, la dernière ligne est alignée à gauche.
Le nombre de blocs d'une ligne s'adapte à la largeur de la fenêtre.
Pour ce que ça vaut: Nous sommes maintenant en 2017 et le module d'agencement de la grille le fait immédiatement.
* {
margin:0;
padding:0;
}
.container {
display: grid;
grid-template-columns: repeat(auto-fill, 100px);
grid-gap: 10px;
justify-content: center;
align-content: flex-start;
margin: 0 auto;
text-align: center;
margin-top: 10px;
}
.block {
background-color: #ddd;
border: 1px solid #999;
height: 100px;
width: 100px;
}
<div class="container">
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
</div>
Si le support du navigateur vous convient, utilisez la grille. Si non, alors lisez la suite ....
Comme mentionné dans la réponse de @ Web-tiki, le mieux que vous puissiez faire avec CSS est une série de requêtes multimédia.
Cela étant dit, si vous utilisez un préprocesseur tel que LESS, la tâche n'est pas si difficile ni sujette aux erreurs. (bien que, oui, le CSS sera toujours long et moche)
Voici comment tirer parti de MOINS pour configurer les requêtes multimédia:
Commencez par définir quelques variables en fonction du modèle dont vous avez besoin:
@item-width:100px;
@item-height:100px;
@marginV: 4px;
@marginH: 2px;
@min-cols:2;
@max-cols:9; //set an upper limit of how may columns you want to write the media queries for
Ensuite:
Configurez un mix d'itération comme ceci: (Vous pouvez coller ce code dans http://less2css.org )
.loopingClass (@index-width) when (@index-width <= @item-width * @max-cols) {
@media (min-width:@index-width) {
.container{
width: @index-width;
}
}
.loopingClass(@index-width + @item-width + 2*@marginH);
}
.loopingClass (@item-width * @min-cols + @min-cols*@marginH*2);
Le mixin ci-dessus va cracher une série de requêtes médiatiques sous la forme:
@media (min-width: 208px) {
.container {
width: 208px;
}
}
@media (min-width: 312px) {
.container {
width: 312px;
}
}
@media (min-width: 416px) {
.container {
width: 416px;
}
}
@media (min-width: 520px) {
.container {
width: 520px;
}
}
@media (min-width: 624px) {
.container {
width: 624px;
}
}
@media (min-width: 728px) {
.container {
width: 728px;
}
}
@media (min-width: 832px) {
.container {
width: 832px;
}
}
Avec les CSS restants (MOINS):
.container {
margin: 0 auto;
text-align: center;
overflow: auto;
min-width: @min-cols * @item-width;
max-width: @max-cols * @item-width;
display: block;
list-style:none;
}
.block {
background-color: #ddd;
border:1px solid #999;
box-sizing:border-box;
float: left;
height: @item-height;
width: @item-width;
margin:@marginV @marginH;
}
... vous obtenez le résultat souhaité.
Tout ce que je dois faire est de changer les variables que j'ai utilisées dans le mixin LESS en fonction de mes besoins - je reçois la mise en page exacte que je suis après.
Avec flexbox, quelques pseudo-éléments, une div supplémentaire, et après beaucoup de frustration, j'ai pu y parvenir sans interrogation de média (étant donné que je devais insérer ma grille dans de nombreux éléments de tailles différentes, les requêtes de média ne fonctionneraient pas vraiment pour moi). .
Une mise en garde: les gouttières entre les articles sont fluides.
Démo: http://codepen.io/anon/pen/OXvxEW
CSS:
.wrapper {
display: flex;
flex-wrap: wrap;
border: 2px solid #ffc0cb;
max-width: 1100px;
margin: 0.5rem auto;
justify-content: center;
}
.wrapper:after {
content: ' ';
flex: 1;
height: 100%;
border: 1px solid #00f;
margin: 0.5rem;
}
.child {
flex: 1;
border: 2px solid #ffa500;
min-width: 300px;
margin: 0.5rem;
text-align: center;
}
.child-contents {
width: 300px;
border: 2px solid #008000;
height: 100px;
margin: 0 auto;
}
HTML:
<div class='wrapper'>
<div class='child'>
<div class='child-contents'></div>
</div>
<div class='child'>
<div class='child-contents'></div>
</div>
<div class='child'>
<div class='child-contents'></div>
</div>
...etc., more .child's...
</div>
Le résultat final est quelque chose comme ceci, où les rectangles verts sont divs. Les bordures rose/orange sont juste pour référence afin que vous puissiez voir ce qui se passe. Si vous supprimez les bordures rose/orange, vous devriez obtenir la grille que vous recherchez (encore une fois, notez que les gouttières sont fluides).
À ce jour, la seule solution propre à cet égard est la
Fondamentalement, le code pertinent nécessaire se résume à ceci:
ul {
display: grid; /* (1) */
grid-template-columns: repeat(auto-fill, 120px); /* (2) */
grid-gap: 1rem; /* (3) */
justify-content: center; /* (4) */
align-content: flex-start; /* (5) */
}
1) Faire de l’élément conteneur un conteneur de grille
2) Définissez la grille avec une quantité 'auto' de colonnes de largeur 120px. (La valeur de remplissage automatique est utilisée pour les mises en page réactives).
3) Définissez les espaces/gouttières pour les lignes et les colonnes de la grille.
4) et 5) - Similaire à la flexbox.
body {
margin: 0;
}
ul {
display: grid;
grid-template-columns: repeat(auto-fill, 120px);
grid-gap: 1rem;
justify-content: center;
align-content: flex-start;
/* boring properties: */
list-style: none;
width: 90vw;
height: 90vh;
margin: 2vh auto;
border: 5px solid green;
padding: 0;
overflow: auto;
}
li {
background: tomato;
height: 120px;
}
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ul>
Actuellement pris en charge par Chrome (Blink) et Firefox, avec prise en charge partielle de IE et Edge (voir cet article de Rachel Andrew)
Lectures complémentaires sur les grilles CSS:
Utilisez flexbox:
.container {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: row;
flex-direction: row;
-webkit-justify-content: flex-start;
justify-content: flex-start;
flex-wrap:wrap;
}
.block {
background-color: #ddd;
border:1px solid #999;
display: inline-block;
height: 100px;
margin: 4px 2px;
width: 100px;
}
Terminé.
Il n’existe pas de solution "normale" à votre problème, mais uniquement les "solutions de contournement" mentionnées.
La situation est la suivante: votre conteneur de blocs remplira l’espace disponible jusqu’au maximum disponible/configuration, puis cassera tous les blocs internes à la ligne suivante, ce qui entraînera un débordement du conteneur. Également avec d'autres configurations comme flottante, le comportement sera le même. C’est ainsi que fonctionne le rendu - chaque fois qu’il est gourmand dans l’espace pour calculer le comportement des éléments internes.
Peut-être que l'avenir Flexboxes rendra cela possible - mais je n'ai pas lu toutes les spécifications. Juste une supposition ...
Essayez ceci avec un simple css:
CSS:
.row {text-align: center; taille de la police: 0;} . block {text-align: center; affichage: bloc en ligne; largeur: 150px; hauteur: 15px; marge: 5px; bordure: 1px solide #dddddd; taille de la police: 13px;}
HTML:
<div class="row">
<div class="block"></div>
</div>
.row{text-align:center;font-size:0;}
.block{text-align:center;display:inline-block;width:150px;height:150px;margin:5px; border:1px solid #dddddd;font-size:13px;line-height:150px;}
<div class="row">
<div class="block">1</div>
<div class="block">2</div>
<div class="block">3</div>
<div class="block">4</div>
<div class="block">5</div>
<div class="block">6</div>
<div class="block">7</div>
<div class="block">8</div>
</div>