Flexbox: 4 Elemente pro Zeile

260

Ich verwende eine Flexbox, um 8 Elemente anzuzeigen, deren Größe sich dynamisch mit meiner Seite ändert. Wie erzwinge ich, dass die Elemente in zwei Zeilen aufgeteilt werden? (4 pro Reihe)?

Hier ist ein relevanter Ausschnitt:

(Oder wenn Sie jsfiddle bevorzugen - 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
quelle
16
[Update] Diese Frage basierte auf einem schlechten, nicht reagierenden Design. Wenn Sie eine der folgenden Antworten verwenden, seien Sie vorsichtig. In einem guten Design hätten Sie mehr Elemente auf breiteren Bildschirmen und weniger auf kleineren Bildschirmen. Das Erzwingen von 4 Elementen für alle Bildschirmgrößen sieht nur in einem engen Bereich von Bildschirmbreiten ansprechend aus.
Vivek Maharajh

Antworten:

380

Du bist flex-wrap: wrapauf dem Container. Das ist gut, weil es den Standardwert nowrap( Quelle ) überschreibt . Dies ist der Grund, warum Elemente in einigen Fällen nicht zu einem Raster umgebrochen werden .

In diesem Fall liegt das Hauptproblem flex-grow: 1bei den flexiblen Elementen.

Die flex-growEigenschaft hat keine Größe für Flex-Elemente. Seine Aufgabe ist es, freien Speicherplatz im Container ( Quelle ) zu verteilen . Unabhängig von der Größe des Bildschirms erhält jedes Element einen proportionalen Teil des freien Speicherplatzes in der Zeile.

Insbesondere enthält Ihr Container acht Flex-Artikel. Mit flex-grow: 1erhält jeder 1/8 des freien Speicherplatzes auf der Leitung. Da Ihre Artikel keinen Inhalt enthalten, können sie auf die Breite Null schrumpfen und werden niemals verpackt.

Die Lösung besteht darin, eine Breite für die Elemente zu definieren. Versuche dies:

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

Bei der flex-grow: 1Definition in der flexKurzform müssen keine flex-basis25% angegeben werden, was aufgrund der Ränder tatsächlich zu drei Elementen pro Zeile führen würde.

Da flex-growder freie Speicherplatz in der Zeile belegt wird, flex-basismuss er nur groß genug sein, um einen Wrap zu erzwingen. In diesem Fall flex-basis: 21%gibt es mit viel Platz für die Ränder, aber nie genug Platz für ein fünftes Element.

Michael Benjamin
quelle
1
Ich mag das, weil es für mich funktioniert hat, aber „viel Platz“ macht mich ein wenig unruhig. Gibt es ein winziges Fenster oder eine Situation, in der diese „Schätzung“ mich verfehlen könnte?
Jackson
1
Was für eine Situation? In den meisten Layouts gibt es Extremfälle, die Probleme verursachen können. Solche Fälle durchlaufen normalerweise Kosten-Nutzen-Analysen, weil sie nie oder fast nie auftreten. Wenn Sie in der obigen Lösung beispielsweise sehr große Ränder eingeben, kann das Layout beschädigt werden. Wenn dies ein Problem ist, sollte es in der Frage veröffentlicht werden. @ Jackson
Michael Benjamin
2
„Wenn Sie sehr große Ränder eingeben, kann das Layout beschädigt werden.“ Dies ist ein Beispiel für ein Szenario, das ich vermeiden möchte. Praktikabilität ist mir egal; unterhalte meine Anbetung für Perfektion. Gibt es eine Möglichkeit, genauer zu sein?
Jackson
27
Sie können auch verwendenflex: 1 0 calc(25% - 10px);
MarkG
2
Gute Antwort! Eine kleine Verbesserung, die ich verwende, ist margin: 2%;anstelle einer festen Pixelanzahl, um zu verhindern, dass die Boxen bei kleinen Geräten / Auflösungen zu einer neuen Zeile springen. Die allgemeine Formel lautet (100 - (4 * box-width-percent)) / 8% für verschiedene Kastenbreiten
Thomaspsk
104

Fügen Sie den .childElementen eine Breite hinzu . Ich persönlich würde Prozentsätze für die verwenden, margin-leftwenn Sie es immer 4 pro Zeile haben möchten.

DEMO

.child {
    display: inline-block;
    background: blue;
    margin: 10px 0 0 2%;
    flex-grow: 1;
    height: 100px;
    width: calc(100% * (1/4) - 10px - 1px);
}
Dowomenfart
quelle
Gute Idee. Ich habe diese Idee mit geringfügigen Änderungen verwendet. jsfiddle.net/vivmaha/oq6prk1p/6
Vivek Maharajh
1
Ah. Das löst mein Problem eigentlich nicht. Ein Beispiel finden Sie hier: jsfiddle.net/vivmaha/oq6prk1p/7 . Ich habe nicht die Freiheit, Prozentsätze für meine Marge zu verwenden. Sie müssen eine feste Breite haben. Dies bedeutet, dass die von uns gewählten magischen 23% nicht funktionieren, da der feste Spielraum nicht berücksichtigt wird.
Vivek Maharajh
3
Ja, calc löst es! 'calc (100% * (1/4) - 10px - 1px)'. Siehe jsfiddle.net/vivmaha/oq6prk1p/9
Vivek Maharajh
24
Was nützt Flex dann noch?
zweimal
Was ist mit Responsive Design? Wir wollen keine feste Breite für Kinder
festlegen
40

Hier ist ein weiterer Ansatz.

Sie können dies auch auf folgende Weise erreichen:

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

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

Beispiel: https://codepen.io/capynet/pen/WOPBBm

Und ein vollständigeres Beispiel: https://codepen.io/capynet/pen/JyYaba

Capy
quelle
1
Was ist, wenn ich weniger als 4 Kinder habe? Ich mag diesen leeren leeren Raum nicht, das Kind
reagiert
Die andere Antwort von Muddasir Abbas verwendet nur Flex-Einstellungen, daher denke ich, dass es eine sauberere Lösung ist.
Andrew Koster
17

Ich würde es so machen, indem ich negative Ränder benutze und für die Dachrinnen kalkuliere:

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


Alternative CSS-Grid-Methode:

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

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

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

Ich hoffe es hilft. Für weitere Informationen können Sie diesem Link folgen

Muddasir Abbas
quelle
4

Ich glaube, dieses Beispiel ist mehr Barebones und leichter zu verstehen als @dowomenfart.

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

Dies führt die gleichen Breitenberechnungen durch, während direkt zum Fleisch geschnitten wird. Die Mathematik ist viel einfacher und aufgrund ihrer Skalierbarkeit und Benutzerfreundlichkeit emder neue Standard .

Joseph Cho
quelle
3
em ist nicht wirklich der neue Standard. Es kann nerven, und Designer entwerfen nicht mit Blick auf EMs.
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
quelle
1
Wenn Sie einen Kontext hinzufügen können, warum dies die OP-Frage beantwortet, anstatt nur den Code zu veröffentlichen.
d219
Wenn Sie justify-content: space-evenly;dem Prent etwas hinzufügen , sind sie gut ausgerichtet und Sie müssen das nicht calcfür das Kind tun . Vielen Dank für das Beispiel!
Mattijs
0

Flex Wrap + negativer Rand

Warum flex vs. display: inline-block?

Warum negative Marge?

Entweder verwenden Sie SCSS oder CSS-in-JS für die Randfälle (dh das erste Element in der Spalte), oder Sie legen einen Standardrand fest und entfernen den äußeren Rand später.

Implementierung

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

Hier ist ein anderer Weg ohne zu verwenden 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!

Das ist alles dazu. Sie können sich mit den Abmessungen ein Bild machen, um ästhetischere Größen zu erhalten, aber das ist die Idee.

wle8300
quelle
6
Ich habe dies nicht getestet, aber die CSS-Syntax ist falsch (CSS-Werte werden nicht in Anführungszeichen gesetzt und Deklarationen sollten in einem Semikolon enden), sodass es in der aktuellen Form definitiv nicht funktioniert.
Nick F