Тримайте середній елемент у центрі, коли бічні елементи мають різну ширину


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
}

Якщо лівий і правий ящик були б точно однакового розміру, я отримую потрібний ефект. Однак, коли один з двох розмірів з іншим розміром, центрированная коробка вже не по-справжньому зосереджена.

Хтось може мені допомогти?

Оновлення

А justify-selfбуло б добре, це було б ідеально:

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

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

3
В основному ... ти не можеш. Це не так, як flexboxмає працювати. Ви можете спробувати іншу методологію.
Paulie_D

1
Дійсно завершити flexbox, якби це зробило тхо. Причина flexbox - це все про розподіл простору та про те, як предмети ведуть себе всередині.
Марк

1
Ми обговорювали justify-selfраніше сьогодні, тож вам може бути цікаво: stackoverflow.com/questions/32551291/…
Michael Benjamin

Відповіді:


130

Якщо лівий і правий поля були б точно однакового розміру, я отримую бажаний ефект. Однак, коли одна з двох відрізняється розміром, центрированная коробка вже не по-справжньому зосереджена. Хтось може мені допомогти?

Ось метод, який використовує флексбокс для центру середнього елемента, незалежно від ширини братів і сестер.

Ключові риси:

  • чистий 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поля для зміщення зовнішніх spans вліво та вправо.

Ви також можете відмовитися justify-contentі використовувати autoвиключно маржі.

Але justify-contentтут можна працювати, оскільки autoпріоритет завжди має пріоритет.

8.1. Вирівнювання з auto маржами

Перед вирівнюванням через justify-contentта align-selfбудь-який позитивний вільний простір розподіляється на автоматичні поля в цьому вимірі.


5
Це рішення не дозволяє widthвказувати
Alex G

@ Алекс, як так? Чи можете ви навести приклад?
Майкл Бенджамін

4
Зміна ширини гнучких елементів для розподілу простору повністю відсутнє питання ОП. У їхньому питанні є простір між елементами. Наприклад: "Уявіть наступний макет, де крапки представляють пробіл між полями." Текст центрування в 3 елементах рівномірного розміру є тривіальним.
Леланд

1
Клянусь, я міг би просто поцілувати тебе зараз! Це саме те, що мені було потрібно і я не міг зрозуміти.
eliotRosewater

1
Це було саме те, що мені потрібно для реалізації заголовків вікон у стилі MacOS. Додавання white-space: nowrapбуло останньою частиною головоломки, щоб запобігти загортанню тексту, коли область стає занадто маленькою.
Гео1088

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>


Дякую, ця відповідь успішно відповідає на питання ОП, на відміну від прийнятої відповіді
Blowsie

8

Замість того, щоб дефолтом було використання флексокса, використання сітки вирішує його у 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 гойдає, але не повинен бути відповіддю на все. У цьому випадку сітка - це явно найчистіший варіант.

Навіть зробили кодек для задоволення від тестування: https://codepen.io/anon/pen/mooQOV


2
+1 за визнання, що можуть бути інші варіанти, ніж flexдля всього. Єдине заперечення - вертикальне вирівнювання стає простішим за допомогою flex ( align-items: center) у випадку, якщо ваші предмети мають різну висоту та їх потрібно вирівняти
Феліпе

1
Мені подобається це рішення та ідея використання сітки для цієї проблеми, але я думаю, що ваше рішення має деякі помітні недоліки. По-перше, якщо вміст будь-якої із зовнішніх комірок перевищує 20%, вміст або перегортається, або переливається в центральну клітинку. По-друге, якщо центр більший за 60%, він буде рости поза його вікном вмісту і або завертати, або виштовхувати останню клітинку. Нарешті, центр не зміщується, щоб звільнити місце для зовнішніх комірок. Це просто змушує їх загортати / переповнювати. Це не погане рішення, але ІМО, це не "явно найчистіший варіант".
Кріс

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

Ось відповідь, що використовує сітку замість флексбоксу. Це рішення не вимагає додаткових елементів онуків у 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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.