Pertahankan item tengah di tengah saat item samping memiliki lebar berbeda

162

masukkan deskripsi gambar di sini

Bayangkan tata letak berikut, di mana titik-titik mewakili ruang di antara kotak-kotak:

[Left box]......[Center box]......[Right box]

Ketika saya menghapus kotak kanan, saya suka kotak tengah untuk tetap berada di tengah, seperti:

[Left box]......[Center box].................

Hal yang sama berlaku jika saya akan menghapus kotak kiri.

................[Center box].................

Sekarang ketika konten di dalam kotak tengah menjadi lebih lama, itu akan memakan ruang sebanyak yang dibutuhkan saat tetap berada di tengah. Kotak kiri dan kanan tidak akan pernah menyusut dan karena itu ketika tidak ada ruang tersisa overflow:hiddendan text-overflow: ellipsisakan berlaku untuk menghancurkan konten;

[Left box][Center boxxxxxxxxxxxxx][Right box]

Semua hal di atas adalah situasi ideal saya, tetapi saya tidak tahu bagaimana menyelesaikan efek ini. Karena ketika saya membuat struktur fleksibel seperti:

.parent {
    display : flex; // flex box
    justify-content : space-between; // horizontal alignment
    align-content   : center; // vertical alignment
}

Jika kotak kiri dan kanan berukuran persis sama, saya mendapatkan efek yang diinginkan. Namun ketika salah satu dari keduanya berasal dari ukuran yang berbeda kotak terpusat tidak benar-benar terpusat lagi.

Adakah yang bisa membantu saya?

Memperbarui

A justify-selfakan menyenangkan, ini akan ideal:

.leftBox {
     justify-self : flex-start;
}

.rightBox {
    justify-self : flex-end;
}
Menandai
sumber
3
Pada dasarnya ... kamu tidak bisa. flexboxSeharusnya bukan itu cara kerjanya. Anda dapat mencoba metodologi lain.
Paulie_D
1
Akan benar-benar menyelesaikan flexbox jika berhasil. Penyebab flexbox adalah tentang mendistribusikan ruang dan bagaimana item berperilaku di dalamnya.
Tandai
1
Kita bahas justify-selfsebelumnya hari ini, jadi Anda mungkin menemukan ini menarik: stackoverflow.com/questions/32551291/…
Michael Benjamin

Jawaban:

130

Jika kotak kiri dan kanan berukuran persis sama, saya mendapatkan efek yang diinginkan. Namun ketika salah satu dari keduanya berukuran berbeda, kotak tengah tidak benar-benar terpusat lagi. Adakah yang bisa membantu saya?

Berikut adalah metode menggunakan flexbox untuk memusatkan item tengah, terlepas dari lebar saudara kandung.

Fitur utama:

  • CSS murni
  • tidak ada penentuan posisi absolut
  • tidak ada JS / jQuery

Gunakan wadah dan automargin fleksibel bersarang :

.container {
  display: flex;
}
.box {
  flex: 1;
  display: flex;
  justify-content: center;
}

.box:first-child > span { margin-right: auto; }

.box:last-child  > span { margin-left: auto;  }

/* non-essential */
.box {
  align-items: center;
  border: 1px solid #ccc;
  background-color: lightgreen;
  height: 40px;
}
p {
  text-align: center;
  margin: 5px 0 0 0;
}
<div class="container">
  <div class="box"><span>short text</span></div>
  <div class="box"><span>centered text</span></div>
  <div class="box"><span>loooooooooooooooong text</span></div>
</div>
<p>&#8593;<br>true center</p>

Begini cara kerjanya:

  • Div tingkat atas ( .container) adalah wadah fleksibel.
  • Setiap div anak ( .box) sekarang menjadi item fleksibel.
  • Setiap .boxitem diberikan flex: 1untuk mendistribusikan ruang kontainer secara merata ( lebih detail ).
  • Sekarang item mengkonsumsi semua ruang di baris dan lebarnya sama.
  • Jadikan setiap item sebagai wadah fleksibel (bersarang) dan tambahkan justify-content: center.
  • Sekarang setiap spanelemen adalah item flex terpusat.
  • Gunakan automargin fleksibel untuk menggeser bagian luar spankiri dan kanan.

Anda juga bisa melupakan justify-contentdan menggunakan automargin secara eksklusif.

Tetapi justify-contentdapat bekerja di sini karena automargin selalu mendapat prioritas.

8.1. Menyelaraskan dengan auto margin

Sebelum penyelarasan melalui justify-contentdan align-self, setiap ruang bebas positif didistribusikan ke margin otomatis di dimensi itu.

Michael Benjamin
sumber
5
Solusi ini tidak memungkinkan widthuntuk ditentukan
Alex G
@AlexG, bagaimana bisa begitu? Bisakah Anda memberikan contoh?
Michael Benjamin
4
Mengubah lebar elemen yang ditekuk untuk mendistribusikan ruang secara merata melewatkan pertanyaan OP sepenuhnya. Pertanyaan mereka memiliki ruang antar elemen. Contoh: "Bayangkan tata letak berikut, di mana titik-titik mewakili ruang di antara kotak-kotak." Memusatkan teks dalam 3 elemen berukuran sama adalah sepele.
Leland
1
Aku bersumpah aku bisa menciummu sekarang juga! Ini persis apa yang saya butuhkan dan tidak tahu.
eliotRosewater
1
Ini melakukan persis apa yang saya butuhkan untuk menerapkan tajuk jendela gaya MacOS. Menambahkan white-space: nowrapadalah bagian terakhir dari teka-teki untuk mencegah pembungkus teks saat area menjadi terlalu kecil.
Geo1088
32
  1. Gunakan tiga item fleksibel dalam wadah
  2. Atur flex: 1ke yang pertama dan terakhir. Ini membuat mereka tumbuh sama rata untuk mengisi ruang yang tersedia di tengah.
  3. Dengan demikian, yang di tengah akan cenderung terpusat.
  4. Namun, jika item pertama atau terakhir memiliki konten yang luas, item flex itu juga akan tumbuh karena min-width: autonilai awal yang baru .

    Catatan Chrome tampaknya tidak menerapkan ini dengan benar. Namun, Anda dapat mengatur min-widthke -webkit-max-contentatau -webkit-min-contentdan itu akan berhasil juga.

  5. Hanya dalam kasus itu elemen tengah akan didorong keluar dari tengah.

.outer-wrapper {
  display: flex;
}
.item {
  background: lime;
  margin: 5px;
}
.left.inner-wrapper, .right.inner-wrapper {
  flex: 1;
  display: flex;
  min-width: -webkit-min-content; /* Workaround to Chrome bug */
}
.right.inner-wrapper {
  justify-content: flex-end;
}
.animate {
  animation: anim 5s infinite alternate;
}
@keyframes anim {
  from { min-width: 0 }
  to { min-width: 100vw; }
}
<div class="outer-wrapper">
  <div class="left inner-wrapper">
    <div class="item animate">Left</div>
  </div>
  <div class="center inner-wrapper">
    <div class="item">Center</div>
  </div>
  <div class="right inner-wrapper">
    <div class="item">Right</div>
  </div>
</div>
<!-- Analogous to above --> <div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">Left</div></div><div class="center inner-wrapper"><div class="item animate">Center</div></div><div class="right inner-wrapper"><div class="item">Right</div></div></div><div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">Left</div></div><div class="center inner-wrapper"><div class="item">Center</div></div><div class="right inner-wrapper"><div class="item animate">Right</div></div></div>

Oriol
sumber
Terima kasih, jawaban ini berhasil menjawab pertanyaan OP, tidak seperti jawaban yang diterima
Blowsie
8

Alih-alih default menggunakan flexbox, menggunakan grid memecahkannya dalam 2 baris CSS tanpa markup tambahan di dalam anak-anak tingkat atas.

HTML:

<header class="header">
  <div class="left">variable content</div>
  <div class="middle">variable content</div>
  <div class="right">variable content which happens to be very long</div>
</header>

CSS:

.header {
  display: grid;
  grid-template-columns: [first] 20% auto [last] 20%;
}
.middle {
  /* use either */
  margin: 0 auto;
  /* or */
  text-align: center;
}

Flexbox mengguncang tetapi seharusnya tidak menjadi jawaban untuk semuanya. Dalam hal ini kisi jelas merupakan pilihan terbersih.

Bahkan membuat codepen untuk kesenangan pengujian Anda: https://codepen.io/anon/pen/mooQOV

Johan
sumber
2
+1 untuk mengakui bahwa mungkin ada opsi lain selain flexuntuk semuanya. Satu-satunya keberatan saya adalah penyelarasan vertikal menjadi lebih mudah menggunakan flex ( align-items: center) jika item Anda berbeda ketinggian dan perlu disejajarkan
Felipe
1
Saya suka solusi ini dan gagasan menggunakan grid untuk masalah ini, tapi saya pikir solusi Anda memiliki beberapa kelemahan. Pertama, jika salah satu dari isi sel luar lebih besar dari 20%, isinya akan membungkus atau meluap ke sel pusat. Kedua, jika pusat lebih besar dari 60%, itu akan tumbuh di luar kotak isinya dan membungkus atau mendorong sel terakhir keluar. Akhirnya, pusat tidak bergeser untuk memberi ruang bagi sel-sel luar. Itu hanya memaksa mereka untuk membungkus / meluap. Ini bukan solusi yang buruk, tetapi IMO, itu bukan "jelas opsi terbersih".
Chris
6

Anda dapat melakukan ini seperti ini:

.bar {
    display: flex;    
    background: #B0BEC5;
}
.l {
    width: 50%;
    flex-shrink: 1;
    display: flex;
}
.l-content {
    background: #9C27B0;
}
.m { 
    flex-shrink: 0;
}
.m-content {    
    text-align: center;
    background: #2196F3;
}
.r {
    width: 50%;
    flex-shrink: 1;
    display: flex;
    flex-direction: row-reverse;
}
.r-content { 
    background: #E91E63;
}
<div class="bar">
    <div class="l">
        <div class="l-content">This is really long content.  More content.  So much content.</div>
    </div>
    <div class="m">
        <div class="m-content">This will always be in the center.</div>
    </div>
    <div class="r">
        <div class="r-content">This is short.</div>
    </div>
</div>

Michael Morton
sumber
2

Inilah jawaban yang menggunakan kisi bukan flexbox. Solusi ini tidak memerlukan elemen cucu ekstra dalam HTML seperti jawaban yang diterima. Dan itu berfungsi dengan benar bahkan ketika konten di satu sisi cukup lama untuk meluap ke tengah, tidak seperti jawaban grid dari 2019.

Satu hal yang tidak dilakukan solusi ini adalah menampilkan elipsis atau menyembunyikan konten tambahan di kotak tengah, seperti yang dijelaskan dalam pertanyaan.

section {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
}

section > *:last-child {
  white-space: nowrap;
  text-align: right;
}

/* not essential; just for demo purposes */
section {
  background-color: #eee;
  font-family: helvetica, arial;
  font-size: 10pt;
  padding: 4px;
}

section > * {
  border: 1px solid #bbb;
  padding: 2px;
}
<section>
  <div>left</div>
  <div>center</div>
  <div>right side is longer</div>
</section>

<section>
  <div>left</div>
  <div>center</div>
  <div>right side is much, much longer</div>
</section>

<section>
  <div>left</div>
  <div>center</div>
  <div>right side is much, much longer, super long in fact</div>
</section>

Brian Morearty
sumber
1

Berikut cara lain untuk melakukannya, menggunakan display: flexpada orang tua dan anak-anak:

.Layout{
    display: flex;
    justify-content: center;
}
.Left{
    display: flex;
    justify-content: flex-start;
    width: 100%;
}
.Right{
    display: flex;
    justify-content: flex-end;
    width: 100%;
}
<div class = 'Layout'>
    <div class = 'Left'>I'm on the left</div>
    <div class = 'Mid'>Centered</div>
    <div class = 'Right'>I'm on the right</div>
</div>

Erik Martín Jordán
sumber
0

Anda juga dapat menggunakan cara sederhana ini untuk mencapai perataan tengah tepat untuk elemen tengah:

.container {
    display: flex;
    justify-content: space-between;
}

.container .sibling {
    display: flex;
    align-items: center;
    height: 50px;
    background-color: gray;
}

.container .sibling:first-child {
    width: 50%;
    display: flex;
    justify-content: space-between;
}

.container .sibling:last-child {
    justify-content: flex-end;
    width: 50%;
    box-sizing: border-box;
    padding-left: 100px; /* .center's width divided by 2 */
}

.container .sibling:last-child .content {
    text-align: right;
}

.container .sibling .center {
    height: 100%;
    width: 200px;
    background-color: lightgreen;
    transform: translateX(50%);
}

codepen: https://codepen.io/ErAz7/pen/mdeBKLG

Erfan Azary
sumber