Come centrare un contenitore flessibile ma allineare a sinistra gli elementi flessibili


92

Voglio che gli elementi flessibili siano centrati ma quando abbiamo una seconda linea, avere 5 (dall'immagine sotto) sotto 1 e non centrati nel genitore.

inserisci qui la descrizione dell'immagine

Ecco un esempio di quello che ho:

ul {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
  margin: 0;
  padding: 0;
}
li {
  list-style-type: none;
  border: 1px solid gray;
  margin: 15px;
  padding: 5px;
  width: 200px;
}
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
</ul>

http://jsfiddle.net/8jqbjese/2/

Risposte:


79

Flexbox Challenge & Limitation

La sfida è centrare un gruppo di elementi flessibili e allinearli a sinistra sulla fasciatura. Ma a meno che non ci sia un numero fisso di scatole per riga e ogni scatola abbia una larghezza fissa, questo non è attualmente possibile con flexbox.

Utilizzando il codice pubblicato nella domanda, potremmo creare un nuovo contenitore flessibile che avvolge l'attuale contenitore flessibile ( ul), che ci consentirebbe di centrare il ulcon justify-content: center.

Quindi gli elementi flessibili di ulpotrebbero essere allineati a sinistra con justify-content: flex-start.

#container {
    display: flex;
    justify-content: center;
}

ul {
    display: flex;
    justify-content: flex-start;
}

Questo crea un gruppo centrato di elementi flessibili allineati a sinistra.

Il problema con questo metodo è che a determinate dimensioni dello schermo ci sarà uno spazio sulla destra del ul, che non apparirà più centrato.

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

Ciò accade perché nel layout flessibile (e, in realtà, CSS in generale) il contenitore:

  1. non sa quando un elemento va a capo;
  2. non sa che uno spazio precedentemente occupato è ora vuoto, e
  3. non ricalcola la sua larghezza per restringere il layout più stretto.

La lunghezza massima dello spazio bianco a destra è la lunghezza dell'elemento flessibile che il contenitore si aspettava fosse lì.

Nella demo seguente, ridimensionando la finestra orizzontalmente, puoi vedere gli spazi bianchi andare e venire.

DEMO


Un approccio più pratico

Il layout desiderato può essere ottenuto senza l'utilizzo di flexbox inline-blocke media query .

HTML

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
</ul>

CSS

ul {
    margin: 0 auto;                  /* center container */
    width: 1200px;
    padding-left: 0;                 /* remove list padding */
    font-size: 0;                    /* remove inline-block white space;
                                        see https://stackoverflow.com/a/32801275/3597276 */
}

li {
    display: inline-block;
    font-size: 18px;                 /* restore font size removed in container */
    list-style-type: none;
    width: 150px;
    height: 50px;
    line-height: 50px;
    margin: 15px 25px;
    box-sizing: border-box;
    text-align: center;
}

@media screen and (max-width: 430px) { ul { width: 200px; } }
@media screen and (min-width: 431px) and (max-width: 630px) { ul { width: 400px; } }
@media screen and (min-width: 631px) and (max-width: 830px) { ul { width:600px;  } }
@media screen and (min-width: 831px) and (max-width: 1030px) { ul { width: 800px; } }
@media screen and (min-width: 1031px) and (max-width: 1230px) { ul { width: 1000px; } }

Il codice precedente esegue il rendering di un contenitore centrato orizzontalmente con elementi figlio allineati a sinistra come questo:

inserisci qui la descrizione dell'immagine

DEMO


Altre opzioni


3
Sì, molto di ciò che le persone vogliono fare e finiscono per usare flexbox è in realtà solo creare una griglia. Fortunatamente questo sarà coperto da CSS Grids quando ciò raggiunge uno stato più finalizzato.
TylerH

1
Collegato questo post al tuo. Ho un'altra versione in là su come risolvere lo stesso problema, tuttavia, potrebbe essere un imbroglione, quindi dai un'occhiata e decidi tu stesso se vuoi chiuderlo come tale. E più 1 per la grande spiegazione in questo.
Ason

Forse un'altra idea è da fare margin:0 autosu un wrapper genitore, in modo che tutto sia centrato sulla pagina. Da quel punto, tutti i componenti figli, (cioè il primo contenitore flessibile) si limitano al normale processo di riga del flusso? Sembra che questo possa essere reso semplice da fare.
klewis

13

Puoi ottenerlo con CSS Grid, basta usare repeat(autofit, minmax(width-of-the-element, max-content))

ul {
       display: grid;
       grid-template-columns: repeat(auto-fit, minmax(210px, max-content));
       grid-gap: 16px;
       justify-content: center;
       padding: initial;
}

li {
    list-style-type: none;
    border: 1px solid gray;
    padding: 5px;
    width: 210px;
}
<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
</ul>

http://jsfiddle.net/rwa20jkh/


Interessante. Ma non elimina il distacco a destra né centra la griglia
Rossa

2
@Red C'era una cosa che non andava. Sono passato justify-items: centera justify-content:center, e ora si centra perfettamente.
Joe82

Non capisco la 210pxparte all'interno minmax. Come faccio a fare lo stesso ma senza una restrizione artificiale di 210px? Non esiste una tale restrizione con flexbox. Voglio esattamente lo stesso risultato di flexbox, ma l'area del contenuto deve essere centrata come nella tua soluzione.
Andrey Mikhaylov - lolmaus

1
Ciao @ AndreyMikhaylov-lolmaus, questo metodo funziona quando vuoi impostare una larghezza fissa per tutti gli elementi. Nella domanda, è espresso come width:200px, e nel mio esempio, come ho impostato width:210px, devo aggiungere anche quello nella minmaxparte
Joe82

@ Joe82 Grazie per aver chiarito! 🙏 Conosci un modo per farlo funzionare per elementi di larghezza arbitraria?
Andrey Mikhaylov - lolmaus

0

Come suggerito da @michael, questa è una limitazione con l'attuale flexbox. Ma se vuoi ancora usare flexe justify-content: center;, allora possiamo aggirare il problema aggiungendo un lielemento fittizio e assign margin-left.

    const handleResize = () => {
        const item_box = document.getElementById('parentId')
        const list_length  = item_box.clientWidth
        const product_card_length = 200 // length of your child element
        const item_in_a_row = Math.round(list_length/product_card_length)
        const to_be_added = item_in_a_row - parseInt(listObject.length % item_in_a_row) // listObject is the total number items
        const left_to_set = (to_be_added - 1 ) * product_card_length // -1 : dummy item has width set, so exclude it when calculating the left margin 
        const dummy_product = document.querySelectorAll('.product-card.dummy')[0]
        dummy_product.style.marginLeft = `${left_to_set}px`
    }
    handleResize() // Call it first time component mount
    window.addEventListener("resize", handleResize); 

Controlla questo violino (ridimensiona e guarda) o video come riferimento


0

Un modo per ottenere lo stile desiderato con i margini è eseguire le seguenti operazioni:

#container {
    display: flex;
    justify-content: center;
}

#innercontainer {
    display: flex;
    flex: 0.9; -> add desired % of margin
    justify-content: flex-start;
}

0

Puoi posizionare elementi invisibili con la stessa classe degli altri (rimossi nell'esempio per scopi di esposizione) e altezza impostata a 0. Con ciò, sarai in grado di giustificare gli elementi fino all'inizio della griglia.

Esempio

<div class="table-container">
  <div class="table-content">
    <p class="table-title">Table 1</p>
    <p class="mesa-price">$ 20</p>
  </div>
  
  <!-- Make stuff justified start -->
  <div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
  <div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
  <div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
  <div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
</div>

Risultato

inserisci qui la descrizione dell'immagine


0

Stavo affrontando un problema simile mentre cercavo di centrare i contenuti all'interno di flex. Ho provato molti trucchi e correzioni ma non funzionava a causa di un errore stupido.

Se qualcuno che viene qui non è in grado di aggirare il problema anche dopo aver letto queste risposte, prova a fare il checkout per errori stupidi. Nel mio caso si trattava di un spancon flex-growset per 1aggiunto come un distanziatore.


-1

Mi sono imbattuto in questo problema durante la codifica con React Native. C'è una soluzione elegante che puoi avere usando FlexBox. Nella mia situazione particolare, stavo cercando di centrare tre scatole flessibili (Flex: 2) all'interno di un'altra usando alignItems. La soluzione che ho trovato è stata l'utilizzo di due vuoti, ciascuno con Flex: 1.

<View style={{alignItems: 'center', flexWrap: 'wrap', flexDirection: 'row'}}>
  <View style={{flex: 1}} />
    // Content here
  <View style={{flex: 1}} />
</View>

Abbastanza facile da convertire in web / CSS.


Hai frainteso la domanda. L'OP non chiede come centrare 3 elementi, chiede come allineare a sinistra gli elementi su una seconda riga mentre tutti gli elementi vengono centrati come un gruppo, e per questo la tua soluzione non funziona.
Ason
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.