Flex container not adjusting to content [duplicate] - css

This question already has answers here:
When flexbox items wrap in column mode, container does not grow its width
(9 answers)
Closed 5 years ago.
I learned here:
Multi columns list by css
how to make a self adjusting multi column list. However there is one problem left: The container doesn't adjust it's width to it's content:
https://jsfiddle.net/rkofktdz/3/
ul {
height: 40px;
display:inline-flex;
flex-direction: column;
flex-wrap: wrap;
border: 2px solid black;
background-color: grey;
padding: 0;
}
li {
list-style: none;
}
a {
display: inline-block;
width: 60px;
}
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>item 4</li>
</ul>
I can extend the container (ul) by applying a fixed width but I would like to have it self adjusting.
This is part of a three level menu being a bit more complex:
http://nachrichtentisch.de/

Please check if this is what you wanted to achieve:
https://jsfiddle.net/rkofktdz/4/
ul {
display:flex;
flex-wrap: wrap;
}
li {
list-style: none;
flex-direction: column;
display: flex;
border: 2px solid black;
background-color: grey;
height: 40px;
padding: 0;
margin: 0 10px;
}
a {
display: inline-block;
width: 60px;
}

Related

Make each column in a flex-direction:column flex-wrap:wrap list be no wider than it needs to be

This fiddle largely works as intended, other than it seems to fill all the available width when it can:
https://jsfiddle.net/d16ba2re/2/
CSS:
ul {
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 100px;
padding: 0;
margin: 0
}
li {
background: white;
border: 1px solid #ccc;
list-style: none;
padding: 0;
margin: 0
}
justify-content doesn't seem to make any difference, no matter what I set it to.
Is there a simple trick to achieve what I'm looking for here, or am I out of luck?
I guess you're looking for the align-content property with the value of your choice, here with the flex-start:
ul {
display: flex;
flex-direction: column;
flex-wrap: wrap;
align-content: flex-start;
height: 100px;
padding: 0;
margin: 0
}
li {
background: white;
border: 1px solid #ccc;
list-style: none;
padding: 0;
margin: 0;
}
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
<li>Four</li>
<li>Five</li>
<li>Six</li>
<li>Seven</li>
<li>Eight</li>
<li>Nine</li>
<li>Ten</li>
<li>Eleven</li>
<li>Twelve</li>
<li>Thirteen</li>
<li>Fourteen</li>
<li>Fifteen</li>
<li>Sixteen</li>
<li>Seventeen</li>
<li>Eighteen</li>
<li>Nineteen</li>
<li>Twenty</li>
<li>Twenty one</li>
<li>Twenty two</li>
<li>Twenty three</li>
</ul>
I'll probably start a new question, but in case this is another dead-simple query for you... I also have problems when wrapping that in a float:right . I'd expect the div to fully contain the ul, but the reality is that it bleeds out of it. jsfiddle.net/d16ba2re/3
Set a proper width to your div. I tried 295px and it seems alright.

Same width tabs based on largest content side by side

So the conditions that I would like to achieve is
Width of each tab is based on the label
All tabs are the same size as the longest tab (with longest label)
As such the tab group should not be fixed or take up 100% of parent. Should be based on longest tab.
The layout of the tabs are side by side.
This is my progress so far (not same width as largest): https://jsfiddle.net/cyhwx7z0/5/
I have tried this solution but the layout is not side by side. https://jsfiddle.net/alexkwa/L9oy6hbp/1/
HTML
<div class="wrapper">
<ul class="tab-group">
<li class="single-tab">Tab 1</li>
<li class="single-tab">Tab 2</li>
<li class="single-tab">Very Long Tab Name</li>
<li class="single-tab active">Tab 4</li>
<li class="single-tab">Tab 5</li>
</ul>
</div>
SCSS
$active-color: #262933;
$inactive-color: #B3B4B8;
$inactive-font-color: #8B8C8F;
$border-thickness: 1px;
$border-radius: 3px;
body {
background: #fff;
padding: 20px;
font-family: Helvetica;
}
.wrapper {
display: inline-block;
}
.tab-group {
display: flex;
flex-direction: column;
list-style: none;
}
.single-tab {
background-color: #fff;
border: $border-thickness solid $inactive-color;
border-right: 0;
border-sizing: border-box;
color: $inactive-font-color;
cursor: normal;
font-size: 14px;
padding: 9px 21px;
margin: 0;
margin-left: -6px;
user-select: none;
display: flex;
justify-content: center;
flex-direction: column;
text-align: center;
}
.single-tab:first-child {
border-radius: $border-radius 0 0 $border-radius;
}
.single-tab:last-child {
border-radius: 0 $border-radius $border-radius 0;
border-right: $border-thickness solid $inactive-color;
}
.single-tab.active {
background-color: $active-color;
border: $border-thickness solid $active-color;
color: #fff;
}
.single-tab.active + .single-tab {
border-left: 0;
}
.single-tab:last-child.active {
border-left: 0;
}
Any ideas?
Try this
.tab-group {
display: flex; // instead of inline flex
... all other styles
}
.single-tab {
flex: 1; // makes your tabs of same width
... all other styles
}
Here's the working fiddle - https://jsfiddle.net/flexdinesh/xuc6amcu/2/
If you require the parent to not take up the full width, you have to define it manually, say 60%. Example fiddle - https://jsfiddle.net/flexdinesh/xuc6amcu/3/

CSS: Combining display:flex and overflow:auto kills padding [duplicate]

I have a list of items that I'm trying to arrange into a scrollable horizontal layout with flexbox.
Each item in the container has a margin left and right, but the right margin of the last item is being collapsed.
Is there a way to stop this happening, or a good workaround?
ul {
list-style-type: none;
padding: 0;
margin: 0;
display: flex;
height: 300px;
overflow: auto;
width: 600px;
background: orange;
}
ul li {
background: blue;
color: #fff;
padding: 90px;
margin: 0 30px;
white-space: nowrap;
flex-basis: auto;
}
<div class="container">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>
Potential Problem #1
The last margin is not being collapsed. It's being ignored.
The overflow property applies only to content. It doesn't apply to padding or margins.
Here's what it says in the spec:
11.1.1 Overflow: the overflow
property
This property specifies whether content of a block container element
is clipped when it overflows the element's box.
Now let's take a look at the CSS Box Model:
source: W3C
The overflow property is limited to the content box area. If the content overflows its container, then overflow applies. But overflow doesn't enter into the padding or margin areas (unless, of course, there is more content that follows).
Potential Problem #2
The problem with Potential Problem #1 is that it appears to fall apart outside of a flex or grid formatting context. For example, in a standard block layout, the last margin doesn't appear to collapse. So maybe overflow is permitted to cover margins / paddings, regardless of what it says in the spec.
div {
height: 150px;
overflow: auto;
width: 600px;
background: orange;
white-space: nowrap;
}
span {
background: blue;
color: #fff;
padding: 50px;
margin: 0 30px;
display: inline-block;
}
<div class="container">
<span>Item 1</span>
<span>Item 2</span>
<span>Item 3</span>
<span>Item 4</span>
</div>
Hence, maybe the problem is instead related to elements that are "over-constrained".
10.3.3 Block-level, non-replaced elements in normal
flow
The following constraints must hold among the used values of the other
properties:
margin-left + border-left-width + padding-left + width +
padding-right + border-right-width + margin-right = width of
containing block
If width is not auto and border-left-width + padding-left +
width + padding-right + border-right-width (plus any of
margin-left or margin-right that are not auto) is larger than
the width of the containing block, then any auto values for
margin-left or margin-right are, for the following rules, treated
as zero.
If all of the above have a computed value other than auto, the values are said to be "over-constrained" and one of the used values
will have to be different from its computed value. If the direction
property of the containing block has the value ltr, the specified
value of margin-right is ignored and the value is calculated so as
to make the equality true. If the value of direction is rtl,
this happens to margin-left instead
(emphasis added)
So, according to the CSS Visual Formatting Model, elements may be "over-constrained" and, as a result, a right margin gets tossed out.
Potential Workarounds
Instead of margin or padding, use a right border on the last element:
li:last-child {
border-right: 30px solid orange;
}
ul {
list-style-type: none;
padding: 0;
margin: 0;
display: flex;
height: 100px; /* adjusted for demo */
overflow: auto;
width: 600px;
background: orange;
}
ul li {
background: blue;
color: #fff;
padding: 90px;
margin: 0 30px;
white-space: nowrap;
flex-basis: auto;
}
li:last-child {
border-right: 30px solid orange;
}
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
Another solution uses a pseudo-elements instead of margins or padding.
Pseudo-elements on a flex container are rendered as flex items. The first item in the container is ::before and last item is ::after.
ul::after {
content: "";
flex: 0 0 30px;
}
ul {
list-style-type: none;
padding: 0;
margin: 0;
display: flex;
height: 100px; /* adjusted for demo */
overflow: auto;
width: 600px;
background: orange;
}
ul li {
margin: 0 30px;
background: blue;
color: #fff;
padding: 90px;
white-space: nowrap;
flex-basis: auto;
}
ul::after {
content: "";
flex: 0 0 30px;
}
ul::before {
content: "";
flex: 0 0 30px;
}
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
Your problem is not the margin in itself. It's the scroll bar dimensioning only the visible content of the element.
One hack to solve it would be to create a visible element that occupies the margin
This solution handles this using a pseudo on the last child
ul {
list-style-type: none;
padding: 0;
margin: 0;
display: flex;
height: 300px;
overflow: auto;
width: 600px;
background: orange;
}
ul li {
background: blue;
color: #fff;
padding: 90px;
margin: 0 30px;
white-space: nowrap;
flex-basis: auto;
position: relative;
}
li:last-child:after {
content: "";
width: 30px;
height: 1px;
position: absolute;
left: 100%;
top: 0px;
}
<div class"container">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>
You can set width and overflow on the div container, and set display: inline-flex rather than flex on the ul, so that the size of the flex box will be calculated based on the items inside, and all padding and margin will apply without any issues.
.container {
width: 600px;
overflow: auto;
}
.container ul {
list-style: none;
padding: 0;
margin: 0;
display: inline-flex;
background: orange;
}
.container li {
padding: 60px;
margin: 0 30px;
white-space: nowrap;
background: blue;
color: #fff;
}
<div class="container">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>
See the solution. I remove white-space, flex-basis and margin, to provide you a pure flexbox solution.
It relays on flex-flow: row(horizontal), justify-content: space-around (your margin) and no more!! The width is changed to 1200px since the padding of 90px set the total width of the boxes more than your 600px (defined in your snippet).
ul {
list-style-type: none;
padding: 0;
margin: 0;
display: flex;
flex-flow: row ;
justify-content: space-around;
height: 300px;
overflow: auto;
width: 1200px;
background: orange;
}
ul li {
background: blue;
color: #fff;
padding: 90px;
}
<div class"container">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>

When the flex container overflow, the last item's right margin was cut off [duplicate]

I have a list of items that I'm trying to arrange into a scrollable horizontal layout with flexbox.
Each item in the container has a margin left and right, but the right margin of the last item is being collapsed.
Is there a way to stop this happening, or a good workaround?
ul {
list-style-type: none;
padding: 0;
margin: 0;
display: flex;
height: 300px;
overflow: auto;
width: 600px;
background: orange;
}
ul li {
background: blue;
color: #fff;
padding: 90px;
margin: 0 30px;
white-space: nowrap;
flex-basis: auto;
}
<div class="container">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>
Potential Problem #1
The last margin is not being collapsed. It's being ignored.
The overflow property applies only to content. It doesn't apply to padding or margins.
Here's what it says in the spec:
11.1.1 Overflow: the overflow
property
This property specifies whether content of a block container element
is clipped when it overflows the element's box.
Now let's take a look at the CSS Box Model:
source: W3C
The overflow property is limited to the content box area. If the content overflows its container, then overflow applies. But overflow doesn't enter into the padding or margin areas (unless, of course, there is more content that follows).
Potential Problem #2
The problem with Potential Problem #1 is that it appears to fall apart outside of a flex or grid formatting context. For example, in a standard block layout, the last margin doesn't appear to collapse. So maybe overflow is permitted to cover margins / paddings, regardless of what it says in the spec.
div {
height: 150px;
overflow: auto;
width: 600px;
background: orange;
white-space: nowrap;
}
span {
background: blue;
color: #fff;
padding: 50px;
margin: 0 30px;
display: inline-block;
}
<div class="container">
<span>Item 1</span>
<span>Item 2</span>
<span>Item 3</span>
<span>Item 4</span>
</div>
Hence, maybe the problem is instead related to elements that are "over-constrained".
10.3.3 Block-level, non-replaced elements in normal
flow
The following constraints must hold among the used values of the other
properties:
margin-left + border-left-width + padding-left + width +
padding-right + border-right-width + margin-right = width of
containing block
If width is not auto and border-left-width + padding-left +
width + padding-right + border-right-width (plus any of
margin-left or margin-right that are not auto) is larger than
the width of the containing block, then any auto values for
margin-left or margin-right are, for the following rules, treated
as zero.
If all of the above have a computed value other than auto, the values are said to be "over-constrained" and one of the used values
will have to be different from its computed value. If the direction
property of the containing block has the value ltr, the specified
value of margin-right is ignored and the value is calculated so as
to make the equality true. If the value of direction is rtl,
this happens to margin-left instead
(emphasis added)
So, according to the CSS Visual Formatting Model, elements may be "over-constrained" and, as a result, a right margin gets tossed out.
Potential Workarounds
Instead of margin or padding, use a right border on the last element:
li:last-child {
border-right: 30px solid orange;
}
ul {
list-style-type: none;
padding: 0;
margin: 0;
display: flex;
height: 100px; /* adjusted for demo */
overflow: auto;
width: 600px;
background: orange;
}
ul li {
background: blue;
color: #fff;
padding: 90px;
margin: 0 30px;
white-space: nowrap;
flex-basis: auto;
}
li:last-child {
border-right: 30px solid orange;
}
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
Another solution uses a pseudo-elements instead of margins or padding.
Pseudo-elements on a flex container are rendered as flex items. The first item in the container is ::before and last item is ::after.
ul::after {
content: "";
flex: 0 0 30px;
}
ul {
list-style-type: none;
padding: 0;
margin: 0;
display: flex;
height: 100px; /* adjusted for demo */
overflow: auto;
width: 600px;
background: orange;
}
ul li {
margin: 0 30px;
background: blue;
color: #fff;
padding: 90px;
white-space: nowrap;
flex-basis: auto;
}
ul::after {
content: "";
flex: 0 0 30px;
}
ul::before {
content: "";
flex: 0 0 30px;
}
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
Your problem is not the margin in itself. It's the scroll bar dimensioning only the visible content of the element.
One hack to solve it would be to create a visible element that occupies the margin
This solution handles this using a pseudo on the last child
ul {
list-style-type: none;
padding: 0;
margin: 0;
display: flex;
height: 300px;
overflow: auto;
width: 600px;
background: orange;
}
ul li {
background: blue;
color: #fff;
padding: 90px;
margin: 0 30px;
white-space: nowrap;
flex-basis: auto;
position: relative;
}
li:last-child:after {
content: "";
width: 30px;
height: 1px;
position: absolute;
left: 100%;
top: 0px;
}
<div class"container">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>
You can set width and overflow on the div container, and set display: inline-flex rather than flex on the ul, so that the size of the flex box will be calculated based on the items inside, and all padding and margin will apply without any issues.
.container {
width: 600px;
overflow: auto;
}
.container ul {
list-style: none;
padding: 0;
margin: 0;
display: inline-flex;
background: orange;
}
.container li {
padding: 60px;
margin: 0 30px;
white-space: nowrap;
background: blue;
color: #fff;
}
<div class="container">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>
See the solution. I remove white-space, flex-basis and margin, to provide you a pure flexbox solution.
It relays on flex-flow: row(horizontal), justify-content: space-around (your margin) and no more!! The width is changed to 1200px since the padding of 90px set the total width of the boxes more than your 600px (defined in your snippet).
ul {
list-style-type: none;
padding: 0;
margin: 0;
display: flex;
flex-flow: row ;
justify-content: space-around;
height: 300px;
overflow: auto;
width: 1200px;
background: orange;
}
ul li {
background: blue;
color: #fff;
padding: 90px;
}
<div class"container">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>

Spread elements evenly using Flexbox

I'm starting with Flexbox and I'm trying to center a row with three columns to the center of the document. I've tried the following code (Written in Sass) but as you can see in the screenshot the three elements are not perfectly centered (they don't have the same space between them):
HTML for the header:
<header>
<nav>
<ul>
<li>ELE 1</li>
<li>ELEMENT 2</li>
<li>ELEMENT 3</li>
</ul>
</nav>
</header>
SCSS for the header:
header {
height: 80px;
width: 100%;
background-color: $dark-grey;
}
nav {
height: inherit;
max-width: 800px;
margin: auto;
text-align: center;
display: flex;
align-items: center;
& ul {
width: 100%;
display: flex;
& li {
flex: 1 0 auto;
& a, a:visited {
color: $white-alpha;
}
& a.active {
color: $white;
}
}
}
}
I've recreated the problem in this CodePen, as you can see the real example. What I'm doing wrong? Thanks.

Resources