I have a container <div> with display: flex. It has a child <a>.
How can I make the child appear "inline"?
Specifically, how can I make the child's width determined by its content, and not expand to the width of the parent?
What I tried:
I set the child to display: inline-flex, but it still took up the full width. I also tried all other display properties, but nothing had an effect.
Example:
.container {
background: red;
height: 200px;
flex-direction: column;
padding: 10px;
display: flex;
}
a {
display: inline-flex;
padding: 10px 40px;
background: pink;
}
<div class="container">
Test
</div>
http://codepen.io/donpinkus/pen/YGRxRY
Use align-items: flex-start on the container, or align-self: flex-start on the flex items.
No need for display: inline-flex.
An initial setting of a flex container is align-items: stretch. This means that flex items will expand to cover the full length of the container along the cross axis.
The align-self property does the same thing as align-items, except that align-self applies to flex items while align-items applies to the flex container.
By default, align-self inherits the value of align-items.
Since your container is flex-direction: column, the cross axis is horizontal, and align-items: stretch is expanding the child element's width as much as it can. (The column setting is also the reason why display: inline-flex isn't working.)
You can override the default with align-items: flex-start on the container (which is inherited by all flex items) or align-self: flex-start on the item (which is confined to the single item).
Learn more about flex alignment along the cross axis here:
How does flex-wrap work with align-self, align-items and align-content?
Learn more about flex alignment along the main axis here:
In CSS Flexbox, why are there no "justify-items" and "justify-self" properties?
In addition to align-self you can also consider auto margin which will do almost the same thing
.container {
background: red;
height: 200px;
flex-direction: column;
padding: 10px;
display: flex;
}
a {
margin-right:auto;
padding: 10px 40px;
background: pink;
}
<div class="container">
Test
</div>
width: min-content also yields the same result.
Not supported in IE11 if that matters to you: https://caniuse.com/mdn-css_properties_width_min-content
Related
I am trying to have a number of items underneath each other in a container with a set height. Items will then carry on next to each other if there's no space left.
This is the idea:
I am trying to achieve this using flexbox, a container with a set height, direction is set to column and flex-wrap is wrap:
The issue is that there are wide gaps between the columns.
I tried setting both justify-content and align-items to flex-start, but that is probably the default value.
Is there any way to solve this?
Here is the code:
* {
box-sizing: border-box;
}
body {
font-family: sans-serif;
}
.container {
display: flex;
flex-wrap: wrap;
height: 300px;
flex-direction: column;
background-color: #ccc;
}
.items {
width: 100px;
height: 100px;
margin: 10px;
background-color: tomato;
color: white;
font-size: 60px;
font-weight: bold;
text-align: center;
padding: 15px;
}
<div class="container">
<div class="items">1</div>
<div class="items">2</div>
<div class="items">3</div>
<div class="items">4</div>
<div class="items">5</div>
</div>
codepen
An initial setting of a flex container is align-content: stretch.
This means that multiple lines of flex items will be distributed evenly along the cross axis.
To override this behavior, apply align-content: flex-start to the container.
When you're working in a single-line flex container (i.e., flex-wrap: nowrap), the properties to use to distribute space along the cross axis are align-items and align-self.
When you're working in a multi-line flex container (i.e., flex-wrap: wrap) – like in the question – the property to use to distribute flex lines (rows / columns) along the cross axis is align-content.
From the spec:
8.3. Cross-axis Alignment: the align-items and align-self properties
align-items sets the default alignment for all of the flex container’s items, including anonymous flex items. align-self allows this default alignment to be overridden for individual flex items.
8.4. Packing Flex Lines: the align-content
property
The align-content property aligns a flex container’s lines within the
flex container when there is extra space in the cross-axis, similar to
how justify-content aligns individual items within the main-axis.
Note, this property has no effect on a single-line flex container.
The align-content property takes six values:
flex-start
flex-end
center
space-between
space-around
stretch
Here's the definition for stretch:
stretch
Lines stretch to take up the remaining space. If the leftover free-space is negative, this value is identical to flex-start. Otherwise, the free-space is split equally between all of the lines, increasing their cross size.
In other words, align-content: stretch on the cross axis is similar to flex: 1 on the main axis.
I have a container <div> with display: flex. It has a child <a>.
How can I make the child appear "inline"?
Specifically, how can I make the child's width determined by its content, and not expand to the width of the parent?
What I tried:
I set the child to display: inline-flex, but it still took up the full width. I also tried all other display properties, but nothing had an effect.
Example:
.container {
background: red;
height: 200px;
flex-direction: column;
padding: 10px;
display: flex;
}
a {
display: inline-flex;
padding: 10px 40px;
background: pink;
}
<div class="container">
Test
</div>
http://codepen.io/donpinkus/pen/YGRxRY
Use align-items: flex-start on the container, or align-self: flex-start on the flex items.
No need for display: inline-flex.
An initial setting of a flex container is align-items: stretch. This means that flex items will expand to cover the full length of the container along the cross axis.
The align-self property does the same thing as align-items, except that align-self applies to flex items while align-items applies to the flex container.
By default, align-self inherits the value of align-items.
Since your container is flex-direction: column, the cross axis is horizontal, and align-items: stretch is expanding the child element's width as much as it can. (The column setting is also the reason why display: inline-flex isn't working.)
You can override the default with align-items: flex-start on the container (which is inherited by all flex items) or align-self: flex-start on the item (which is confined to the single item).
Learn more about flex alignment along the cross axis here:
How does flex-wrap work with align-self, align-items and align-content?
Learn more about flex alignment along the main axis here:
In CSS Flexbox, why are there no "justify-items" and "justify-self" properties?
In addition to align-self you can also consider auto margin which will do almost the same thing
.container {
background: red;
height: 200px;
flex-direction: column;
padding: 10px;
display: flex;
}
a {
margin-right:auto;
padding: 10px 40px;
background: pink;
}
<div class="container">
Test
</div>
width: min-content also yields the same result.
Not supported in IE11 if that matters to you: https://caniuse.com/mdn-css_properties_width_min-content
I am trying to have a number of items underneath each other in a container with a set height. Items will then carry on next to each other if there's no space left.
This is the idea:
I am trying to achieve this using flexbox, a container with a set height, direction is set to column and flex-wrap is wrap:
The issue is that there are wide gaps between the columns.
I tried setting both justify-content and align-items to flex-start, but that is probably the default value.
Is there any way to solve this?
Here is the code:
* {
box-sizing: border-box;
}
body {
font-family: sans-serif;
}
.container {
display: flex;
flex-wrap: wrap;
height: 300px;
flex-direction: column;
background-color: #ccc;
}
.items {
width: 100px;
height: 100px;
margin: 10px;
background-color: tomato;
color: white;
font-size: 60px;
font-weight: bold;
text-align: center;
padding: 15px;
}
<div class="container">
<div class="items">1</div>
<div class="items">2</div>
<div class="items">3</div>
<div class="items">4</div>
<div class="items">5</div>
</div>
codepen
An initial setting of a flex container is align-content: stretch.
This means that multiple lines of flex items will be distributed evenly along the cross axis.
To override this behavior, apply align-content: flex-start to the container.
When you're working in a single-line flex container (i.e., flex-wrap: nowrap), the properties to use to distribute space along the cross axis are align-items and align-self.
When you're working in a multi-line flex container (i.e., flex-wrap: wrap) – like in the question – the property to use to distribute flex lines (rows / columns) along the cross axis is align-content.
From the spec:
8.3. Cross-axis Alignment: the align-items and align-self properties
align-items sets the default alignment for all of the flex container’s items, including anonymous flex items. align-self allows this default alignment to be overridden for individual flex items.
8.4. Packing Flex Lines: the align-content
property
The align-content property aligns a flex container’s lines within the
flex container when there is extra space in the cross-axis, similar to
how justify-content aligns individual items within the main-axis.
Note, this property has no effect on a single-line flex container.
The align-content property takes six values:
flex-start
flex-end
center
space-between
space-around
stretch
Here's the definition for stretch:
stretch
Lines stretch to take up the remaining space. If the leftover free-space is negative, this value is identical to flex-start. Otherwise, the free-space is split equally between all of the lines, increasing their cross size.
In other words, align-content: stretch on the cross axis is similar to flex: 1 on the main axis.
I am exploring Flexbox and am trying to align some items. The following code works and shows what I want to achieve (successful codepen here):
.labelinput {
display: flex;
flex-flow: row;
margin: 1px;
}
.labelinput > *:first-child {
flex-basis: 10em;
flex-grow: 0;
flex-shrink: 0;
}
.labelinput > *:nth-child(2) {
flex-grow: 1;
flex-shrink: 1;
border: 3px solid purple;
}
<div class='labelinput'>
<div>1st input</div>
<div>this is just a div</div>
</div>
<div class='labelinput'>
<div>2nd:</div>
<input type="text" name="foo" value="this is an input box" />
</div>
The above code produces the nicely align output shown below:
My reading of the above code is that it works because the first child in every div has a determined size (10em) and is totally inflexible (flex-grow and flex-shrink set to 0) whereas the second child has no determined size and will grow and shrink as appropriately.
What breaks though is when I try to embed the two top-level div elements (of class labelinput) into yet another container (failing codepen here):
#container {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
margin: 5px;
border: 1px solid grey;
}
.labelinput {
display: flex;
flex-flow: row;
margin: 1px;
}
.labelinput > *:first-child {
flex-basis: 7em;
flex-grow: 0;
flex-shrink: 0;
}
.labelinput > *:nth-child(2) {
flex-grow: 1;
flex-shrink: 1;
border: 3px solid purple;
}
<div id='container'>
<div class='labelinput'>
<div>1st input</div>
<div>this is just a div</div>
</div>
<div class='labelinput'>
<div>2nd:</div>
<input type="text" name="foo" value="this is the input box" />
</div>
</div>
The above produces the following unsatisfactory output:
I can't explain why this fails as I am just inserting the content of the successful case into a container that simply performs the default vertical stacking (flex-direction: column;).
By experimentation I have discovered that removing the align-items property from the outer level container (#container) fixes the problem but I can't explain that either.
I understand that the outermost container (#container) is asked to layout two other containers (of class labelinput) so whatever property I set for align-items in the outermost container should apply to the inner containers as a whole, not change the layout of their internal items.
Moreover I can't explain why the layout is changed based on the element type when there's nothing in my CSS that differentiates between items of element div versus items of element input.
I can't explain why this fails as I am just inserting the content of the successful case into a container that simply performs the default vertical stacking (flex-direction: column).
The difference is that this new primary container has align-items: flex-start.
By experimentation I have discovered that removing the align-items property from the outer level container (#container) fixes the problem but I can't explain that either.
When you nest the .labelinput flex containers in the larger container (#container), then the .labelinput elements become flex items, in addition to flex containers.
Since the #container flex container is set to flex-direction: column, the main axis is vertical and the cross axis is horizontal1.
The align-items property works only along the cross axis. It's default setting is align-items: stretch2, which causes flex items to expand the full width of the container.
But when you override the default with align-items: flex-start, like in your code, you pack the two labelinput items to the start of the container, as illustrated in your problem image:
Because stretch is the default value for align-items, when you omit this property altogether, you get the behavior you want:
I understand that the outermost container (#container) is asked to layout two other containers (of class labelinput) so whatever property I set for align-items in the outermost container should apply to the inner containers as a whole, not change the layout of their internal items.
The outermost container is not changing the layout of the inner container's children. At least not directly.
The align-items: flex-start rule on the outermost container is applying directly to the inner containers. The internal items of the inner containers are just responding to the sizing adjustment of their parent.
Here's an illustration of align-items: flex-start impacting .labelinput (red borders added).
#container {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
margin: 5px;
border: 1px solid grey;
}
.labelinput {
display: flex;
flex-flow: row;
margin: 1px;
border: 2px dashed red;
}
.labelinput > *:first-child {
flex-basis: 7em;
flex-grow: 0;
flex-shrink: 0;
}
.labelinput > *:nth-child(2) {
flex-grow: 1;
flex-shrink: 1;
border: 3px solid purple;
}
<div id='container'>
<div class='labelinput'>
<div>1st input</div>
<div>this is just a div</div>
</div>
<div class='labelinput'>
<div>2nd:</div>
<input type="text" name="foo" value="this is the input box" />
</div>
</div>
Moreover I can't explain why the layout is changed based on the element type when there's nothing in my CSS that differentiates between items of element div versus items of element input.
There may be no difference between div and input in your code, but there are intrinsic differences.
Unlike a div, an input element has a minimum width set by the browser (maybe to always allow for character entry).
You may be able to reduce the input width by applying min-width: 0 or overflow: hidden3.
Footnotes
1. Learn more about flex layout's main axis and cross axis here: In CSS Flexbox, why are there no "justify-items" and "justify-self" properties?
2. Learn more about the align-items property in the spec: 8.3. Cross-axis Alignment: the align-items and align-self properties
3. Why doesn't flex item shrink past content size?
Using flexbox, how can you align a <p> to its parent's "end"?
According to the documentation, adding align-content: flex-end to the parent element should be enough. However, this isn't working in the example below.
Example:
Here is a simple div containing a p element.
div {
display: flex;
flex-direction: column;
align-content: flex-end; /* This should do the alignment, but doesn't. */
background: yellow;
padding: 50px;
height: 300px;
width: 400px;
}
<div>
<p>Align me to the end.</p>
</div>
jsFiddle
A hacky solution would be to add a ::before to the child with flex: 1, but I'm curious if there is a better solution.
The align-content property only works when there are multiple lines of flex items in a container. This property is designed to distribute the space between lines.
Since there is only one line in your container, align-content is having no effect.
Use align-items in a single line container.
div {
display: flex;
flex-direction: column;
align-items: flex-end; /* changed from align-content */
justify-content: flex-end; /* optional */
background: yellow;
padding: 50px;
width: 400px;
height: 300px;
}
<div>
<p>
Align me in the bottom left corner.
</p>
</div>
revised fiddle
8.4. Packing Flex Lines: the align-content
property
The align-content property aligns a flex container’s lines within
the flex container when there is extra space in the cross-axis,
similar to how justify-content aligns individual items within the
main-axis.
Note, this property has no effect on a single-line flex container.
Only multi-line flex containers ever have free space in the cross-axis
for lines to be aligned in, because in a single-line flex container
the sole line automatically stretches to fill the space.