How to add a space (as in gutter) between flex items? [duplicate] - html

I'm trying to create some kind of universal component of flex container. This component consists of container and its children in a row.
If there are too many children in a line, those who don't have enough space go to second line. It can be easily achieved with flexbox, but also I want to be able to set gutter between elements. And first and last elements of a line shouldn't have left and right margin respectively.
I do this using negative margin technique, but the problem here is that right margin can provoke overflow issues if container is too big. I can solve this problem adding overflow: hidden to cut off negative margin, but it provokes problem with overflowing items inside container (drop-downs, etc).
So now I'm looking for silver bullet, implementation which can satisfy this requirements:
There are multiple items in a row. Width of items can differ.
If some items have not enough space, they go to next line.
There is a gap between items (margin), and first and last item doesn't have left and right margin, respectively.
Inside container can be placed overflowing content (drop-downs), so I can't use overflow: hidden
Css grid and flexbox can be used
Here is my solution of this problem:
https://jsbin.com/gabumax
And here code from example:
.container {
overflow: hidden;
}
.wrapper {
margin: -10px;
display: flex;
flex-wrap: wrap;
}
.item {
flex: 0 0 auto;
padding: 10px;
background-color: red;
margin: 10px;
}
<div class="container">
<div class="wrapper">
<div class="item">Width of items can vary</div>
<div class="item">This example works</div>
<div class="item">But there is a problem</div>
<div class="item">Dye to overlow:hidden</div>
<div class="item">It is impossible to place here</div>
<div class="item">Overflowing content</div>
<div class="item">Such as dropdowns</div>
</div>
</div>
It works, but the only negative point here is overlow: hidden. Because of this I can't place here dropdowns and other overflowing content.
Any better solution? Thanks in advance.

Use gap / row-gap / column-gap:
.wrapper {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
See more here

To avoid the scrollbar to show, you may set your negative margin on the left and top only.
body {
margin: 0;
}
.container {
width:31.7em;
max-width:100%;
margin:auto;;
background:yellow;
}
.wrapper {
display: flex;
flex-wrap: wrap;
margin-left:-10px;
margin-top:-10px;
}
.item {
flex: 0 0 auto;
padding: 10px;
background-color: red;
margin:10px 0 0 10px;
}
<div class="container">
<div class="wrapper">
<div class="item">Width of items can vary</div>
<div class="item">This example works</div>
<div class="item">But there is a problem</div>
<div class="item">Dye to overlow:hidden</div>
<div class="item">It is impossible to place here</div>
<div class="item">Overflowing content</div>
<div class="item">Such as dropdowns</div>
</div>
</div>
or negative right margin if document dir is rtl
body {
margin: 0;
direction:rtl;
}
.container {
width:31.7em;
max-width:100%;
margin:auto;;
background:yellow;
}
.wrapper {
display: flex;
flex-wrap: wrap;
margin-right:-10px;
margin-top:-10px;
}
.item {
flex: 0 0 auto;
padding: 10px;
background-color: red;
margin:10px 10px 0 0;
}
<div class="container">
<div class="wrapper">
<div class="item">Width of items can vary</div>
<div class="item">This example works</div>
<div class="item">But there is a problem</div>
<div class="item">Dye to overlow:hidden</div>
<div class="item">It is impossible to place here</div>
<div class="item">Overflowing content</div>
<div class="item">Such as dropdowns</div>
</div>
</div>

Flexbox isn't your best option here. As you describe, gutter solutions are clumsy and inefficient.
A clean and efficient solution is possible with CSS Grid.
Grid wins over flexbox in this area for now because Grid accepts the gap properties. These properties are not yet available in flex but, as browsers continue to implement the CSS Box Alignment Module, the gap properties will be available across multiple box models (including flex).
§ Gaps Between Boxes
While margin and padding can be used to specify visual spacing
around individual boxes, it’s sometimes more convenient to globally
specify spacing between adjacent boxes within a given layout context,
particularly when the spacing is different between boxes as opposed to
between the first/last box and the container’s edge.
The gap property, and its row-gap and column-gap sub-properties,
provide this functionality for multi-column, flex, and grid layout.
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-auto-rows: 50px;
grid-gap: 10px;
}
.item {
padding: 10px;
background-color: red;
}
body {
margin: 0;
}
<div class="container">
<div class="wrapper">
<div class="item">Width of items can vary</div>
<div class="item">This example works</div>
<div class="item">But there is a problem</div>
<div class="item">Dye to overlow:hidden</div>
<div class="item">It is impossible to place here</div>
<div class="item">Overflowing content</div>
<div class="item">Such as dropdowns</div>
</div>
</div>
jsFiddle demo

Related

div Margins with display: inline-block [duplicate]

This question already has answers here:
Better way to set distance between flexbox items
(40 answers)
Closed 9 months ago.
I'm trying to manipulate divs without using float, using display: inline-block; in my css allows me to get the siblings next to each other within a container div, but with inline-block, I can't space them apart using margin-left: 20px;, margin-right :20px; ... and so on.
I'm sure there's a really simple solution, even if it doesn't involve using display: inline-block;, I just want to avoid floats and preferably avoid padding too.
you can try flex-box method to create space between two div which is inside a div (I conclude that from your question )
.parent{
border:2px solid red;
display:flex;
justify-content:space-around;
}
.parent div{
border:3px solid black;
}
<div class="parent">
<div class="child1">
child1
</div>
<div class="child2">
child2
</div>
</div>
you can also add many child div as you want , they will automatically make place in the parent container.
Here you can see below how i managed to do so without display:inline-block; and this will not break on any device unlike inline-block.
.box {
width: 200px;
height: 200px;
background: #F3F3F3;
color: #000;
display: flex;
align-items: center;
justify-content: center;
margin-left: 20px;
}
.container {
display: flex;
margin-bottom: 40px;
}
.container.two {
justify-content: space-between;
}
.container.three {
justify-content: space-evenly;
}
Margin 20px in between
<div class="container">
<div class="box">
BOX 1
</div>
<div class="box">
BOX 1
</div>
</div>
Align boxes on left and right according to width
<div class="container two">
<div class="box">
BOX 1
</div>
<div class="box">
BOX 1
</div>
</div>
Align even spacing on left and right
<div class="container three">
<div class="box">
BOX 1
</div>
<div class="box">
BOX 1
</div>
</div>

Different number of divs based on how large is the screen best practices?

I am having a problem regarding elements inside a flex box. I am using flex: 1 1 auto with flex-flow: column wrap. I want to show a number of divs whose size increases along with that of the screen.
Using media queries would be so confusing and the code would be so large. I am searching for a way to achieve it without using media queries because the size of each div in the flex is about 200px each, I would need to make a lot of media queries incrementing from low to high resolutions.
The min-width property is rather useful here. I put fifteen divs to show the effect on multiple screen sizes.
.flex-parent {
display: flex;
flex-wrap: wrap; /* this makes the divs wrap */
}
.flex-child {
margin: 3px;
background-color: lightblue;
min-width: 200px; /*prevents the flex-child from shrinking more than 200px */
height: 50px;
flex: auto; /* this auto-adjusts the width */
/* Everything after this is just to align everything to the center */
padding-top: 20px;
text-align: center;
}
<div class='flex-parent'>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
</div>
Use flex-flow: row wrap.
If you want to show more div elements as the screen gets wider, you’ll want to use row for flex-direction, not column. With flex-direction: row, the flex items will be put into each line from left to right, like a line of text. And the bigger the screen, the more items will fit.
If you want your flex items to grow and fill all the available space, use flex: auto. This might mean the items end up with different sizes, because you can have a different number of items in each flex line. If you want all of them to be the same size, you could set something like flex: 200px.
.flex-container {
display: flex;
flex-flow: row wrap;
gap: 8px;
}
.flex-item {
flex: auto;
padding: 32px;
background-color: bisque;
}
<div class="flex-container">
<div class="flex-item">One</div>
<div class="flex-item">Two</div>
<div class="flex-item">Three</div>
<div class="flex-item">Four</div>
<div class="flex-item">Five</div>
<div class="flex-item">Six</div>
<div class="flex-item">Seven</div>
<div class="flex-item">Eight</div>
<div class="flex-item">Nine</div>
<div class="flex-item">Ten</div>
<div class="flex-item">Eleven</div>
<div class="flex-item">Twelve</div>
</div>
If you want to arrange the div elements as columns (top to bottom), then your flex container needs to have a height set on it, for example height: 500px. This is so that the flex container can calculate how many flex items can fit into each column.
.flex-container {
display: flex;
flex-flow: column wrap;
height: 100vh;
gap: 8px;
}
.flex-item {
flex: auto;
padding: 32px;
background-color: bisque;
}
<div class="flex-container">
<div class="flex-item">One</div>
<div class="flex-item">Two</div>
<div class="flex-item">Three</div>
<div class="flex-item">Four</div>
<div class="flex-item">Five</div>
<div class="flex-item">Six</div>
<div class="flex-item">Seven</div>
<div class="flex-item">Eight</div>
<div class="flex-item">Nine</div>
<div class="flex-item">Ten</div>
<div class="flex-item">Eleven</div>
<div class="flex-item">Twelve</div>
</div>

How to set gaps (gutters) in a flex container?

I'm trying to create some kind of universal component of flex container. This component consists of container and its children in a row.
If there are too many children in a line, those who don't have enough space go to second line. It can be easily achieved with flexbox, but also I want to be able to set gutter between elements. And first and last elements of a line shouldn't have left and right margin respectively.
I do this using negative margin technique, but the problem here is that right margin can provoke overflow issues if container is too big. I can solve this problem adding overflow: hidden to cut off negative margin, but it provokes problem with overflowing items inside container (drop-downs, etc).
So now I'm looking for silver bullet, implementation which can satisfy this requirements:
There are multiple items in a row. Width of items can differ.
If some items have not enough space, they go to next line.
There is a gap between items (margin), and first and last item doesn't have left and right margin, respectively.
Inside container can be placed overflowing content (drop-downs), so I can't use overflow: hidden
Css grid and flexbox can be used
Here is my solution of this problem:
https://jsbin.com/gabumax
And here code from example:
.container {
overflow: hidden;
}
.wrapper {
margin: -10px;
display: flex;
flex-wrap: wrap;
}
.item {
flex: 0 0 auto;
padding: 10px;
background-color: red;
margin: 10px;
}
<div class="container">
<div class="wrapper">
<div class="item">Width of items can vary</div>
<div class="item">This example works</div>
<div class="item">But there is a problem</div>
<div class="item">Dye to overlow:hidden</div>
<div class="item">It is impossible to place here</div>
<div class="item">Overflowing content</div>
<div class="item">Such as dropdowns</div>
</div>
</div>
It works, but the only negative point here is overlow: hidden. Because of this I can't place here dropdowns and other overflowing content.
Any better solution? Thanks in advance.
Use gap / row-gap / column-gap:
.wrapper {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
See more here
To avoid the scrollbar to show, you may set your negative margin on the left and top only.
body {
margin: 0;
}
.container {
width:31.7em;
max-width:100%;
margin:auto;;
background:yellow;
}
.wrapper {
display: flex;
flex-wrap: wrap;
margin-left:-10px;
margin-top:-10px;
}
.item {
flex: 0 0 auto;
padding: 10px;
background-color: red;
margin:10px 0 0 10px;
}
<div class="container">
<div class="wrapper">
<div class="item">Width of items can vary</div>
<div class="item">This example works</div>
<div class="item">But there is a problem</div>
<div class="item">Dye to overlow:hidden</div>
<div class="item">It is impossible to place here</div>
<div class="item">Overflowing content</div>
<div class="item">Such as dropdowns</div>
</div>
</div>
or negative right margin if document dir is rtl
body {
margin: 0;
direction:rtl;
}
.container {
width:31.7em;
max-width:100%;
margin:auto;;
background:yellow;
}
.wrapper {
display: flex;
flex-wrap: wrap;
margin-right:-10px;
margin-top:-10px;
}
.item {
flex: 0 0 auto;
padding: 10px;
background-color: red;
margin:10px 10px 0 0;
}
<div class="container">
<div class="wrapper">
<div class="item">Width of items can vary</div>
<div class="item">This example works</div>
<div class="item">But there is a problem</div>
<div class="item">Dye to overlow:hidden</div>
<div class="item">It is impossible to place here</div>
<div class="item">Overflowing content</div>
<div class="item">Such as dropdowns</div>
</div>
</div>
Flexbox isn't your best option here. As you describe, gutter solutions are clumsy and inefficient.
A clean and efficient solution is possible with CSS Grid.
Grid wins over flexbox in this area for now because Grid accepts the gap properties. These properties are not yet available in flex but, as browsers continue to implement the CSS Box Alignment Module, the gap properties will be available across multiple box models (including flex).
§ Gaps Between Boxes
While margin and padding can be used to specify visual spacing
around individual boxes, it’s sometimes more convenient to globally
specify spacing between adjacent boxes within a given layout context,
particularly when the spacing is different between boxes as opposed to
between the first/last box and the container’s edge.
The gap property, and its row-gap and column-gap sub-properties,
provide this functionality for multi-column, flex, and grid layout.
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-auto-rows: 50px;
grid-gap: 10px;
}
.item {
padding: 10px;
background-color: red;
}
body {
margin: 0;
}
<div class="container">
<div class="wrapper">
<div class="item">Width of items can vary</div>
<div class="item">This example works</div>
<div class="item">But there is a problem</div>
<div class="item">Dye to overlow:hidden</div>
<div class="item">It is impossible to place here</div>
<div class="item">Overflowing content</div>
<div class="item">Such as dropdowns</div>
</div>
</div>
jsFiddle demo

Making container div exact size of wrapping contents [duplicate]

This question already has answers here:
CSS when inline-block elements line-break, parent wrapper does not fit new width
(2 answers)
How to remove the space between inline/inline-block elements?
(41 answers)
Closed 4 years ago.
I have a container div that has child divs with fixed widths and wraps. What I realised is that the container's width doesn't fit tightly to the content after it wraps, usually leaving a 'ghost' space on the right. Is there a way to force it to readjust the width according to its content?
.container {
max-width: 12em;
background-color: black;
}
.child {
display: inline-block;
width: 5em;
background-color: red;
}
<div class="container">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
</div>
So in this case when the child wraps after 2 of them add up to 10em, the container instead of being 10em, it is still 12em. And if the window size forces it down to a single div wrapping, the container rather than being 5em, could be 6em, 7em, 8em, etc depending on window width.
Is there a way to get rid of the 'ghost' space and make the container fit exactly to how the child is wrapping and it's total width?
Note: I am not talking about the extra space in between each child element. I'm referring to the giant gap left in the container, which causes the container to not accurately reflect the size of its child content. I understand that I can simply count how many child can fit in 12em and change the container width to be 10em to fit 2 childs perfectly. But I want that to be flexible. Is that possible?
The extra space after each child element is a result of the display: inline-block property and is due to the literal whitespace between each div in your HTML. You may verify this by removing the linebreaks between child divs so that their open and close tags are back-to-back:
<div class="container">
<div class="child">1</div><div class="child">2</div><div class="child">3</div>/*...*/
</div>
Although this will eliminate the pesky whitespace, it comes at the expense of code clarity/readability and is surely an irritating way to write HTML.
In my experience, often the best solution to this issue is to set the parent container to display: flex:
.container {
display: flex;
flex-wrap: wrap;
max-width: 10em;
background-color: black;
}
.child {
display: inline-block;
width: 5em;
background-color: red;
}
<div class="container">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div><div class="child">5</div>
<div class="child">6</div>
</div>
In this case you will also need to provide the flex-wrap: wrap property to inform the flex container to wrap its contents. Presumably you can now update the container's max-width property to 10em to fit exactly the width of two child elements so I've taken the liberty of this change in the code snippet.
Looks like you want to render a table. So you may want to use:
<table>
<tr>
<td>Col1</td>
<td>Col2</td>
</tr>
...
</table>
In case im wrong:
You can do this with flex or grid
Helpful link Flexbox, Grid
.container {
max-width: 12em;
background-color: black;
display: flex;
}
.child {
display: block;
min-width: 5em;
background-color: red;
border: 1px dashed blue;
}
/* FLEX */
.container-flex {
/* new row if next element doesnt fit */
flex-wrap: wrap;
}
.container-flex .child {
/* makes children grow evenly after wrapping */
flex-grow: 1;
}
/* GRID */
.container-grid {
display: grid;
/* 2 auto-horizontally sized colums */
grid-template-columns: auto auto;
}
.container-grid .child {
/* noting to do here */
}
<div style='float: left; margin-right: 10px;'>
Flex<br>
<small>extend elements to 6em</small><br>
<hr>
<div class="container container-flex">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
</div>
</div>
<div style='float: left; margin-right: 10px;'>
Grid<br/>
<small>collapse container to 10em</small><br>
<hr>
<div class="container container-grid">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
</div>
</div>
You can do it like this
.container { max-width: 4.5em;background-color: black; }
.child { display: inline-block; width:cover; background-color: red; }
<!DOCTYPE html>
<html>
<head>
<title>Answer</title>
</head>
<body>
<div class="container">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
</div>
With the width set to 'cover' it covers the complete area leaving no space.In order to fix the black background (of container which is more or less acting like border), you can manually adjust it's size.

How to create a div that expands while centered until it hits a right margin (no left margin)? [duplicate]

#michael-benjamin Center and right align flexbox elements almost what I want, but with 2 differences:
Div have to take empty space at left side too (when it be wide)
Div have to collapse text when there is no empty space around at all.
What I have?
A is main centered object and BBBBBBBBBBBBBBB is right object.
This is fine till A will grow:
What I want?
Is it possible to do with flex/grid/table-tr-td/any other css tricks?
What I tried?
CSS Positioning Properties - can't stop when grow to B
Flex Auto Margins & Invisible Flex Item (DOM element) - invisible item don't give empty space at left side
CSS Grid Layout - 1fr don't give empty space at left side
CSS grid can do it like below:
.container {
margin: 10px;
display: grid;
grid-template-columns: 1fr minmax(0,max-content) 1fr;
color: #fff;
}
.container::before {
content:"";
}
.b {
margin-left: auto;
background: grey;
}
.a {
margin: auto;
background: blue;
overflow:hidden;
text-overflow:ellipsis;
max-width:100%;
}
body {
background:linear-gradient(red,red) center/ 2px 100% no-repeat;
}
<div class="container">
<div class="a">AA</div>
<div class="b">BBBBBBBBBBBBBBBB</div>
</div>
<div class="container">
<div class="a">AA</div>
<div class="b">BBBBBBBBBBBBBBBB</div>
</div>
<div class="container">
<div class="a">AAAAAAAAAAAAAA</div>
<div class="b">BBBBBBBBBBBBBBBB</div>
</div>
<div class="container">
<div class="a">AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</div>
<div class="b">BBBBBBBBBBBBBBBB</div>
</div>
<div class="container">
<div class="a">AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</div>
<div class="b">BBBBBBBBBBBBBBBB</div>
</div>