Flexbox: 4 елементи в ряд


260

Я використовую флекс-вікно для відображення 8 елементів, які динамічно змінюватимуть розмір моєї сторінки. Як змусити це розділити елементи на два ряди? (4 у ряд)?

Ось відповідний фрагмент:

(Або якщо ви віддаєте перевагу jsfiddle - http://jsfiddle.net/vivmaha/oq6prk1p/2/ )

.parent-wrapper {
  height: 100%;
  width: 100%;
  border: 1px solid black;
}
.parent {
  display: flex;
  font-size: 0;
  flex-wrap: wrap;
  margin: -10px 0 0 -10px;
}
.child {
  display: inline-block;
  background: blue;
  margin: 10px 0 0 10px;
  flex-grow: 1;
  height: 100px;
}
<body>
  <div class="parent-wrapper">
    <div class="parent">
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
    </div>
  </div>
</body>


16
[Оновити] Це питання ґрунтувалося на поганій невідповідній конструкції. Якщо ви опинитесь одним із відповідей нижче, будьте обережні. У гарному дизайні ви матимете більше елементів на ширших екранах, а менше на менших екранах. Примусовий розмір 4 елементів для всіх розмірів екрана виглядатиме привабливо лише у вузькому діапазоні ширини екрана.
Vivek Maharajh

Відповіді:


380

Ви потрапили flex-wrap: wrapна контейнер. Це добре, оскільки воно переосмислює значення за замовчуванням, яке є nowrap( джерело ). З цієї причини елементи в деяких випадках не загортаються, щоб утворювати сітку .

У цьому випадку основна проблема полягає flex-grow: 1в гнучких елементах.

flex-growВластивість фактично не розмір згинати деталі. Його завдання - розподілити вільний простір у контейнері ( джерелі ). Тож незалежно від того, наскільки маленький розмір екрана, кожен елемент отримає пропорційну частину вільного місця в рядку.

Більш конкретно, у вашому контейнері є вісім гнучких предметів. З flex-grow: 1, кожен отримує 1/8 вільного місця на лінії. Оскільки у ваших предметах немає вмісту, вони можуть скорочуватися до нульової ширини і ніколи не завершаться.

Рішення полягає у визначенні ширини на елементах. Спробуйте це:

.parent {
  display: flex;
  flex-wrap: wrap;
}

.child {
  flex: 1 0 21%; /* explanation below */
  margin: 5px;
  height: 100px;
  background-color: blue;
}
<div class="parent">
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
</div>

Якщо flex-grow: 1визначено у flexстенограмі, немає необхідності flex-basisстановити 25%, що фактично призведе до трьох елементів у рядку через маржинацію.

Оскільки flex-growбуде витрачено вільний простір в ряду, його flex-basisпотрібно мати лише достатньо великого розміру, щоб забезпечити обертання. У цьому випадку, з flex-basis: 21%, є достатньо місця для поля, але ніколи не вистачає місця для п’ятого елемента.


1
Мені це подобається, бо це працювало на мене, але «багато місця» змушує мене почувати себе трохи неприємно. Чи є якесь крихітне вікно чи ситуація, коли ця "оцінка" може мене зірвати?
Джексон

1
Яка ситуація? У більшості макетів є крайні випадки, які можуть створити проблеми. Такі випадки зазвичай проходять через аналіз витрат і вигод, оскільки вони ніколи, або майже ніколи не трапляються. Наприклад, у рішенні вище, якщо розмістити дуже великі поля, макет може зламатися. Якщо це питання, то його слід розмістити в запитанні. @Jackson
Майкл Бенджамін

2
"Якщо ви поставите дуже великі поля, макет може зламатися". Це приклад сценарію, якого я хотів би уникнути. Мене не хвилює практичність; розважати моє обожнення до досконалості. Чи є якийсь спосіб бути точнішим?
Джексон

27
Ви також можете скористатисяflex: 1 0 calc(25% - 10px);
MarkG

2
Чудова відповідь! Я використовую невелике вдосконалення margin: 2%;замість фіксованого числа пікселів, щоб запобігти переходу ящиків на нову лінію на невеликих пристроях / роздільній здатності. загальна формула становить (100 - (4 * box-width-percent)) / 8% для різної ширини коробки
thomaspsk

104

Додайте ширину до .childелементів. Я особисто використовував би відсотки, margin-leftякщо ви хочете мати його завжди 4 в ряд.

DEMO

.child {
    display: inline-block;
    background: blue;
    margin: 10px 0 0 2%;
    flex-grow: 1;
    height: 100px;
    width: calc(100% * (1/4) - 10px - 1px);
}

Гарна ідея. Я використовував цю ідею з незначними правками. jsfiddle.net/vivmaha/oq6prk1p/6
Vivek Maharajh

1
Ага. Це насправді не вирішує мою проблему. Тут див. Приклад: jsfiddle.net/vivmaha/oq6prk1p/7 . Я не маю права використовувати відсотки для своєї маржі. Вони повинні бути фіксованої ширини. Це означає, що вибрані нами магічні 23% не будуть працювати, оскільки вони не враховують фіксовану маржу.
Vivek Maharajh

3
Так, кальц це вирішує! 'обчислення (100% * (1/4) - 10 пікс. - 1 пікс.)'. Дивіться jsfiddle.net/vivmaha/oq6prk1p/9
Vivek Maharajh

24
Тоді в чому все-таки користь флексу?
doublejr

Що з чуйним дизайном? Ми не хочемо ставити фіксовану ширину на дитину
підсвічник

40

Ось ще один підручник.

Ви також можете виконати це таким чином:

.parent{
  display: flex;
  flex-wrap: wrap;
}

.child{
  width: 25%;
  box-sizing: border-box;
}

Зразок: https://codepen.io/capynet/pen/WOPBBm

І більш повний зразок: https://codepen.io/capynet/pen/JyYaba


1
А як бути, якщо у мене менше 4 дітей? Мені не подобається порожній простір, дитина не реагує на ...
підсвічник

Інша відповідь Муддасіра Аббаса використовує лише гнучкі настройки, тому я думаю, що це більш чисте рішення.
Андрій Костер

17

Я б це робив так, використовуючи негативні поля та вирахування для жолобів:

.parent {
  display: flex;
  flex-wrap: wrap;
  margin-top: -10px;
  margin-left: -10px;
}

.child {
  width: calc(25% - 10px);
  margin-left: 10px;
  margin-top: 10px;
}

Демо: https://jsfiddle.net/9j2rvom4/


Альтернативний метод сітки CSS:

.parent {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-column-gap: 10px;
  grid-row-gap: 10px;
}

Демонстрація: https://jsfiddle.net/jc2utfs3/


14
<style type="text/css">
.parent{
    display: flex;
    flex-wrap: wrap;
}
.parent .child{
    flex: 1 1 25%;
}
</style>    
<div class="parent">
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
    </div>

Сподіваюся, це допомагає. для більш детальної інформації ви можете перейти за цим посиланням


4

Я вважаю, що цей приклад є більш босоніжним і легшим для розуміння, ніж @dowomenfart.

.child {
    display: inline-block;
    margin: 0 1em;
    flex-grow: 1;
    width: calc(25% - 2em);
}

Це виконує однакові розрахунки ширини при різанні прямо до м'яса. Математика набагато легша і emє новим стандартом завдяки своїй масштабованості та зручності для мобільних пристроїв.


3
em насправді не є новим стандартом. Це може бути біль в попці, і дизайнери не розробляють дизайн з урахуванням ЕМ.
Денні ван Голтен

2

.parent-wrapper {
	height: 100%;
	width: 100%;
	border: 1px solid black;
}
	.parent {
	display: flex;
	font-size: 0;
	flex-wrap: wrap;
	margin-right: -10px;
	margin-bottom: -10px;
}
	.child {
	background: blue;
	height: 100px;
	flex-grow: 1;
	flex-shrink: 0;
	flex-basis: calc(25% - 10px);
}
	.child:nth-child(even) {
	margin: 0 10px 10px 10px;
	background-color: lime;
}
	.child:nth-child(odd) {
	background-color: orange; 
}
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<style type="text/css">

	</style>
</head>
<body>
  <div class="parent-wrapper">
    <div class="parent">
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
    </div>
  </div>
</body>
</html>

;)


1
Якщо ви можете, будь-ласка, додайте контекст про те, чому це відповідає на питання ОП, а не просто розміщувати код.
d219

якщо ви додасте justify-content: space-evenly;до прент, то вони добре вирівнюються, і вам не доведеться робити це calcнад дитиною. Дякую за приклад, хоча!
Маттійс

0

Flex wrap + негативний запас

Чому флекс проти display: inline-block?

Чому від’ємна маржа?

Або ви використовуєте SCSS або CSS-in-JS для крайових випадків (тобто перший елемент у стовпці), або встановлюєте маржу за замовчуванням і позбуєтесь зовнішнього поля пізніше.

Впровадження

https://codepen.io/zurfyx/pen/BaBWpja

<div class="outerContainer">
    <div class="container">
        <div class="elementContainer">
            <div class="element">
            </div>
        </div>
        ...
    </div>
</div>
:root {
  --columns: 2;
  --betweenColumns: 20px; /* This value is doubled when no margin collapsing */
}

.outerContainer {
    overflow: hidden; /* Hide the negative margin */
}

.container {
    background-color: grey;
    display: flex;
    flex-wrap: wrap;
    margin: calc(-1 * var(--betweenColumns));
}

.elementContainer {
    display: flex; /* To prevent margin collapsing */
    width: calc(1/var(--columns) * 100% - 2 * var(--betweenColumns));
    margin: var(--betweenColumns);
}

.element {
    display: flex;
    border: 1px solid red;
    background-color: yellow;
    width: 100%;
    height: 42px;
}

-12

Ось ще один спосіб без використання calc().

// 4 PER ROW
// 100 divided by 4 is 25. Let's use 21% for width, and the remainder 4% for left & right margins...
.child {
  margin: 0 2% 0 2%;
  width: 21%;
}

// 3 PER ROW
// 100 divided by 3 is 33.3333... Let's use 30% for width, and remaining 3.3333% for sides (hint: 3.3333 / 2 = 1.66666)
.child {
  margin: 0 1.66666% 0 1.66666%;
  width: 30%;
}

// and so on!

Це все, що там є. Ви можете захоплюватися розмірами, щоб отримати більш естетичні розміри, але це ідея.


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