Як відцентрувати гнучкий контейнер, але вирівняти елементи гнучкого вирівнювання за лівим краєм


91

Я хочу, щоб гнучкі елементи були відцентровані, але коли у нас є другий рядок, щоб їх було 5 (з малюнка нижче) під 1, а не по центру в батьківському.

введіть тут опис зображення

Ось приклад того, що я маю:

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/

Відповіді:


79

Проблеми та обмеження Flexbox

Завдання полягає в тому, щоб відцентрувати групу гнучких предметів та вирівняти їх за обертанням за лівим краєм. Але якщо в рядку немає фіксованої кількості ящиків і кожна коробка має фіксовану ширину, це на даний момент неможливо для flexbox.

Використовуючи код, опублікований у питанні, ми могли б створити новий flex-контейнер, який обгортає поточний flex-контейнер ( ul), що дозволить нам відцентрувати за ulдопомогою justify-content: center.

Тоді гнучкі елементи ulможна вирівняти за лівим краєм justify-content: flex-start.

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

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

Це створює центровану групу гнучких елементів, вирівняних за лівим краєм.

Проблема цього методу полягає в тому, що при певних розмірах екрану буде проміжок праворуч ul, через що він більше не буде виглядати по центру.

введіть тут опис зображення введіть тут опис зображення

Це відбувається тому, що в гнучкому макеті (і, власне, CSS загалом) контейнер:

  1. не знає, коли елемент загортається;
  2. не знає, що раніше зайнятий простір тепер порожній, і
  3. не перераховує його ширину, щоб стиснути-обернути вужчий макет.

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

У наступній демонстрації, змінивши розмір вікна по горизонталі, ви зможете побачити пробіли, які з’являються та йдуть.

ДЕМО


Більш практичний підхід

Бажаний макет можна досягти без використання flexbox inline-blockта медіа-запитів .

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

Наведений вище код відображає горизонтально відцентрований контейнер з вирівняними за лівим боку дочірніми елементами, як це:

введіть тут опис зображення

ДЕМО


Інші варіанти


3
Так, багато з того, що люди хочуть зробити і в кінцевому підсумку використовують flexbox, насправді просто створюють сітку. На щастя, це буде покрито сітками CSS, коли ці досяжності стануть більш доопрацьованими.
TylerH

1
Цей допис пов’язано з вашим. У мене є ще одна версія, як вирішити ту саму проблему, все-таки це може бути обман, тож подивіться і вирішіть самі, чи хочете ви закрити її як таку. І плюс 1 за чудове пояснення в цьому.
Незабаром

Можливо, інша ідея полягає у виконанні margin:0 autoбатьківської обгортки, щоб все було зосереджено на сторінці. З цього моменту всі дочірні компоненти (тобто перший flex-контейнер) просто виконують це звичайний процес рядка потоку? Здається, це можна зробити просто.
klewis

12

Ви можете досягти цього за допомогою CSS Grid, просто використовуйте 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/


Цікаво. Але не усуває прогалину праворуч чи центрує сітку
Червоне

2
@Red Була одна помилка. Я змінився justify-items: centerна justify-content:center, і тепер він ідеально центрується.
Joe82

Я не розумію 210pxчастину всередині minmax. Як мені зробити те саме, але без штучного обмеження 210px? Такого обмеження у flexbox немає. Я хочу точно такий же результат, як і у flexbox, але область вмісту повинна бути відцентрована, як у вашому рішенні.
Андрій Михайлов - lolmaus

1
Привіт @ AndreyMikhaylov-lolmaus, цей метод працює, коли потрібно встановити фіксовану ширину для всіх елементів. У питанні це виражається як width:200px, і в моєму прикладі, як я встановив width:210px, я повинен додати це, як і в minmaxчастині
Joe82

@ Joe82 Дякую за роз'яснення! 🙏 Чи знаєте ви спосіб змусити його працювати для елементів довільної ширини?
Андрій Михайлов - lolmaus

0

Як запропонував @michael, це обмеження для поточного flexbox. Але якщо ви все ще хочете використовувати flexі justify-content: center;, тоді ми можемо обійти це шляхом додавання фіктивного liелемента та призначення 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); 

Перевірте цю скрипку (змініть розмір і перегляньте) або відео для довідки


0

Одним із способів отримати бажаний стиль із полями є наступне:

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

#innercontainer {
    display: flex;
    flex: 0.9; -> add desired % of margin
    justify-content: flex-start;
}

0

Ви можете розміщувати невидимі елементи з тим самим класом, що й інші (вилучені на прикладі з метою виставки), а висоту встановити на 0. Завдяки цьому ви зможете обгрунтувати елементи до самого початку сітки.

Приклад

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

Результат

введіть тут опис зображення


-1

Я зіткнувся з цією проблемою під час кодування за допомогою React Native. Є елегантне рішення, яке ви можете отримати за допомогою FlexBox. У моїй конкретній ситуації я намагався відцентрувати три коробки згину (Flex: 2) всередині іншого за допомогою alignItems. Рішення, яке я придумав, було використання двох порожніх s, кожен з Flex: 1.

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

Досить просто перетворити на веб / CSS.


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