Giữ mục giữa ở giữa khi các mục bên có chiều rộng khác nhau


161

nhập mô tả hình ảnh ở đây

Hãy tưởng tượng bố cục sau đây, trong đó các dấu chấm đại diện cho không gian giữa các hộp:

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

Khi tôi bỏ hộp bên phải, tôi thích hộp trung tâm vẫn ở giữa, như vậy:

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

Điều tương tự cũng xảy ra nếu tôi loại bỏ hộp bên trái.

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

Bây giờ khi nội dung trong hộp trung tâm dài hơn, nó sẽ chiếm nhiều không gian có sẵn khi cần trong khi vẫn ở giữa. Hộp bên trái và bên phải sẽ không bao giờ co lại và do đó khi không còn chỗ trống overflow:hiddentext-overflow: ellipsissẽ có hiệu lực để phá vỡ nội dung;

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

Tất cả những điều trên là tình huống lý tưởng của tôi, nhưng tôi không biết làm thế nào để thực hiện được hiệu ứng này. Bởi vì khi tôi tạo một cấu trúc flex như vậy:

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

Nếu hộp bên trái và bên phải có cùng kích thước, tôi sẽ có được hiệu ứng mong muốn. Tuy nhiên, khi một trong hai từ một kích thước khác, hộp trung tâm không thực sự được căn giữa nữa.

Có ai có thể giúp tôi không?

Cập nhật

A justify-selfsẽ tốt đẹp, điều này sẽ là lý tưởng:

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

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

3
Về cơ bản ... bạn không thể. Đó không phải flexboxlà cách làm việc. Bạn có thể thử phương pháp khác.
Paulie_D

1
Sẽ thực sự hoàn thành flexbox nếu nó đã tho. Nguyên nhân flexbox là tất cả về phân phối không gian và cách các mục hoạt động trong.
Đánh dấu

1
Chúng tôi đã thảo luận justify-selfsớm hơn ngày hôm nay, vì vậy bạn có thể thấy điều này thú vị: stackoverflow.com/questions/32551291/ Khăn
Michael Benjamin

Câu trả lời:


130

Nếu hộp bên trái và bên phải có cùng kích thước, tôi sẽ có được hiệu ứng mong muốn. Tuy nhiên, khi một trong hai kích thước khác nhau, hộp trung tâm không thực sự được căn giữa nữa. Có ai có thể giúp tôi không?

Đây là một phương pháp sử dụng flexbox để căn giữa mục giữa, bất kể chiều rộng của anh chị em.

Các tính năng chính:

  • CSS thuần
  • không có định vị tuyệt đối
  • không có JS / jQuery

Sử dụng các thùng chứa flex và autolề:

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

Đây là cách nó hoạt động:

  • Div cấp cao nhất ( .container) là một thùng chứa flex.
  • Mỗi div div ( .box) bây giờ là một mục flex.
  • Mỗi .boxmục được đưa flex: 1ra để phân phối không gian chứa bằng nhau ( chi tiết hơn ).
  • Bây giờ các mục đang tiêu thụ tất cả không gian trong hàng và có chiều rộng bằng nhau.
  • Làm cho mỗi mục một thùng chứa flex (lồng nhau) và thêm justify-content: center.
  • Bây giờ mỗi spanphần tử là một mục flex trung tâm.
  • Sử dụng autolề flex để dịch chuyển spans bên trái và bên phải.

Bạn cũng có thể từ bỏ justify-contentvà sử dụng autolợi nhuận độc quyền.

Nhưng justify-contentcó thể làm việc ở đây vì autolợi nhuận luôn được ưu tiên.

8.1. Căn chỉnh với auto lề

Trước khi căn chỉnh thông qua justify-contentalign-self, bất kỳ không gian trống tích cực nào cũng được phân phối cho lề tự động theo chiều đó.


5
Giải pháp này không cho phép widthđược chỉ định
Alex G

@AlexG, làm sao vậy? bạn có thể cung cấp một ví dụ?
Michael Benjamin

4
Thay đổi độ rộng của các phần tử uốn cong để phân phối không gian hoàn toàn bỏ lỡ câu hỏi của OP. Câu hỏi của họ có không gian giữa các yếu tố. Ví dụ: "Hãy tưởng tượng bố cục sau, trong đó các dấu chấm đại diện cho không gian giữa các hộp." Trung tâm văn bản trong 3 yếu tố kích thước đồng đều là tầm thường.
Leland

1
Tôi thề tôi có thể hôn bạn ngay bây giờ! Đây chính xác là những gì tôi cần và không thể tìm ra.
eliotRosewater

1
Điều này đã làm chính xác những gì tôi cần để thực hiện các tiêu đề cửa sổ kiểu MacOS. Thêm white-space: nowraplà phần cuối cùng của câu đố để ngăn văn bản gói lại khi diện tích quá nhỏ.
Geo1088

32
  1. Sử dụng ba vật phẩm flex trong container
  2. Đặt flex: 1thành cái đầu tiên và cuối cùng. Điều này làm cho chúng phát triển như nhau để lấp đầy không gian có sẵn ở giữa.
  3. Vì vậy, một ở giữa sẽ có xu hướng được tập trung.
  4. Tuy nhiên, nếu mục đầu tiên hoặc cuối cùng có nội dung rộng, mục flex đó cũng sẽ phát triển do min-width: autogiá trị ban đầu mới .

    Lưu ý Chrome dường như không thực hiện đúng cách này. Tuy nhiên, bạn có thể đặt min-widththành -webkit-max-contenthoặc -webkit-min-contentnó cũng hoạt động.

  5. Chỉ trong trường hợp đó, phần tử ở giữa sẽ bị đẩy ra khỏi trung tâm.

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


Cảm ơn, câu trả lời này trả lời thành công câu hỏi của OP, không giống như câu trả lời được chấp nhận
Blowsie

8

Thay vì mặc định sử dụng flexbox, sử dụng lưới sẽ giải quyết nó trong 2 dòng CSS mà không cần đánh dấu bổ sung bên trong các con cấp cao nhất.

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 nhưng không nên là câu trả lời cho tất cả mọi thứ. Trong trường hợp này lưới rõ ràng là lựa chọn sạch nhất.

Thậm chí đã tạo một codepen cho niềm vui thử nghiệm của bạn: https://codepen.io/anon/pen/mooQOV


2
+1 để thừa nhận rằng có thể có các tùy chọn khác ngoài flexmọi thứ. Phản đối duy nhất của tôi là căn chỉnh dọc trở nên dễ dàng hơn khi sử dụng flex ( align-items: center) trong trường hợp các mục của bạn có chiều cao khác nhau và cần được căn chỉnh
Felipe

1
Tôi thích giải pháp này và ý tưởng sử dụng lưới cho vấn đề này, nhưng tôi nghĩ giải pháp của bạn có một số nhược điểm đáng chú ý. Đầu tiên, nếu một trong hai nội dung của các ô bên ngoài lớn hơn 20%, thì nội dung sẽ được bọc hoặc tràn vào ô trung tâm. Thứ hai, nếu trung tâm lớn hơn 60%, nó sẽ phát triển bên ngoài hộp nội dung của nó và bọc hoặc đẩy ô cuối cùng ra. Cuối cùng, trung tâm không dịch chuyển để nhường chỗ cho các tế bào bên ngoài. Nó chỉ buộc họ phải bọc / tràn. Đó không phải là một giải pháp tồi, nhưng IMO, nó không "rõ ràng là lựa chọn sạch nhất".
Chris

6

Bạn có thể làm điều này như vậy:

.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

Đây là một câu trả lời sử dụng lưới thay vì flexbox. Giải pháp này không yêu cầu thêm các yếu tố cháu trong HTML như câu trả lời được chấp nhận. Và nó hoạt động chính xác ngay cả khi nội dung ở một bên đủ dài để tràn vào trung tâm, không giống như câu trả lời lưới từ năm 2019.

Điều duy nhất mà giải pháp này không làm là hiển thị dấu chấm lửng hoặc ẩn nội dung bổ sung trong hộp trung tâm, như được mô tả trong câu hỏi.

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>


0

bạn cũng có thể sử dụng cách đơn giản này để đạt được căn chỉnh trung tâm chính xác cho phần tử ở giữa:

.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


0

Đây là một cách khác để làm điều đó, sử dụng display: flextrong cha mẹ và trẻ em:

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.