Lepszy sposób na ustawienie odległości między elementami Flexbox

777

Aby ustawić minimalną odległość między elementami schematu flexbox używam margin: 0 5pxna .itemi margin: 0 -5pxna pojemniku. Dla mnie to wygląda na hack, ale nie mogę znaleźć lepszego sposobu na zrobienie tego.

Przykład

#box {
  display: flex;
  width: 100px;
  margin: 0 -5px;
}
.item {
  background: gray;
  width: 50px;
  height: 50px;
  margin: 0 5px;
}
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

Sasha Koss
źródło
28
To nie jest hack - to jedna z zamierzonych metod wyrównywania przedmiotów. Istnieją jednak inne właściwości. Zobacz w3.org/TR/css3-flexbox/#alignment
BoltClock
4
Tak, rozumiem. Ale na przykład istnieje właściwość odstępu między kolumnami, która daje nam możliwość kontrolowania odległości od kontenera: w3.org/TR/css3-multicol/#column-gap
Sasha Koss,
Przyczyną jest to, że margines zapada się w flexboksie. Inne pytanie ma słuszność: [Jak mogę zatrzymać ostatni margines zapadający się w flexboksie? ] ( stackoverflow.com/questions/38993170/… )
Jack Yang
6
CSS Box Level 3 Wyrównanie Moduł zawiera rozdział dotyczący luki między skrzynek - mającym zastosowanie do elementów wielu kolumn, Flex pojemników i kontenerów siatki. W końcu będzie to proste: row-gap: 5px- zrobione.
Danield,
2
@JohnCarrell firefox faktycznie już wspiera gapnieruchomości na pojemnikach typu flex ( caniuse )
Danield

Odpowiedzi:

427
  • Flexbox nie ma zawijanych marginesów.
  • Flexbox nie ma nic podobnego do border-spacingtabel (z wyjątkiem właściwości CSS, gapktóra nie jest dobrze obsługiwana w większości przeglądarek, caniuse )

Dlatego osiągnięcie tego, o co prosisz, jest nieco trudniejsze.

Z mojego doświadczenia wynika, że ​​„najczystszym” sposobem, który nie używa :first-child/ :last-childi działa bez żadnych modyfikacji, flex-wrap:wrapjest ustawienie padding:5pxkontenera i margin:5pxdzieci. To stworzy 10pxlukę między każdym dzieckiem a między każdym dzieckiem a ich rodzicem.

Próbny

.upper
{
  margin:30px;
  display:flex;
  flex-direction:row;
  width:300px;
  height:80px;
  border:1px red solid;

  padding:5px; /* this */
}

.upper > div
{
  flex:1 1 auto;
  border:1px red solid;
  text-align:center;

  margin:5px;  /* and that, will result in a 10px gap */
}

.upper.mc /* multicol test */
{flex-direction:column;flex-wrap:wrap;width:200px;height:200px;}
<div class="upper">
  <div>aaa<br/>aaa</div>
  <div>aaa</div>
  <div>aaa<br/>aaa</div>
  <div>aaa<br/>aaa<br/>aaa</div>
  <div>aaa</div>
  <div>aaa</div>
</div>

<div class="upper mc">
  <div>aaa<br/>aaa</div>
  <div>aaa</div>
  <div>aaa<br/>aaa</div>
  <div>aaa<br/>aaa<br/>aaa</div>
  <div>aaa</div>
  <div>aaa</div>
</div>

Wszyscy pracownicy są niezbędni
źródło
219
To nie osiąga tego samego, co zadaje pytanie, będziesz miał wcięcie 10 pikseli po lewej i prawej stronie, co, jak zakładam, nie ma takiego zamiaru. Stąd ujemne marginesy w pierwotnym pytaniu.
Chris Nicola,
17
Co jeśli orderzestaw właściwości? :first-child/:last-childnie będzie działać zgodnie z oczekiwaniami.
Guria,
4
„Flexbox nie ma zawijanych marginesów”. Bardzo wnikliwe i pozornie prawdziwe, ale czy mogę poprosić o cytat?
chharvey
2
Czy nie jest to gorsza odpowiedź od pierwotnego pytania? Ta metoda wymaga przestrzeni wokół kontenera, a rynna musi być zawsze liczbą parzystą.
limitlessloop
7
@chharvey, ze specyfikacji w3.org/TR/css-flexbox-1/#item-margins , „Marginesy sąsiednich elementów elastycznych się nie zwija”.
romellem
195

To nie jest hack. Ta sama technika jest również używana przez bootstrap i jego siatkę, jednak zamiast marginesu, bootstrap używa wypełnienia dla swoich cols.

.row {
  margin:0 -15px;
}
.col-xx-xx {
  padding:0 15px;
}
Roumelis George
źródło
1
Jedynym problemem związanym z tą metodą jest utrzymanie elementów o jednakowej wysokości z kolorami tła. Bezwzględne pozycjonowanie z height:100%; width:100%ignoruje dopełnienie elementu.
Steven Vachon
3
Problem dotyczy IE10 i 11. flex-basiswartości nie uwzględniają box-sizing: border-box, więc dziecko z dowolnym dopełnieniem lub ramką przepełni nadrzędny (lub zawinie w tym przypadku). Źródło
Carson
18
Istnieje inny problem z tym podejściem: dostosowanie marginesu w ten sposób może zwiększyć szerokość strony. Demo: jsfiddle.net/a97tatf6/1
Nathan Osman
4
Chociaż zgadzam się, że to nie jest hack, fakt, że coś jest powszechnie używane, nie oznacza, że ​​nie jest to hack. Zobacz wypełnienia, tymczasowe łatki bezpieczeństwa, edycję szesnastkową itp.
William
15
Oczywiście, że to hack. Ponieważ Bootstrap używa tej metody , nie oznacza, że ​​to nie hack. Oznacza to po prostu, że Bootstrap używa hacka.
Michael Benjamin
108

Flexbox i css calc z obsługą wielu rzędów

Witaj, poniżej jest moje działające rozwiązanie dla wszystkich przeglądarek obsługujących Flexbox. Brak ujemnych marż.

Fiddle Demo

   
.flexbox {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: space-between;
}

.flexbox > div {
  /*
    1/3  - 3 columns per row
    10px - spacing between columns 
  */
  box-sizing: border-box;
  margin: 10px 10px 0 0;
  outline: 1px dotted red;
  width: calc(1/3*100% - (1 - 1/3)*10px);
}

/*
  align last row columns to the left
  3n - 3 columns per row
*/
.flexbox > div:nth-child(3n) {
  margin-right: 0;
}

.flexbox::after {
  content: '';
  flex: auto;
}

/*
  remove top margin from first row
  -n+3 - 3 columns per row 
*/
.flexbox > div:nth-child(-n+3) {
  margin-top: 0;
}
<div class="flexbox">
  <div>col</div>
  <div>col</div>
  <div>col</div>
  <div>col</div>
  <div>col</div>
</div>

Uwaga: ten kod może być krótszy przy użyciu SASS

Aktualizacja 2020.II.11 Wyrównane kolumny w ostatnim wierszu po lewej stronie

Aktualizacja 2020.II.14 Usunięto margines na dole w ostatnim wierszu

Dariusz Sikorski
źródło
13
Podoba mi się to rozwiązanie, ale zawodzi, jeśli w ostatnim rzędzie są tylko 2 elementy. Przedmioty nie są ułożone w stos ze względu na justify-content.
James Brantly
4
aby naprawić problem z dwoma przedmiotami, po prostu zmień na justify-content: space-evenly;lub justify-content: space-around;.
Paul Rooney
6
@PaulRooney Na stronie z wieloma listami możesz nie zawsze znać liczbę pozycji, jeśli listy są generowane przez CMS.
NinjaFart
1
@ 1.21gigawatts Proszę nie wprowadzać dowolnych zmian w cudzym kodzie / odpowiedzi; zamiast tego napisz własną odpowiedź.
TylerH,
2
@TylerH To nie było arbitralne. Pytanie brzmiało: „... aby ustawić odległość między elementami Flexbox”. Ta odpowiedź nie pokazuje wielkości rynny. Ustawienie koloru tła pokazuje rynnę. Dodanie ramki pokazuje margines poniżej ostatniego wiersza.
1.21 gigawatów
93

Możesz użyć przezroczystych ramek.

Rozważałem ten problem, starając się zbudować model elastycznej siatki, który może wrócić do modelu tabeli + komórki-komórki dla starszych przeglądarek. A granice dla rynien kolumnowych wydawały mi się najlepszym wyborem. tzn. komórki tabeli nie mają marginesów.

na przykład

.column{
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-bottom: 10px solid transparent;
}

Pamiętaj też, że potrzebujesz min-width: 50px;Flexboksa. Model flex nie będzie obsługiwał stałych rozmiarów, chyba że wykonasz flex: none;określony element podrzędny, który chcesz ustawić jako stały, a zatem nie będzie on istniał "flexi". http://jsfiddle.net/GLpUp/4/ Ale wszystkie kolumny razem z nimi flex:none;nie są już modelem elastycznym. Oto coś bliższego modelowi flex: http://jsfiddle.net/GLpUp/5/

Tak więc możesz właściwie używać marginesów normalnie, jeśli nie potrzebujesz rezerwowania komórek tabeli w starszych przeglądarkach. http://jsfiddle.net/GLpUp/3/

Ustawienie background-clip: padding-box;będzie konieczne podczas korzystania z tła, ponieważ w przeciwnym razie tło przepłynie do przezroczystego obszaru obramowania.

hexalys
źródło
5
świetna odpowiedź. marginesy są używane różnie w flexboksie (lubią absorbować dodatkową przestrzeń), więc przezroczyste ramki zapewniają doskonałe rozwiązanie dla równomiernie rozmieszczonych elementów, które mogą się zawijać z zachowaniem przypominającym marginesy
Eolis
4
z wyjątkiem sytuacji, gdy użyjesz koloru tła, tło przekroczy pożądane granice.
ahnbizcad
2
@ahnbizcad Dobrze z różnymi kolorami tła, możesz użyć białego lub odpowiedniego koloru w zależności od tego, w którą stronę jest tło.
hexalys
27
@ahnbizcad: Jeśli nie potrzebujesz wsparcia IE8, jest to lepsze rozwiązanie:background-clip: padding-box
Albin
5
Komentarz Albina wymaga więcej głosów! To najlepsze rozwiązanie. Przezroczyste obramowania w połączeniu z klipsem tła: padding-box (i ujemne marginesy na pojemniku, jeśli to konieczne, dla prawidłowego wyrównania krawędzi) to idealne rozwiązanie. IE8 i tak nie obsługuje Flexboksa, więc brak obsługi klipu w tle nie powinien mieć znaczenia.
Brian
74

To rozwiązanie będzie działać we wszystkich przypadkach, nawet jeśli jest wiele wierszy lub dowolna liczba elementów. Ale liczba sekcji powinna być taka sama, jak chcesz 4 w pierwszym rzędzie, a 3 to drugi rząd, to nie będzie działać w ten sposób, że miejsce na 4. zawartość będzie puste, pojemnik nie będzie wypełniony.

Używamy display: grid; i jego właściwości.

#box {
  display: grid;
  width: 100px;
  grid-gap: 5px;
  /* Space between items */
  grid-template-columns: 1fr 1fr 1fr 1fr;
  /* Decide the number of columns and size */
}

.item {
  background: gray;
  width: 100%;
  /* width is not necessary only added this to understand that width works as 100% to the grid template allocated space **DEFAULT WIDTH WILL BE 100%** */
  height: 50px;
}
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

Minusem tej metody jest to, że w Mobile Opera Mini nie będzie obsługiwana, a na PC działa to tylko po IE10 .

Uwaga: aby uzyskać pełną zgodność przeglądarki, w tym IE11, użyj Autoprefixera


STARA ODPOWIEDŹ

Nie myśl o tym jako o starym rozwiązaniu, wciąż jest jednym z najlepszych, jeśli chcesz mieć tylko jeden rząd elementów i będzie działać ze wszystkimi przeglądarkami.

Ta metoda jest używana przez kombinację rodzeństwa CSS , więc możesz nią manipulować również na wiele innych sposobów, ale jeśli twoja kombinacja jest zła, może również powodować problemy.

.item+.item{
  margin-left: 5px;
}

Poniższy kod załatwi sprawę. W tej metodzie nie ma potrzeby, aby dać margin: 0 -5px;do #boxowinięcia.

Działająca próbka dla Ciebie:

#box {
  display: flex;
  width: 100px;
}
.item {
  background: gray;
  width: 22px;
  height: 50px;
}
.item+.item{
 margin-left: 5px;
}
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

weBBer
źródło
Zredagowałem twoją odpowiedź opartą na siatce, aby pokazać, że działa poprawnie, nawet jeśli ostatni wiersz zawiera mniej elementów. Aby udowodnić, że w takim przypadku działa. (Możesz cofnąć, jeśli nie podoba ci się ta zmiana.)
ToolmakerSteve
Zgodnie z tym pytaniem poprosili jedynie o właściwe wypełnienie przestrzeni elementami potomnymi bez włamania, że ​​to, co zrobiłem, za pomocą siatki możemy zarządzać zgodnie z tym, grid-template-columnsco definiujemy nie dynamicznie. Więc jeśli podasz wartość, 1fr 1fr 1fr 1frto podzieli div 4fractionsi spróbuje wypełnić elementy potomne w każdym fractions, według mojej wiedzy, jest to jedyny sposób grid. To, co powiedziałem w odpowiedzi, jest takie, że jeśli użytkownik będzie musiał podzielić div na 4 i używać ich z wieloma elementami, nawet dla wielu wierszy, gidpomoże.
weBBer
69

Możesz użyć & > * + *jako selektora do emulacji flex-gap(dla pojedynczej linii):

#box { display: flex; width: 230px; outline: 1px solid blue; }
.item { background: gray; width: 50px; height: 100px; }

/* ----- Flexbox gap: ----- */

#box > * + * {
  margin-left: 10px;
}
<div id='box'>
    <div class='item'></div>
    <div class='item'></div>
    <div class='item'></div>
    <div class='item'></div>
</div>

Jeśli potrzebujesz obsługi elastycznego owijania , możesz użyć elementu opakowania:

.flex { display: flex; flex-wrap: wrap;  }
.box { background: gray; height: 100px; min-width: 100px; flex: auto; }
.flex-wrapper {outline: 1px solid red; }

/* ----- Flex gap 10px: ----- */

.flex > * {
  margin: 5px;
}
.flex {
  margin: -5px;
}
.flex-wrapper {
  width: 400px; /* optional */
  overflow: hidden; /* optional */
}
<div class='flex-wrapper'>
  <div class='flex'>
    <div class='box'></div>
    <div class='box'></div>
    <div class='box'></div>
    <div class='box'></div>
    <div class='box'></div>
  </div>
</div>

Wykonaj asynchronię
źródło
3
Czyste rozwiązanie. Działa dla dowolnej liczby elastycznych elementów potomnych.
Konrad Gałęzowski
1
Właśnie tego szukałem i działał dla mnie świetnie 👍
Paul Odeon
Należy jednak zauważyć, że *operator nie zwiększa specyficzności, jak można się spodziewać. Tak więc w zależności od istniejącego css może być konieczne zwiększenie specyficzności .flex > *selektora lub dodanie !importantdo reguły, jeśli istnieją inne selektory stosujące margines do tego elementu.
Paul Odeon
Najlepsze rozwiązanie o
o01
26

Powiedzmy, że jeśli chcesz ustawić 10pxodstęp między przedmiotami, możesz po prostu ustawić .item {margin-right:10px;}dla wszystkich i zresetować go na ostatnim.item:last-child {margin-right:0;}

Możesz także użyć selektora rodzeństwa ogólnego ~lub następnego +rodzeństwa, aby ustawić lewy margines na elementach z wyjątkiem pierwszego .item ~ .item {margin-left:10px;}lub użyj.item:not(:last-child) {margin-right: 10px;}

Flexbox jest tak sprytny, że automatycznie przelicza i równo rozprowadza siatkę.

body {
  margin: 0;
}

.container {
  display: flex;
}

.item {
  flex: 1;
  background: gray;
  height: 50px;
}

.item:not(:last-child) {
  margin-right: 10px;
}
<div class="container">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
</div>

Jeśli chcesz zezwolić na owijanie flex , zobacz następujący przykład.

body {
  margin: 0;
}

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

.item {
  flex: 0 0 calc(50% - 10px);
  background: gray;
  height: 50px;
  margin: 0 0 10px 10px;
}
<div class="container">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
</div>

Naklejki
źródło
6
To nie zadziałałoby, gdyby przedmioty były zapakowane, ponieważ :last-childnie wpływa to na każde ostatnie dziecko na końcu linii, prawda?
Flimm
2
@Flimm Dodałem podejście do pracy z Flex Wrapiem, patrz druga część powyżej.
Naklejki
Najlepsza odpowiedź dla mnie ... prosta, czysta, wydajna! Działa idealnie z Flex Wrap, dziękuję
Matthieu Marcé
16

Znalazłem rozwiązanie oparte na ogólnym selektorze rodzeństwa ~i umożliwiające nieskończone zagnieżdżanie.

Zobacz ten kodowy długopis jako działający przykład

Zasadniczo w kontenerach kolumnowych każde dziecko poprzedzone innym dzieckiem otrzymuje górny margines. Podobnie, w każdym kontenerze wiersza każde dziecko poprzedzone innym otrzymuje lewy margines.

.box {
  display: flex;
  flex-grow: 1;
  flex-shrink: 1;
}

.box.columns {
  flex-direction: row;
}

.box.columns>.box~.box {
  margin-left: 5px;
}

.box.rows {
  flex-direction: column;
}

.box.rows>.box~.box {
  margin-top: 5px;
}
<div class="box columns">
  <div class="box" style="background-color: red;"></div>
  <div class="box rows">
    <div class="box rows">
      <div class="box" style="background-color: blue;"></div>
      <div class="box" style="background-color: orange;"></div>
      <div class="box columns">
        <div class="box" style="background-color: yellow;"></div>
        <div class="box" style="background-color: pink;"></div>
      </div>
    </div>
    <div class="box" style="background-color: green;"></div>
  </div>
</div>

Simon Epskamp
źródło
Powoduje to, że przedmioty o różnych rozmiarach nie są stosowane globalnie.
Steven Vachon
Będziesz także musiał dodać dodatkowy CSS do obsługi mniejszych ekranów, ponieważ wygląda to trochę dziwnie na urządzeniach mobilnych, zastosowałbym regułę .box ~ .box na większych ekranach, a dla mniejszych ekranów ustawiłem klasę .box na maksymalną szerokość 100% i dolny margines.
rhysclay
14

Przechodząc od odpowiedzi Sawy, oto nieco ulepszona wersja, która pozwala ustawić stały odstęp między przedmiotami bez otaczającego marginesu.

http://jsfiddle.net/chris00/s52wmgtq/49/

Dołączona jest również wersja Safari „-webkit-flex”.

.outer1 {
    background-color: orange;
    padding: 10px;
}

.outer0 {
    background-color: green;
    overflow: hidden;
}

.container
{
    display: flex;
    display: -webkit-flex;
    flex-wrap: wrap;    
    -webkit-flex-wrap: wrap;
    background-color: rgba(0, 0, 255, 0.5);
    margin-left: -10px;
    margin-top: -10px;
}

.item
{
    flex-grow: 1;
    -webkit-flex-grow: 1;
    background-color: rgba(255, 0, 0, 0.5);
    width: 100px;
    padding: 10px;
    margin-left: 10px;
    margin-top: 10px;
    text-align: center;
    color: white;
}

<div class="outer1">
    <div class="outer0">
        <div class="container">
            <div class="item">text</div>
            <div class="item">text</div>
            <div class="item">text</div>
            <div class="item">text</div>
            <div class="item">text</div>
            <div class="item">text</div>
        </div>
    </div>
</div>
Chris
źródło
2
Czy to nie jest zasadniczo to samo co przykład podany w pytaniu?
br.
10

Według #ChromDevSummit istnieje implementacja gapwłaściwości Flexboksa, chociaż w tej chwili (14 listopada 2019 r.) Jest ona obsługiwana tylko w Firefoksie, ale wkrótce powinna zostać zaimplementowana w Chrome:

wprowadź opis zdjęcia tutaj

Demo na żywo

Zaktualizuję swoją odpowiedź, gdy tylko przejdzie do Chrome.

Eliya Cohen
źródło
9

Użyłem tego do kolumn owiniętych i o stałej szerokości. Kluczem jest tutajcalc()

Próbka SCSS

$gap: 10px;

dl {
  display: flex;
  flex-wrap: wrap;
  padding: $gap/2;

  dt, dd {
    margin: $gap/2;}

  dt { // full width, acts as header
    flex: 0 0 calc(100% - #{$gap});}

  dd { // default grid: four columns 
    flex: 0 0 calc(25% - #{$gap});}

  .half { // hall width columns
    flex: 0 0 calc(50% - #{$gap});}

}

Pełna próbka Codepen

Veiko Jääger
źródło
2
To wciąż dodaje rynnę przed pierwszym i po ostatnim elemencie, co PO uniemożliwia stosowanie ujemnych marginesów.
herman
2
Flexbox nie obsługuje funkcji calc () w elemencie „flex” w IE 11.
Adam Šipický
Nie mogę być zawsze używany. wyobraź sobie, czy istnieje potrzeba granicy dla bezpośrednich dzieci
Andris
9

Elastyczny pojemnik z -x (ujemna) margines i giętkie elementy z x (liczba dodatnia) marginesu lub impregnowanie zarówno prowadzić do żądanego efektu końcowego: elementy Flex ma ustaloną wielkość szczeliny 2X jedynie między sobą.

Wydaje się, że jest to po prostu kwestia preferencji, czy użyć marginesu czy wypełnienia na elementach elastycznych.

W tym przykładzie elementy elastyczne są skalowane dynamicznie w celu zachowania stałej szczeliny:

.flex-container { 
  margin: 0 -5px;
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
}

.flex-item {
  margin: 0 5px; // Alternatively: padding: 0 5px;
  flex: 1 0 auto;
}
Tim
źródło
3
Przepraszam, nie rozumiem Co nowego wprowadza twoja odpowiedź, czego nie powiedziano bezpośrednio w pytaniu?
użytkownik
Po pierwsze, chciałem podsumować, że zarówno margines, jak i dopełnienie elementu elastycznego prowadzą do pożądanego rezultatu, ponieważ istniejące odpowiedzi tylko wspominają o jednym lub drugim. Po drugie, chciałem podać przykład, w którym luki są zachowywane przez skalowanie samych elementów flex.
Tim
oto kodepen przykład pokazujący ten efekt. codepen.io/dalgard/pen/Dbnus
pedalpete,
8

W końcu dodadzą gapwłaściwość do Flexbox. Do tego czasu możesz użyć siatki CSS, która ma już gapwłaściwość i mieć tylko jeden wiersz. Ładniejsze niż zajmowanie się marżami.

Ollie Williams
źródło
Dyskusja tutaj: github.com/w3c/csswg-drafts/issues/1696 - usprawnią również nazewnictwo w CSS Grid, Flexbox i CSS Column.
Frank Lämmer,
6

gapWłaściwość CSS :

Dodano nową gapwłaściwość CSS dla układów wielokolumnowych, flexbox i układów siatki, która działa teraz w niektórych przeglądarkach! (Zobacz Czy mogę użyć linku 1 ; link 2 ).

#box {
  display: flex;
  flex-wrap: wrap;
  width: 200px;
  background-color: red;
  gap: 10px;
}
.item {
  background: gray;
  width: 50px;
  height: 50px;
}
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

W chwili pisania to działa tylko w Firefoksie. Obecnie działa w Chrome, jeśli włączysz „Włącz eksperymentalne funkcje platformy internetowej” about:flags.

Flimm
źródło
5

Korzystając z Flexboksa w moim rozwiązaniu, użyłem justify-contentwłaściwości elementu nadrzędnego (kontenera) i określiłem marginesy wewnątrz flex-basiswłaściwości elementów. Sprawdź fragment kodu poniżej:

.container {
  display: flex;
  flex-flow: row wrap;
  justify-content: space-around;
  margin-bottom: 10px;
}

.item {
  height: 50px;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #999;
}

.item-1-4 {
  flex-basis: calc(25% - 10px);
}

.item-1-3 {
  flex-basis: calc(33.33333% - 10px);
}

.item-1-2 {
  flex-basis: calc(50% - 10px);
}
<div class="container">
  <div class="item item-1-4">1</div>
  <div class="item item-1-4">2</div>
  <div class="item item-1-4">3</div>
  <div class="item item-1-4">4</div>
</div>
<div class="container">
  <div class="item item-1-3">1</div>
  <div class="item item-1-3">2</div>
  <div class="item item-1-3">3</div>
</div>
<div class="container">
  <div class="item item-1-2">1</div>
  <div class="item item-1-2">2</div>
</div>

iClusterDev
źródło
5

Dzięki Flexbox tworzenie rynien jest uciążliwe, szczególnie gdy chodzi o owijanie.

Musisz użyć ujemnych marginesów ( jak pokazano w pytaniu ):

#box {
  display: flex;
  width: 100px;
  margin: 0 -5px;
}

... lub zmień HTML ( jak pokazano w innej odpowiedzi ):

<div class='flex-wrapper'>
  <div class='flex'>
    <div class='box'></div>
    <div class='box'></div>
            ...
  </div>
</div>

... albo coś innego.

W każdym razie potrzebujesz brzydkiego hacka, aby działał, ponieważ Flexbox nie zapewnia funkcji „ flex-gap” ( przynajmniej na razie ).

Problem z rynnami jest jednak prosty i łatwy dzięki CSS Grid Layout.

Specyfikacja siatki zapewnia właściwości, które tworzą przestrzeń między elementami siatki, ignorując przestrzeń między elementami a kontenerem. Te właściwości to:

  • grid-column-gap
  • grid-row-gap
  • grid-gap (skrót dla obu nieruchomości powyżej)

Ostatnio specyfikacja została zaktualizowana, aby była zgodna z CSS Box Alignment Module , który zapewnia zestaw właściwości wyrównania do użytku we wszystkich modelach pudełek. Więc właściwości są teraz:

  • column-gap
  • row-gap
  • gap (stenografia)

Jednak nie wszystkie przeglądarki obsługujące Grid obsługują nowsze właściwości, więc użyję oryginalnych wersji w poniższej wersji demonstracyjnej.

Ponadto, jeśli potrzebny jest odstęp między przedmiotami a pojemnikiem, paddingna pojemniku działa dobrze (patrz trzeci przykład w pokazie poniżej).

Ze specyfikacji:

10.1 Rynny: te row-gap, column-gaporaz gap ogłoszenia

Właściwości row-gapi column-gap(oraz ich gapskróty), gdy są określone w kontenerze siatki, definiują rynny między rzędami siatki i kolumnami siatki. Ich składnia jest zdefiniowana w CSS Box Alignment 3 §8 Gaps Between Boxes .

Efekt tych właściwości jest taki, jakby grubość uzyskanych linii siatki: grubość linii między dwiema liniami siatki była przestrzenią między rynnami, które je reprezentują.

.box {
  display: inline-grid;
  grid-auto-rows: 50px;
  grid-template-columns: repeat(4, 50px);
  border: 1px solid black;
}

.one {
  grid-column-gap: 5px;
}

.two {
  grid-column-gap: 10px;
  grid-row-gap: 10px;
}

.three {
  grid-gap: 10px;
  padding: 10px;
}

.item {
  background: lightgray;
}
<div class='box one'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

<hr>

<div class='box two'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

<hr>

<div class='box three'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

Więcej informacji:

Michael Benjamin
źródło
4

Dlaczego nie zrobić tego w ten sposób:

.item + .item {
    margin-left: 5px;
}

Używa sąsiedniego selektora rodzeństwa , aby dać wszystkie .itemelementy, z wyjątkiem pierwszego a margin-left. Dzięki Flexbox uzyskuje się nawet równie szerokie elementy. Można to również zrobić z elementami ustawionymi pionowo i margin-topoczywiście.

Tillsanders
źródło
8
Działałoby to, o ile elementy elastyczne są zawsze w jednym rzędzie. Jeśli owijanie jest dozwolone, prawdopodobnie nie będzie wystarczające.
Nick F
4

Oto moje rozwiązanie, które nie wymaga ustawiania żadnych klas na elementach potomnych:

.flex-inline-row {
    display: inline-flex;
    flex-direction: row;
}

.flex-inline-row.flex-spacing-4px > :not(:last-child) {
    margin-right: 4px;
}

Stosowanie:

<div class="flex-inline-row flex-spacing-4px">
  <span>Testing</span>
  <span>123</span>
</div>

Tę samą technikę można zastosować do normalnych elastycznych wierszy i kolumn oprócz przykładu śródliniowego podanego powyżej i rozszerzyć o klasy dla odstępów innych niż 4px.

MK10
źródło
4

W takich przypadkach często używam operatora +

#box {
  display: flex;
  width: 100px;
}
.item {
  background: gray;
  width: 50px;
  height: 50px;
}
.item + .item {
    margin-left: 5px;
}
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

wutzebaer
źródło
3

Uważam, że najłatwiej to zrobić za pomocą wartości procentowych i po prostu pozwalając marginesowi na wyrównanie szerokości

Oznacza to, że skończysz z czymś takim, jeśli korzystasz z przykładu

#box {
   display: flex;
}

.item {
   flex: 1 1 23%;
   margin: 0 1%;
}

Oznacza to, że twoje wartości są oparte na szerokości, co może nie być dobre dla wszystkich.

lukefrake
źródło
Właśnie natrafiłem na to rozwiązanie i tak, to bardzo miłe. Działa w moim przypadku przynajmniej (długopis dla tych, którzy mogą uznać go za interesujący: codepen.io/rishatmuhametshin/pen/XXjpaV ).
rishat
2

Oto siatka elementów interfejsu użytkownika karty z odstępami wypełnionymi za pomocą elastycznego pudełka:

wprowadź opis zdjęcia tutaj

Byłem sfrustrowany ręcznym rozmieszczaniem kart przez manipulowanie marginesami i marginesami z niepewnymi wynikami. Oto kombinacje atrybutów CSS, które uważam za bardzo skuteczne:

.card-container {
  width: 100%;
  height: 900px;
  overflow-y: scroll;
  max-width: inherit;
  background-color: #ffffff;
  
  /*Here's the relevant flexbox stuff*/
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: flex-start;
  flex-wrap: wrap; 
}

/*Supplementary styles for .card element*/
.card {
  width: 120px;
  height: 120px;
  background-color: #ffeb3b;
  border-radius: 3px;
  margin: 20px 10px 20px 10px;
}
<section class="card-container">
        <div class="card">

        </div>
        <div class="card">

        </div>
        <div class="card">

        </div>
        <div class="card">

        </div>
      </section>

Mam nadzieję, że to pomaga ludziom, teraźniejszości i przyszłości.

buildpax
źródło
Aktualizacja: Ten odstęp jest skuteczny w przypadku mobilnego renderowania elementów HTML, które wymagają określonego wyrównania (np. Środek, lewo itp.). Jeśli używasz Flex Box do tworzenia aplikacji mobilnych, znalazłem ulgę w przejściu na wyrównanie oparte wyłącznie na marginesie.
buildpax,
2

Columnify - klasa solo dla N kolumn

Flexbox i SCSS

.columnify {
  display: flex;

  > * {
    flex: 1;

    &:not(:first-child) {
      margin-left: 2rem;
    }
  }
}

Flexbox i CSS

.columnify {
  display: flex;
}

.columnify > * {
  flex: 1;
}

.columnify > *:not(:first-child) {
  margin-left: 2rem;
}
<div class="columnify">
  <div style="display: inline-block; height: 20px; background-color: blue;"></div>
  <div style="display: inline-block; height: 20px; background-color: blue"></div>
  <div style="display: inline-block; height: 20px; background-color: blue"></div>
</div>

Graj z nim na JSFiddle .

zurfyx
źródło
1

#box {
  display: flex;
  width: 100px;
}
.item {
  background: gray;
  width: 50px;
  height: 50px;
}
/* u mean utility */
.u-gap-10 > *:not(:last-child) {
  margin-right: 10px;
}
<div id='box' class="u-gap-10">
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

Amo Wu
źródło
1

Wystarczy użyć .item + .itemselektora, aby dopasować od sekundy.item

#box {
  display: inline-flex;
  margin: 0 -5px;
}
.item {
  background: gray;
  width: 10px;
  height: 50px;
}

#box .item + .item {
  margin-left: 10px;
}
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

Andrew Luca
źródło
1

Zarozumiały:

  • Chcesz 4-kolumnowy układ siatki z zawijaniem
  • Liczba przedmiotów niekoniecznie jest wielokrotnością 4

Ustaw lewy margines na każdym elemencie, z wyjątkiem 1., 5., 9. i tak dalej; i ustaw stałą szerokość dla każdego elementu. Jeśli lewy margines wynosi 10 pikseli, wówczas każdy wiersz będzie miał margines 30 pikseli między 4 elementami, procentową szerokość elementu można obliczyć w następujący sposób:

100% / 4 - horizontal-border - horizontal-padding - left-margin * (4 - 1) / 4

Jest to przyzwoite obejście problemów dotyczących ostatniego rzędu Flexboksa.

.flex {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  margin: 1em 0;
  background-color: peachpuff;
}

.item {
  margin-left: 10px;
  border: 1px solid;
  padding: 10px;
  width: calc(100% / 4 - 2px - 20px - 10px * (4 - 1) / 4);
  background-color: papayawhip;
}

.item:nth-child(4n + 1) {
  margin-left: 0;
}

.item:nth-child(n + 5) {
  margin-top: 10px;
}
<div class="flex">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
</div>
<div class="flex">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
</div>
<div class="flex">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
</div>

Salman A.
źródło
1

Jest naprawdę przyjemny, schludny, tylko CSS sposób na zrobienie tego (można to uznać za „lepsze”).

Ze wszystkich zamieszczonych tutaj odpowiedzi znalazłem tylko taką, która z powodzeniem korzysta z funkcji calc () (autor: Dariusz Sikorski). Ale gdy postawiono na: „ale to się nie powiedzie, jeśli w ostatnim rzędzie są tylko 2 elementy”, żadne rozwiązanie nie zostało rozwinięte.

To rozwiązanie odpowiada na pytanie PO jako alternatywy dla ujemnych marż i rozwiązuje problem postawiony Dariuszowi.

uwagi:

  • Ten przykład pokazuje tylko 3-kolumnowy układ
  • Używa, calc()aby pozwolić przeglądarce na matematykę tak, jak chce - 100%/3 (chociaż 33,3333% powinno równie dobrze działać) i (1em/3)*2 (chociaż .66em powinien również działać dobrze) .
  • Służy ::afterdo wypełniania ostatniego wiersza, jeśli jest mniej elementów niż kolumn

.flex-container {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
}
.flex-container:after {
  content: "";
}
.flex-container > div,
.flex-container:after {
  box-sizing: border-box;
  width: calc((100%/3) - ((1em/3)*2));
}
.flex-container > :nth-child(n + 4) {
  margin-top: 1em;
}

/* the following is just to visualize the items */
.flex-container > div,
.flex-container:after {
  font-size: 2em;
}
.flex-container {
  margin-bottom:4em;
}
.flex-container > div {
  text-align: center;
  background-color: #aaa;
  padding: 1em;
}
.flex-container:after {
  border: 1px dashed red;
}
<h2>Example 1 (2 elements)</h2>
<div class="flex-container">
  <div>1</div>
  <div>2</div>
</div>

<h2>Example 2 (3 elements)</h2>
<div class="flex-container">
  <div>1</div>
  <div>2</div>
  <div>3</div>
</div>

Również na https://codepen.io/anon/pen/rqWagE

aequalsb
źródło
1

Możesz skorzystać z nowej właściwości gap. Kopiuję, wklejam wyjaśnienie, które znalazłem w tym artykule , a także więcej informacji

W układzie siatki CSS występował odstęp (wcześniej odstęp). Poprzez określenie wewnętrznego odstępu elementu zawierającego zamiast odstępu wokół elementów potomnych, odstęp rozwiązuje wiele typowych problemów z układem. Na przykład w przypadku odstępu nie musisz martwić się o marginesy na elementach potomnych, które powodują niepożądane spacje wokół krawędzi elementu zawierającego:

Niestety obecnie tylko FireFox obsługuje luki w układach elastycznych.

@use postcss-preset-env {
  stage: 0;
  browsers: last 2 versions
}

section {
  width: 30vw;
  
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(12ch, 1fr));
  
  &[flex] {
    display: flex;
    flex-wrap: wrap;
  }
  
  margin-bottom: 3rem;
}

.tag {
  color: white;
  background: hsl(265 100% 47%);
  padding: .5rem 1rem;
  border-radius: 1rem;
}

button {
  display: inline-flex;
  place-items: center;
  gap: .5rem;
  background: hsl(265 100% 47%);
  border: 1px solid hsl(265 100% 67%);
  color: white;
  padding: 1rem 2rem;
  border-radius: 1rem;
  font-size: 1.25rem;
}

body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
<section>
  <h1>Grid</h1> 
  <div class="tag">Awesome</div>
  <div class="tag">Coo</div>
  <div class="tag">Rad</div>
  <div class="tag">Math</div>
</section>
<br>
<section flex>
  <h1>Flex</h1>
  <div class="tag">Awesome</div>
  <div class="tag">Coo</div>
  <div class="tag">Rad</div>
  <div class="tag">Math</div>
</section>

Andres Paul
źródło
gapbyło już zalecane w odpowiedzi tutaj stackoverflow.com/a/58041749/2756409 Ponadto nie jest to CSS.
TylerH
0

Nie będzie to działać w każdym przypadku, ale jeśli masz elastyczne szerokości potomne (%) i znasz liczbę elementów w rzędzie, możesz bardzo dokładnie określić marginesy niezbędnych elementów, używając nth-child selektora / ów.

Zależy to w dużej mierze od tego, co rozumiesz przez „lepszy”. W ten sposób nie wymaga dodatkowego znacznika opakowania dla elementów potomnych lub elementów ujemnych - ale oba te elementy mają swoje miejsce.

section {
  display: block
  width: 100vw;
}
.container {
  align-content: flex-start;
  align-items: stretch;
  background-color: #ccc;
  display: flex;
  flex-flow: row wrap;
  justify-content: flex-start;
  width: 100%;
}

.child-item {
  background-color: #c00;
  margin-bottom: 2%;
  min-height: 5em;
  width: 32%;
}

.child-item:nth-child(3n-1) {
  margin-left: 2%;
  margin-right: 2%;
}
<html>
  <body>
      <div class="container">
        <div class="child-item"></div>
        <div class="child-item"></div>
        <div class="child-item"></div>
        <div class="child-item"></div>
        <div class="child-item"></div>
        <div class="child-item"></div>
        <div class="child-item"></div>
      </div>
   </body>
</html>

jnmrobinson
źródło
Nie reaguje Działa tylko dla rodzica o stałej szerokości.
Zielony
1
OP nie prosi o elastyczne rozwiązanie, a ich przykład używa stałej szerokości. Biorąc pod uwagę, że używa to wartości%, łatwo jest argumentować, że jest to responsywne, ponieważ elementy dostosują się do rozmiaru elementu nadrzędnego, który jest ustawiony procentowo.
jnmrobinson
0

Natrafiłem wcześniej na ten sam problem, a potem natknąłem się na odpowiedź na to pytanie. Mam nadzieję, że pomoże to innym w przyszłości.

długa odpowiedź krótka, dodaj ramkę do elementów elastycznych dziecka. następnie możesz określić marginesy między elementami elastycznymi do tego, co chcesz. We fragmencie używam czarnego do celów ilustracyjnych, możesz użyć „przezroczystego”, jeśli chcesz.

#box {
  display: flex;
  width: 100px;
  /* margin: 0 -5px; *remove this*/
}
.item {
  background: gray;
  width: 50px;
  height: 50px;
  /* margin: 0 5px; *remove this*/
  border: 1px solid black; /* add this */
}
.item.special{ margin: 0 10px; }
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item special'></div>
</div>

Strojenie
źródło
0

Sztuczka z ujemnym marginesem na kontenerze pudełkowym działa po prostu świetnie. Oto kolejny przykład świetnie działający z zamówieniem, pakowaniem i co nie.

.container {
   border: 1px solid green;
   width: 200px;
   display: inline-block;
}

#box {
  display: flex;
  flex-wrap: wrap-reverse;
  margin: -10px;
  border: 1px solid red;
}
.item {
  flex: 1 1 auto;
  order: 1;
  background: gray;
  width: 50px;
  height: 50px;
  margin: 10px;
  border: 1px solid blue;
}
.first {
  order: 0;
}
<div class=container>
<div id='box'>
  <div class='item'>1</div>
  <div class='item'>2</div>
  <div class='item first'>3*</div>
  <div class='item'>4</div>
  <div class='item'>5</div>
</div>
</div>

Cghislai
źródło