Cara memusatkan wadah fleksibel tetapi item flex rata kiri

91

Saya ingin item flex berada di tengah tetapi ketika kita memiliki baris kedua, memiliki 5 (dari gambar di bawah) di bawah 1 dan tidak di tengah orang tua.

masukkan deskripsi gambar di sini

Inilah contoh dari apa yang saya miliki:

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/

Etienne Noël
sumber

Jawaban:

79

Tantangan & Batasan Flexbox

Tantangannya adalah memusatkan sekelompok item fleksibel dan meratakannya ke kiri pada bungkus. Tetapi kecuali jika ada sejumlah kotak tetap per baris, dan setiap kotak memiliki lebar tetap, ini saat ini tidak mungkin dengan flexbox.

Menggunakan kode yang diposting dalam pertanyaan, kita bisa membuat wadah flex baru yang membungkus wadah flex saat ini ( ul), yang akan memungkinkan kita untuk memusatkan uldengan justify-content: center.

Kemudian item flex ulbisa diratakan dengan kiri justify-content: flex-start.

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

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

Ini membuat grup item flex rata kiri di tengah.

Masalah dengan cara ini adalah pada ukuran layar tertentu akan ada celah di sebelah kanan ul, sehingga tidak lagi tampak di tengah.

masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

Ini terjadi karena dalam tata letak fleksibel (dan, sebenarnya, CSS secara umum) penampung:

  1. tidak tahu kapan sebuah elemen terbungkus;
  2. tidak tahu bahwa ruang yang sebelumnya ditempati sekarang kosong, dan
  3. tidak menghitung ulang lebarnya untuk mengecilkan tata letak yang lebih sempit.

Panjang maksimum whitespace di sebelah kanan adalah panjang item flex yang diharapkan container berada di sana.

Dalam demo berikut, dengan mengubah ukuran jendela secara horizontal, Anda dapat melihat whitespace datang dan pergi.

DEMO


Pendekatan yang Lebih Praktis

Tata letak yang diinginkan dapat dicapai tanpa penggunaan flexbox inline-blockdan kueri media .

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; } }

Kode di atas merender wadah yang berada di tengah horizontal dengan elemen anak rata kiri seperti ini:

masukkan deskripsi gambar di sini

DEMO


Pilihan lain

Michael Benjamin
sumber
3
Ya, banyak hal yang ingin dilakukan orang dan akhirnya menggunakan flexbox sebenarnya hanyalah membuat kisi. Untungnya ini akan dicakup oleh CSS Grids ketika jangkauan itu adalah status yang lebih final.
TylerH
1
Menautkan postingan ini ke postingan Anda. Saya punya satu versi lagi di sana bagaimana menyelesaikan masalah yang sama, tetap saja, itu mungkin penipuan, jadi lihat dan putuskan sendiri apakah Anda ingin menutupnya seperti itu. Dan ditambah 1 untuk penjelasan hebat dalam hal ini.
Ason
Mungkin ide lain adalah melakukannya margin:0 autopada pembungkus induk, sehingga semuanya berada di tengah halaman. Dari titik itu, semua komponen anak, (yaitu wadah-fleksibel pertama) hanya menjalankan proses baris aliran normal? Sepertinya ini bisa dibuat sederhana untuk dilakukan.
klewis
12

Anda dapat mencapainya dengan CSS Grid, cukup gunakan 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/

Joe82
sumber
Menarik. Tapi tidak menghilangkan celah di kanan atau tengah grid
Merah
2
@Red Ada satu hal yang salah. Saya berubah justify-items: centermenjadi justify-content:center, dan sekarang pusatnya sempurna.
Joe82
Saya tidak mengerti 210pxbagian di dalamnya minmax. Bagaimana saya melakukan hal yang sama tetapi tanpa batasan buatan 210px? Tidak ada batasan seperti itu dengan flexbox. Saya ingin hasil yang persis sama dengan flexbox, tetapi area konten harus dipusatkan seperti dalam solusi Anda.
Andrey Mikhaylov - lolmaus
1
Hai @ AndreyMikhaylov-lolmaus, metode ini berfungsi saat Anda ingin menyetel lebar tetap ke semua elemen. Dalam pertanyaan, itu dinyatakan sebagai width:200px, dan dalam contoh saya, seperti yang saya tetapkan width:210px, saya harus menambahkannya juga di minmaxbagian
Joe82
@ Joe82 Terima kasih telah menjelaskan! 🙏 Apakah Anda tahu cara membuatnya berfungsi untuk elemen lebar sembarang?
Andrey Mikhaylov - lolmaus
0

Seperti yang disarankan @michael, ini adalah batasan dengan flexbox saat ini. Tetapi jika Anda ingin tetap menggunakan flexand justify-content: center;, maka kita dapat mengatasinya dengan menambahkan lielemen dummy dan menetapkan 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); 

Periksa biola ini (ubah ukuran dan lihat) atau video untuk referensi

RameshVel
sumber
0

Salah satu cara untuk mendapatkan gaya yang diinginkan dengan margin adalah dengan melakukan hal berikut:

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

#innercontainer {
    display: flex;
    flex: 0.9; -> add desired % of margin
    justify-content: flex-start;
}
Patrik Rikama-Hinnenberg
sumber
0

Anda dapat menempatkan elemen tak terlihat dengan kelas yang sama dengan yang lain (dihapus pada contoh untuk tujuan pameran) dan ketinggian disetel ke 0. Dengan itu, Anda akan dapat membenarkan item ke awal kisi.

Contoh

<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>

Hasil

masukkan deskripsi gambar di sini

Arthur Serafim
sumber
-1

Saya mengalami masalah ini saat melakukan coding dengan React Native. Ada solusi elegan yang dapat Anda miliki dengan menggunakan FlexBox. Dalam situasi khusus saya, saya mencoba untuk memusatkan tiga kotak fleksibel (Flex: 2) di dalam yang lain menggunakan alignItems. Solusi yang saya dapatkan adalah menggunakan dua kosong, masing-masing dengan Flex: 1.

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

Cukup mudah untuk dikonversi ke web / CSS.

FontFamily
sumber
Anda salah paham dengan pertanyaan itu. OP tidak menanyakan cara memusatkan 3 item, mereka menanyakan cara meratakan kiri item pada baris ke-2 sementara semua item dipusatkan sebagai grup, dan untuk itu solusi Anda tidak berfungsi.
Ason