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.
Related
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
I would like to create a vertical layout with flexbox.
Here is the structure :
.container {
display: flex;
flex-direction: column;
}
<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 class="child">7</div>
<div class="child">8</div>
</div>
And it should display 6 items per column
1 7
2 8
3
4
5
6
For the structure to break into a new column, it needs to know the limit to which it can fit its contents.
To make it clear, think of a simple paragraph tag with some text. Once the text exceeds the width of the page (or the container), the excess text wraps to the next line. So, in case of rows, width can be set as the limit, which is by default 100% of the viewport width or 100% of the container's width.
But here as we are dealing with columns and it takes height as the limit, the challenge here arises as the height is limitless in a HTML document. Because the height of a page increases to any extend when the content increases along with the vertical scroll bar. (Note that the same can be made possible in case of width with overflow a horizontal scroll bar, but here we are talking about the default behaviour).
Therefore, in this situation, to break the contents into a new column is only possible (exception with CSS grid) if we specify a height to the container.
It can either be specified in pixels or rem as mentioned in other answers.
Or if you are looking for a behaviour equivalent to the rows' as mentioned above, you can resort to viewport-height similar to viewport-width in case of rows. PEN
body {
margin: 0;
}
.container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 100vh;
}
.child {
height: 16.667vh;
}
Please note that this is not a perfect solution as it could cause misalignment when the content exceeds the height and also have browser compatibility issues. Also you may consider CSS grid or try Javascript solutions to perfectly tackle this scenario.
Hope this helps.
Try this style:
.container {
display: flex;
flex-direction: column;
height: 112px;
flex-wrap: wrap;
}
What I did here is set height to the container div so that the flex items wrap to the next column when it overflows. For this you need to set flex-wrap: wrap; too. In this case, height: 112px caused the overflow. You can change it as per your requirements.
The height is dynamic, base on the number of items you want to control vertically (in this case 6), I have calculated the height base on a 1rem font-size:
Example for 6 items:
.container {
display: flex;
flex-flow: column wrap;
font-size: 1rem;
max-height: calc(6 * 1.2em);
}
<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 class="child">7</div>
<div class="child">8</div>
</div>
Example for 7 items:
.container {
display: flex;
flex-flow: column wrap;
font-size: 1rem;
max-height: calc(7 * 1.2em);
}
<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 class="child">7</div>
<div class="child">8</div>
</div>
As the OP agreed to accept a CSS Grid solution, here is one:
.container {
display: grid;
}
.child:nth-child(6n + 2) {
grid-row-start: 2;
}
.child:nth-child(6n + 3) {
grid-row-start: 3;
}
.child:nth-child(6n + 4) {
grid-row-start: 4;
}
.child:nth-child(6n + 5) {
grid-row-start: 5;
}
.child:nth-child(6n) {
grid-row-start: 6;
}
PEN - Hope this helps.
I have a main <div> container, consisting of 3 child <div>'s:
<div id="parent">
<div id="child-left">.. some markup ..</div>
<div id="child-flex>
<div id="flex-child-1">
<div id="flex-child-2">
<div id="flex-child-3">
<div id="flex-child-4">
</div>
<div id="child-right">.. some markup ..</div>
</div>
child-left is display:inline and float:left, with a fixed
set width
child-right is display:inline and float:right,
with a fixed set width
child-flex is display:inline-flex
I would like to achieve the following:
Get the child-flex container to display inline in between child-left and child-right, and take up any remaining space.
Get all the flex-child- children to have equal width within the child-flex container. At the moment I have set flex: 1 0 auto;, but it does not seem to work. Could be because of the parent?
Just use flexbox throughout...in this case, use display:flex on the parent and then make the #child-flex flex-container a nested flexbox.
No need to use floats at all.
Codepen Demo
#parent {
display: flex;
height: 100px;
}
#child-right,
#child-left {
flex: 0 0 100px;
background: pink;
}
#child-flex {
flex: 1;
background: lightblue;
display: flex;
}
.flex-child {
flex: 1;
border: 1px solid grey;
}
<div id="parent">
<div id="child-left">some markup</div>
<div id="child-flex">
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
</div>
<div id="child-right">some markup</div>
</div>
Ive been struggling finding the right solution to this.
say you have 6 divs all different height varying content etc.
in responsive design at a 1080p screen all 6 divs fit on one row... but when the page gets small enough it changes to 3 on each row.
problem is say the second div, is the tallest out of the 1,2,3 divs then 4 5 and 6 divs get shifted out of place
Meaning the 4th div doesnt end up in line with the first div (column wise), how would you make this happen? to ensure the content ends up in the right place no matter what.
<style>
#maincontent { width: 100%; }
.content{ width: 33%; float:left;}
</style>
<div id="maincontent">
<div class="content">a</div>
<div class="content">I have a lot more content so i'm taller</div>
<div class="content">a</div>
<div class="content">I try to float left but can't get inline with the first child</div>
<div class="content">a</div>
<div class="content">a</div>
</div>
You can use the clear property:
This property indicates which sides of an element's box(es) may not be
adjacent to an earlier floating box.
Values other than 'none' potentially introduce clearance. [...] It
is used to push the element vertically past the float.
.content:nth-child(3n + 1) {
clear: left;
}
.content {
width: 33.3%;
float: left;
}
.content:nth-child(3n + 1) {
clear: left;
}
<div id="maincontent">
<div class="content">a</div>
<div class="content">I have a lot more content so i'm taller</div>
<div class="content">a</div>
<div class="content">I try to float left but can't get inline with the first child</div>
<div class="content">a</div>
<div class="content">a</div>
</div>
Alternatively, there is the amazing flexbox:
#maincontent {
display: flex; /* Magic begins */
flex-wrap: wrap; /* Multiline */
}
.content { width: 33.3%; }
#maincontent {
display: flex; /* Magic begins */
flex-wrap: wrap; /* Multiline */
}
.content {
width: 33.3%;
}
<div id="maincontent">
<div class="content">a</div>
<div class="content">I have a lot more content so i'm taller</div>
<div class="content">a</div>
<div class="content">I try to float left but can't get inline with the first child</div>
<div class="content">a</div>
<div class="content">a</div>
</div>
I'm looking for a CSS solution to the following:-
<div style="display:inline;">
<div>The content of this div is dynamically created but will always be wider than
the below div.
</div>
<div> Need this div to have the same width as the above div.
</div>
</div>
The wrapper div has an inline display and works as expected, both child divs have dynamically generated content. I need the bottom one to take the width of the previous sibling.
Many thanks for any suggestions in advance.
Here's another Flexbox solution which allows for the second child to wrap to match the width of the variable height sibling.
.wrapper > div {
border: 1px solid;
}
.child {
display: flex;
}
.child div {
flex-grow: 1;
width: 0;
}
.wrapper {
display: inline-block;
}
<div class="wrapper">
<div>This div is dynamically sized based on its content</div>
<div class="child"><div>This div will always be the same width as the preceding div, even if its content is longer (or shorter too).</div></div>
</div>
Edit:
To support multiple divs under .child, where each div is on its own line, add break-after: always; ...
.child div {
flex-grow: 1;
width: 0;
break-after: always;
}
Floats and tables are so 2000 and late. With today's browsers we can make the two sibling DIVs match each other's width, regardless which is bigger/smaller.
Here's a Flexbox solution fit for 2016:
.wrapper {
display: inline-block;
}
.parent {
display: flex;
flex-direction: column;
}
/* For visualization */
.child {
border: 1px solid #0EA2E8;
margin: 2px;
padding: 1px 5px;
}
<div class="wrapper">
<div class="parent">
<div class="child">Child number one</div>
<div class="child">Child #2</div>
</div>
</div>
Set your div to display:inline-block instead, this way your div will expand with the content inside of it.
http://jsfiddle.net/CpKDX/
2023 keep it simple...
Use grid and the fr unit. Then you can split up into as many equally sized rows or columns as you want:
.container {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-column-gap: 1em;
}
.container > div {
border: 1px solid black;
padding: 0.5em;
}
<div class="container">
<div>I'm a part of a grid. I will be split up into equal parts with my other sibling(s) depending on how many columns the grid is given.</div>
<div>I am a sibling element.</div>
</div>
Here is still a flexbox-based approach.
The essential idea: in an outermost wrapper, elements that need to be of equal width are wrapped into another wrapper.
.wrapper {
display: inline-block;
}
.flex-wrapper {
display: flex;
flex-direction: column;
}
.demo-bar {
height: 4px;
background-color: deepskyblue;
}
<div class="wrapper">
<div class="flex-wrapper">
<div contenteditable>Some editable text.</div>
<div class="demo-bar"></div>
</div>
</div>
Another practical example: an adaptive progress bar with the same width below a media (video or audio) element.
video.addEventListener("timeupdate", () =>
progress.style.width = `${video.currentTime / video.duration * 100}%`
)
.wrapper {
display: flex;
flex-direction: column;
position: relative;
align-items: center;
}
video {
display: block;
max-width: 100%;
}
.progress-bar {
height: 0.25rem;
background: #555;
}
#progress {
width: 0%;
height: 100%;
background-color: #595;
}
<div class="wrapper">
<div data-css-role="wrapper">
<video id="video" controls>
<source src="https://raw.githubusercontent.com/mdn/interactive-examples/master/live-examples/media/cc0-videos/flower.webm">
</video>
<div class="progress-bar">
<div id="progress"></div>
</div>
</div>
</div>
UPDATE: This works with me, I've just tried it:
<div style="max-width:980px;border:1px solid red;">
<div style="background:#EEE;float:left;">
<div style="width:auto;border:1px solid blue;float:left;">If you use 100% here, it will fit to the width of the mother div automatically.</div>
<div style="border:1px solid green;"> The div will be 100% of the mother div too.</div>
</div>
<div style="clear:both;"></div>
</div>
Is this what you want? The borders and background are just to show the divs ;)
Just go like this:
Let's say you want the whole divs be max. 980px (otherwise just leave that out or replace with 100%)...
<div style="max-width:980px;">
<div style="width:100%;">If you use 100% here, it will fit to the width of the mother div automatically.
</div>
<div style="width:100%;"> The div will be 100% of the mother div too.
</div>
</div>
The second option would be, to use one more div... or you use style="width:auto;" for the dynamic div...
Not sure if I understood what you are trying to do, but looks like setting a 100% width to the last div should work:
<div style="width:100%;">
BTW the style in the first div is not well defined, you should use a colon instead of a equal sign in the properties definition:
<div style="display:inline;">
If your willing to give up on a couple of <div>s then I have the solution for you:
<div style=“display: inline-block;”>
<table>
<tr>
<td>The table automatically makes its siblings the same width</td>
</tr>
<tr>
<td>So this will be as wide</td>
</tr>
</table>
</div>
Remember to set the div display:inline-block;