Flexbox: 4 elementy w rzędzie

260

Korzystam z okna elastycznego, aby wyświetlić 8 elementów, które będą dynamicznie zmieniać rozmiar na mojej stronie. Jak zmusić go do podzielenia przedmiotów na dwa rzędy? (4 na rząd)?

Oto odpowiedni wycinek:

(Lub jeśli wolisz 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>

Vivek Maharajh
źródło
16
[Aktualizacja] To pytanie było oparte na słabym, niereagującym projekcie. Jeśli znajdziesz jedną z poniższych odpowiedzi, zachowaj ostrożność. Przy dobrym projekcie będziesz mieć więcej przedmiotów na szerszych ekranach, a mniej na mniejszych ekranach. Wymuszenie 4 elementów dla wszystkich rozmiarów ekranu będzie wyglądać atrakcyjnie tylko w wąskim zakresie szerokości ekranu.
Vivek Maharajh

Odpowiedzi:

380

Masz flex-wrap: wrapna pojemniku. To dobrze, ponieważ zastępuje wartość domyślną, którą jest nowrap( źródło ). Z tego powodu w niektórych przypadkach elementy nie są zawijane, aby utworzyć siatkę .

W tym przypadku głównym problemem są flex-grow: 1elementy elastyczne.

flex-growNieruchomość nie faktycznie wielkości flex przedmiotów. Jego zadaniem jest dystrybucja wolnej przestrzeni w kontenerze ( źródle ). Niezależnie od tego, jak mały jest rozmiar ekranu, każdy element otrzyma proporcjonalną część wolnego miejsca w wierszu.

Mówiąc dokładniej, w twoim pojemniku znajduje się osiem elastycznych przedmiotów. Z flex-grow: 1, każdy otrzymuje 1/8 wolnego miejsca na linii. Ponieważ w twoich przedmiotach nie ma treści, mogą się one zmniejszyć do zera i nigdy się nie zawiną.

Rozwiązaniem jest zdefiniowanie szerokości elementów. Spróbuj tego:

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

Po flex-grow: 1zdefiniowaniu w flexskrócie nie ma potrzeby, flex-basisaby wynosić 25%, co w rzeczywistości spowodowałoby trzy pozycje z rzędu ze względu na marginesy.

Ponieważ flex-growzajmie wolne miejsce w rzędzie, flex-basismusi być wystarczająco duże, aby wymusić zawijanie. W tym przypadku z flex-basis: 21%marginesami jest dużo miejsca, ale nigdy nie ma wystarczającej ilości miejsca na piąty przedmiot.

Michael Benjamin
źródło
1
Podoba mi się to, ponieważ działało dla mnie, ale „dużo miejsca” sprawia, że ​​czuję się trochę nieswojo. Czy jest jakieś małe okno lub sytuacja, w której to „oszacowanie” może mnie zawieść?
Jackson
1
Jaka sytuacja? W większości układów występują skrajne przypadki, które mogą powodować problemy. Takie przypadki zwykle podlegają analizie kosztów i korzyści, ponieważ nigdy nie występują lub prawie nigdy nie występują. Na przykład w powyższym rozwiązaniu układanie bardzo dużych marginesów może spowodować uszkodzenie układu. Jeśli to jest problem, należy go zamieścić w pytaniu. @Jackson
Michael Benjamin
2
„Jeśli wprowadzisz bardzo duże marginesy, układ może się zepsuć” To przykład scenariusza, którego chciałbym uniknąć. Nie dbam o praktyczność; baw się uwielbieniem dla doskonałości. Czy jest jakiś sposób, aby być bardziej dokładnym?
Jackson
27
Możesz także użyćflex: 1 0 calc(25% - 10px);
MarkG
2
Świetna odpowiedź! Małe ulepszenie, którego używam, to margin: 2%;zamiast stałej liczby pikseli, aby zapobiec przeskakiwaniu pudełek do nowej linii na małych urządzeniach / rozdzielczościach. ogólna formuła to (100 - (4 * box-width-percent)) / 8% dla różnych szerokości skrzynek
Thomaspsk
104

Dodaj szerokość do .childelementów. Osobiście użyłbym wartości procentowych, margin-leftjeśli chcesz mieć zawsze 4 na wiersz.

PRÓBNY

.child {
    display: inline-block;
    background: blue;
    margin: 10px 0 0 2%;
    flex-grow: 1;
    height: 100px;
    width: calc(100% * (1/4) - 10px - 1px);
}
dowomenfart
źródło
Dobry pomysł. Użyłem tego pomysłu z niewielkimi zmianami. jsfiddle.net/vivmaha/oq6prk1p/6
Vivek
1
Ach To tak naprawdę nie rozwiązuje mojego problemu. Zobacz tutaj przykład: jsfiddle.net/vivmaha/oq6prk1p/7 . Nie mogę swobodnie korzystać z procentów dla mojej marży. Muszą mieć stałą szerokość. Oznacza to, że magia 23%, którą wybraliśmy, nie zadziała, ponieważ nie uwzględnia ustalonego marginesu.
Vivek Maharajh,
3
Tak, calc rozwiązuje to! „calc (100% * (1/4) - 10px - 1px)”. Zobacz jsfiddle.net/vivmaha/oq6prk1p/9
Vivek
24
Więc w takim razie jaki jest pożytek z flexu?
twicejr
Co z responsywnym designem? Nie chcemy nakładać stałej szerokości na dziecko
Candlejack
40

Oto kolejny aplet.

Możesz to zrobić również w ten sposób:

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

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

Przykład: https://codepen.io/capynet/pen/WOPBBm

I bardziej kompletna próbka: https://codepen.io/capynet/pen/JyYaba

Capy
źródło
1
Co jeśli mam mniej niż 4 dziecko? Nie podoba mi się to puste puste miejsce, dziecko nie reaguje ...
candlejack
Druga odpowiedź Muddasira Abbasa wykorzystuje tylko ustawienia flex, więc myślę, że jest to czystsze rozwiązanie.
Andrew Koster
17

Zrobiłbym to w ten sposób, używając ujemnych marginesów i obliczeń dla rynien:

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

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

Demo: https://jsfiddle.net/9j2rvom4/


Alternatywna metoda siatki CSS:

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

Demo: https://jsfiddle.net/jc2utfs3/

shanomurphy
źródło
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>

Mam nadzieję, że to pomoże. po więcej szczegółów możesz skorzystać z tego linku

Muddasir Abbas
źródło
4

Uważam, że ten przykład jest bardziej prosty i łatwiejszy do zrozumienia niż @dowomenfart.

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

Dokonuje się tych samych obliczeń szerokości podczas cięcia bezpośrednio do mięsa. Matematyka jest znacznie łatwiejsza i emjest nowym standardem ze względu na skalowalność i łatwość obsługi mobilnej.

Joseph Cho
źródło
3
nie jest tak naprawdę nowym standardem. To może być bolesne w tyłek, a projektanci nie projektują z myślą o EM.
Danny van Holten
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>

;)

Mateus Manosso Barszcz
źródło
1
Jeśli możesz dodać kontekst, dlaczego odpowiada na pytanie OP, a nie tylko kod pocztowy.
d219
jeśli dodasz justify-content: space-evenly;do prenta, to ładnie się dopasują i nie musisz robić tego calcna dziecku. Ale dziękuję za przykład!
Mattijs
0

Flex wrap + ujemny margines

Dlaczego Flex vs. display: inline-block?

Dlaczego marża ujemna?

Albo używasz SCSS lub CSS-in-JS dla przypadków krawędzi (tj. Pierwszy element w kolumnie), albo ustawiasz domyślny margines i pozbywasz się zewnętrznego marginesu później.

Realizacja

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;
}
zurfyx
źródło
-12

Oto inny sposób bez użycia 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!

To wszystko. Możesz uzyskać wymyślne wymiary, aby uzyskać bardziej estetyczne rozmiary, ale taki jest pomysł.

wle8300
źródło
6
Nie testowałem tego, ale składnia CSS jest niepoprawna (wartości CSS nie są cytowane, a deklaracje powinny kończyć się średnikiem), więc na pewno nie będzie działać w obecnej formie.
Nick F