ทำให้รายการกลางอยู่ตรงกลางเมื่อรายการด้านข้างมีความกว้างต่างกัน


162

ป้อนคำอธิบายรูปภาพที่นี่

ลองนึกภาพเลย์เอาต์ต่อไปนี้โดยที่จุดแสดงถึงช่องว่างระหว่างกล่อง

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

เมื่อฉันลบกล่องขวาฉันชอบกล่องตรงกลางที่จะยังคงอยู่ในศูนย์เช่น:

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

สิ่งเดียวกันจะเกิดขึ้นหากฉันจะลบกล่องด้านซ้าย

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

ตอนนี้เมื่อเนื้อหาภายในกล่องกลางยาวขึ้นมันจะใช้พื้นที่มากเท่าที่จำเป็นในขณะที่เหลืออยู่กึ่งกลาง กล่องด้านซ้ายและขวาจะไม่ย่อขนาดดังนั้นเมื่อไม่มีที่ว่างเหลืออยู่overflow:hiddenและtext-overflow: ellipsisจะมีผลในการทำลายเนื้อหา

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

ทั้งหมดข้างต้นเป็นสถานการณ์ในอุดมคติของฉัน แต่ฉันไม่รู้ว่าจะทำสิ่งนี้ได้อย่างไร เพราะเมื่อฉันสร้างโครงสร้างแบบยืดหยุ่นเช่นนั้น:

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

ถ้ากล่องซ้ายและขวามีขนาดเท่ากันฉันจะได้เอฟเฟกต์ที่ต้องการ อย่างไรก็ตามเมื่อหนึ่งในสองนั้นมาจากขนาดที่แตกต่างกันกล่องที่อยู่ตรงกลางไม่ได้อยู่กึ่งกลางอีกต่อไปอย่างแท้จริง

มีใครบ้างที่สามารถช่วยฉันได้บ้าง

ปรับปรุง

A justify-selfจะดีนี่จะเหมาะ:

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

.rightBox {
    justify-self : flex-end;
}

3
โดยทั่วไป ... คุณทำไม่ได้ นั่นไม่ใช่วิธีที่flexboxควรจะทำงาน คุณอาจลองวิธีการอื่น
Paulie_D

1
จะทำเฟล็กบ็อกซ์ให้เสร็จสมบูรณ์ถ้าทำไปได้ สาเหตุ flexbox ทั้งหมดเกี่ยวกับการกระจายพื้นที่และวิธีการทำงานของรายการภายใน
ทำเครื่องหมาย

1
เราได้พูดคุยกันjustify-selfก่อนหน้านี้วันนี้ดังนั้นคุณอาจพบว่าสิ่งนี้น่าสนใจ: stackoverflow.com/questions/32551291/…
Michael Benjamin

คำตอบ:


130

ถ้ากล่องซ้ายและขวามีขนาดเท่ากันทั้งหมดฉันจะได้เอฟเฟกต์ที่ต้องการ อย่างไรก็ตามเมื่อหนึ่งในสองมีขนาดแตกต่างกันกล่องกึ่งกลางไม่ได้อยู่กึ่งกลางจริงอีกต่อไป มีใครบ้างที่สามารถช่วยฉันได้บ้าง

นี่คือวิธีการใช้ flexbox เพื่อจัดกึ่งกลางของรายการโดยไม่คำนึงถึงความกว้างของพี่น้อง

คุณสมบัติหลัก:

  • CSS บริสุทธิ์
  • ไม่มีตำแหน่งแน่นอน
  • ไม่มี JS / jQuery

ใช้เฟล็กซ์เฟล็กซ์และautoระยะขอบ:

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

นี่คือวิธีการทำงาน:

  • div ( .container) ระดับบนสุดเป็นคอนเทนเนอร์แบบยืดหยุ่น
  • div ลูก ( .box) แต่ละอันในขณะนี้เป็นรายการที่ยืดหยุ่น
  • แต่ละ.boxรายการจะได้รับflex: 1เพื่อแจกจ่ายพื้นที่เก็บอย่างเท่าเทียมกัน ( รายละเอียดเพิ่มเติม )
  • ตอนนี้ไอเท็มกำลังกินพื้นที่ทั้งหมดในแถวและมีความกว้างเท่ากัน
  • ทำให้รายการแต่ละ (ซ้อน) justify-content: centerภาชนะดิ้นและเพิ่ม
  • ตอนนี้แต่ละspanองค์ประกอบจะเป็นรายการเฟล็กซ์กึ่งกลาง
  • ใช้autoระยะขอบโค้งงอเพื่อเลื่อนด้านนอกspanซ้ายและขวา

คุณสามารถละทิ้งjustify-contentและใช้autoระยะขอบได้โดยเฉพาะ

แต่justify-contentสามารถทำงานที่นี่ได้เพราะautoระยะขอบมีลำดับความสำคัญเสมอ

8.1 สอดคล้องกับauto ระยะขอบ

ก่อนที่จะจัดแนวผ่านjustify-contentและalign-selfพื้นที่ว่างบวกใด ๆ จะถูกกระจายไปยังระยะขอบอัตโนมัติในมิตินั้น


5
โซลูชันนี้ไม่อนุญาตให้widthมีการระบุ
Alex G

@AlexG เป็นอย่างไร คุณสามารถยกตัวอย่างได้หรือไม่?
Michael Benjamin

4
การเปลี่ยนความกว้างขององค์ประกอบที่ยืดหยุ่นเพื่อกระจายพื้นที่อย่างเท่าเทียมกันคิดถึงคำถามของ OP ทั้งหมด คำถามของพวกเขามีช่องว่างระหว่างองค์ประกอบ ตัวอย่าง: "ลองนึกภาพเลย์เอาต์ต่อไปนี้ซึ่งจุดต่างๆแสดงช่องว่างระหว่างกล่อง" การจัดกึ่งกลางข้อความในองค์ประกอบที่มีขนาดเท่ากัน 3 รายการเป็นเรื่องเล็กน้อย
Leland

1
ฉันสาบานว่าฉันจะจูบคุณได้แล้วตอนนี้! นี่คือสิ่งที่ฉันต้องการและไม่สามารถเข้าใจได้
eliotRosewater

1
นี่เป็นสิ่งที่ฉันต้องการสำหรับการนำแถบหัวเรื่องหน้าต่างแบบ MacOS มาใช้ การเพิ่มwhite-space: nowrapเป็นชิ้นส่วนสุดท้ายของจิ๊กซอว์เพื่อป้องกันข้อความจากการตัดเมื่อพื้นที่มีขนาดเล็กเกินไป
Geo1088

32
  1. ใช้สามรายการที่ยืดหยุ่นในภาชนะ
  2. ตั้งค่าflex: 1เป็นตัวแรกและตัวสุดท้าย สิ่งนี้ทำให้พวกเขาเติบโตอย่างเท่าเทียมกันเพื่อเติมเต็มพื้นที่ว่างที่เหลืออยู่ตรงกลาง
  3. ดังนั้นตรงกลางจะมีแนวโน้มที่จะเป็นศูนย์กลาง
  4. อย่างไรก็ตามหากรายการแรกหรือรายการสุดท้ายมีเนื้อหากว้างรายการดิ้นนั้นก็จะโตขึ้นเนื่องจากmin-width: autoค่าเริ่มต้นใหม่

    หมายเหตุ Chrome ดูเหมือนจะใช้งานไม่ถูกต้อง อย่างไรก็ตามคุณสามารถตั้งค่าmin-widthเป็น-webkit-max-contentหรือ-webkit-min-contentไม่ก็ได้

  5. เฉพาะในกรณีนั้นองค์ประกอบกลางจะถูกผลักออกจากศูนย์

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


ขอบคุณคำตอบนี้ตอบคำถาม
OPs ได้

8

แทนที่จะใช้การตั้งค่าเริ่มต้นเพื่อใช้ flexbox การใช้กริดจะแก้ไขมันใน 2 บรรทัดของ CSS โดยไม่ต้องมาร์กอัปเพิ่มเติมภายในลูกระดับบนสุด

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 เขย่าวงการ แต่ไม่ควรเป็นคำตอบสำหรับทุกสิ่ง ในกรณีนี้กริดเป็นตัวเลือกที่ชัดเจนที่สุด

แม้แต่ทำ codepen เพื่อความสุขในการทดสอบของคุณ: https://codepen.io/anon/pen/mooQOV


2
+1 สำหรับการยอมรับว่าอาจมีตัวเลือกอื่นนอกเหนือจากflexทุกอย่าง ข้อคัดค้านเพียงอย่างเดียวของฉันคือการจัดตำแหน่งแนวตั้งจะง่ายขึ้นโดยใช้ flex ( align-items: center) ในกรณีที่รายการของคุณมีความสูงแตกต่างกันและจำเป็นต้องจัดตำแหน่ง
Felipe

1
ฉันชอบโซลูชันนี้และแนวคิดในการใช้กริดสำหรับปัญหานี้ แต่ฉันคิดว่าโซลูชันของคุณมีข้อบกพร่องที่น่าทึ่ง ขั้นแรกหากเนื้อหาด้านนอกของเซลล์ใดอันหนึ่งมีขนาดใหญ่กว่า 20% เนื้อหานั้นจะทำการตัดหรือล้นลงในเซลล์กึ่งกลาง ประการที่สองหากศูนย์ใหญ่กว่า 60% ก็จะเติบโตนอกกรอบเนื้อหาและห่อหรือผลักเซลล์สุดท้ายออก ในที่สุดศูนย์ไม่เปลี่ยนเพื่อให้มีที่ว่างสำหรับเซลล์ชั้นนอก มันเพียงแค่บังคับให้พวกเขาห่อ / ล้น มันไม่ใช่ทางออกที่ดี แต่ IMO ไม่ใช่ "ตัวเลือกที่ชัดเจนที่สุด"
Chris

6

คุณสามารถทำเช่นนี้เพื่อ:

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


2

นี่คือคำตอบที่ใช้กริดแทน flexbox วิธีนี้ไม่จำเป็นต้องใช้องค์ประกอบของหลานพิเศษใน HTML เหมือนกับคำตอบที่ยอมรับ และทำงานได้อย่างถูกต้องแม้ว่าเนื้อหาในด้านใดด้านหนึ่งจะยาวพอที่จะไหลล้นตรงกลางซึ่งแตกต่างจากคำตอบกริดจาก 2019

สิ่งหนึ่งที่โซลูชันนี้ไม่ทำคือแสดงจุดไข่ปลาหรือซ่อนเนื้อหาเพิ่มเติมในกล่องกึ่งกลางดังที่อธิบายไว้ในคำถาม

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>


1

นี่เป็นอีกวิธีในการทำโดยใช้display: flexในผู้ปกครองและลูก:

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


0

คุณยังสามารถใช้วิธีง่ายๆในการเข้าถึงการจัดตำแหน่งกึ่งกลางที่แน่นอนสำหรับองค์ประกอบกลาง:

.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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.