I would like to have A B and C aligned in the middle.
How can I get D to go completely to the right?
BEFORE:
AFTER:
ul {
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
li:last-child {
background: #ddd;
/* magic to throw to the right*/
}
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
https://jsfiddle.net/z44p7bsx/
Below are five options for achieving this layout:
CSS Positioning
Flexbox with Invisible DOM Element
Flexbox with Invisible Pseudo-Element
Flexbox with flex: 1
CSS Grid Layout
Method #1: CSS Positioning Properties
Apply position: relative to the flex container.
Apply position: absolute to item D.
Now this item is absolutely positioned within the flex container.
More specifically, item D is removed from the document flow but stays within the bounds of the nearest positioned ancestor.
Use the CSS offset properties top and right to move this element into position.
li:last-child {
position: absolute;
top: 0;
right: 0;
background: #ddd;
}
ul {
position: relative;
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
p {
text-align: center;
margin-top: 0;
}
span {
background-color: aqua;
}
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>true center</span></p>
One caveat to this method is that some browsers may not completely remove an absolutely-positioned flex item from the normal flow. This changes the alignment in a non-standard, unexpected way. More details: Absolutely positioned flex item is not removed from the normal flow in IE11
Method #2: Flex Auto Margins & Invisible Flex Item (DOM element)
With a combination of auto margins and a new, invisible flex item the layout can be achieved.
The new flex item is identical to item D and is placed at the opposite end (the left edge).
More specifically, because flex alignment is based on the distribution of free space, the new item is a necessary counterbalance to keep the three middle boxes horizontally centered. The new item must be the same width as the existing D item, or the middle boxes won't be precisely centered.
The new item is removed from view with visibility: hidden.
In short:
Create a duplicate of the D element.
Place it at the beginning of the list.
Use flex auto margins to keep A, B and C centered, with both D elements creating equal balance from both ends.
Apply visibility: hidden to the duplicate D
li:first-child {
margin-right: auto;
visibility: hidden;
}
li:last-child {
margin-left: auto;
background: #ddd;
}
ul {
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
p { text-align: center; margin-top: 0; }
span { background-color: aqua; }
<ul>
<li>D</li><!-- new; invisible spacer item -->
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>true center</span></p>
Method #3: Flex Auto Margins & Invisible Flex Item (pseudo-element)
This method is similar to #2, except it's cleaner semantically and the width of D must be known.
Create a pseudo-element with the same width as D.
Place it at the start of the container with ::before.
Use flex auto margins to keep A, B and C perfectly centered, with the pseudo and D elements creating equal balance from both ends.
ul::before {
content:"D";
margin: 1px auto 1px 1px;
visibility: hidden;
padding: 5px;
background: #ddd;
}
li:last-child {
margin-left: auto;
background: #ddd;
}
ul {
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
p { text-align: center; margin-top: 0; }
span { background-color: aqua; }
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>true center</span></p>
Method #4: Add flex: 1 to left and right items
Starting with Method #2 or #3 above, instead of worrying about equal width for the left and right items to maintain equal balance, just give each one flex: 1. This will force them both to consume available space, thus centering the middle item.
You can then add display: flex to individual items in order to align their content.
NOTE about using this method with min-height: Currently in Chrome, Firefox, Edge and possibly other browsers, the shorthand rule flex: 1 breaks down to this:
flex-grow: 1
flex-shrink: 1
flex-basis: 0%
That percentage unit (%) on flex-basis causes this method to break when min-height is used on the container. This is because, as a general rule, percentage heights on the children require an explicit height property setting on the parent.
This is an old CSS rule dating back to 1998 (CSS Level 2) which is still in effect in many browsers to some degree or another. For complete details see here and here.
Here's an illustration of the problem posted in the comments by user2651804:
#flex-container {
display: flex;
flex-direction: column;
background: teal;
width: 150px;
min-height: 80vh;
justify-content: space-between;
}
#flex-container>div {
background: orange;
margin: 5px;
}
#flex-container>div:first-child {
flex: 1;
}
#flex-container::after {
content: "";
flex: 1;
}
<div id="flex-container">
<div>very long annoying text that will add on top of the height of its parent</div>
<div>center</div>
</div>
The solution is to not use the percentage unit. Try px or just nothing at all (which is what the spec actually recommends, despite the fact that at least some of the major browsers have appended a percentage unit for whatever reason).
#flex-container {
display: flex;
flex-direction: column;
background: teal;
width: 150px;
min-height: 80vh;
justify-content: space-between;
}
#flex-container > div {
background: orange;
margin: 5px;
}
/* OVERRIDE THE BROWSER SETTING IN THE FLEX PROPERTY */
#flex-container > div:first-child {
flex: 1;
flex-basis: 0;
}
#flex-container::after {
content: "";
flex: 1;
flex-basis: 0;
}
/* OR... JUST SET THE LONG-HAND PROPERTIES INDIVIDUALLY
#flex-container > div:first-child {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
}
#flex-container::after {
content: "";
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
}
*/
<div id="flex-container">
<div>very long annoying text that will add on top of the height of its parent</div>
<div>center</div>
</div>
Method #5: CSS Grid Layout
This may be the cleanest and most efficient method. There is no need for absolute positioning, fake elements or other hackery.
Simply create a grid with multiple columns. Then position your items in the middle and end columns. Basically, just leave the first column empty.
ul {
display: grid;
grid-template-columns: 1fr repeat(3, auto) 1fr;
grid-column-gap: 5px;
justify-items: center;
}
li:nth-child(1) { grid-column-start: 2; }
li:nth-child(4) { margin-left: auto; }
/* for demo only */
ul { padding: 0; margin: 0; list-style: none; }
li { padding: 5px; background: #aaa; }
p { text-align: center; }
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>| true center |</span></p>
The simplest solution will be to justify-content center to the parent container and giving margin-left auto to first and last child element.
ul {
display:flex;
justify-content:center;
}
.a,.d {
margin-left:auto;
}
<ul>
<li class="a">A</li>
<li>B</li>
<li>C</li>
<li class="d">D</li>
</ul>
Most easy way
.box{
display:flex;
justify-content:center;
}
.item1{
flex:1;
display: flex;
justify-content: center;
transform: translateX(10px);/*D element Width[if needed]*/
}
<div class="box">
<div class="item1">
<div>A</div>
<div>B</div>
<div>C</div>
</div>
<div class="item2">D</div>
</div>
Using the display:grid approach, you can simply put all of the ul children into the same cell and then set justify-self:
.ul {
display: grid;
}
.ul > * {
grid-column-start: 1;
grid-row-start: 1;
justify-self:center;
}
.ul > *:last-child {
justify-self: right;
}
/* Make Fancy */
.li {
display:inline-block;
margin: 1px;
padding: 5px;
background: #bbb;
}
<div class='ul'>
<span>
<span class='li'>A</span>
<span class='li'>B</span>
<span class='li'>C</span>
</span>
<span class='li'>D</span>
</div>
Inspired by the Method #5: CSS Grid Layout of #Michal Benjamin's solution and because I'm using Tailwind and as of now still don't have access to all the grid options by default. This seems to work:
ul {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
}
li {
align-self: center;
}
li:nth-child(1) {
justify-content: flex-start; /* OR margin-right: auto */
}
li:nth-child(3) {
justify-content: flex-end; /* OR margin-left:auto */
}
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
</ul>
PS: Not sure if mixing up flex and grid like this is a good idea!
If you want to make it aligned, you can simply attach an empty span and split the three child spans into them.
The easiest way:
.wrap {
display:flex;
}
.full-width {
width: 100%;
}
.centered {
display: flex;
justify-content:center;
}
.btn {
display: flex;
justify-content: end;
}
<div class="wrap">
<div class="full-width"></div>
<div class="full-width centered">
<div>A</div>
<div>B</div>
<div>C</div>
</div>
<div class="full-width btn">D</div>
</div>
Very clear question. I couldn't help but post the answer after a few hours of digging. We Could of solved this with tables, table-cell, absolute positions, transforms but we just had to do it with flexbox :)
.parent {
display: flex;
justify-content: flex-end;
}
.center {
margin: auto;
}
http://codepen.io/rgfx/pen/BLorgd
The accepted answer can be changed a bit because you can use grid template areas and do it without fake element
grid-template-areas '. b c'
grid-template-columns: 1fr 1fr 1fr
I expanded on Michael_B's answer
.center-flex__2-of-3 > :nth-child(1), .center-flex__2-of-3 > :nth-child(3) {
flex: 1;
}
.center-flex__2-of-3 > :nth-child(1) {
justify-content: flex-start;
}
.center-flex__2-of-3 > :nth-child(3) {
justify-content: flex-end;
}
.center-flex__1-of-2 > :nth-child(1) {
margin: auto;
}
.center-flex__1-of-2 > :nth-child(2) {
flex: 1;
justify-content: flex-end;
}
.center-flex__2-of-2 > :nth-child(1) {
flex: 1;
justify-content: flex-start;
}
.center-flex__2-of-2 > :nth-child(2) {
margin: auto;
}
.center-flex__1-of-2:before, .center-flex__1-of-1:before {
content: '';
flex: 1;
}
.center-flex__1-of-1:after, .center-flex__2-of-2:after {
content: '';
flex: 1;
}
[class*=center-flex] {
display: flex;
list-style: none;
margin: 0;
padding: 0;
border: 10px solid rgba(0, 0, 0, 0.1);
}
[class*=center-flex] > * {
display: flex;
}
li {
padding: 3px 5px;
}
2 of 3
<ul class="center-flex__2-of-3">
<span>
<li>Accusamus</li>
<li>Porro</li>
</span>
<span>
<li>Center</li>
<li>this</li>
</span>
<span>
<li>Accusamus</li>
<li>Porro</li>
<li>Culpa</li>
<li>Sit</li>
</span>
</ul>
<br><br>
1 of 2
<ul class="akex center-flex__1-of-2">
<span>
<li>Center</li>
<li>this</li>
</span>
<span>
<li>Accusamus</li>
<li>Porro</li>
<li>Culpa</li>
<li>Sit</li>
</span>
</ul>
<br><br>
2 of 2
<ul class="akex center-flex__2-of-2">
<span>
<li>Accusamus</li>
<li>Porro</li>
<li>Culpa</li>
<li>Sit</li>
</span>
<span>
<li>Center</li>
<li>this</li>
</span>
</ul>
<br><br>
1 of 1
<ul class="center-flex__1-of-1">
<span>
<li>Center</li>
<li>this</li>
</span>
</ul>
Here with the help of SASS as a codepen
ul {
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
li:last-child {
background: #ddd;
position:absolute;
right:10px;
}
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
Related
I need to put the li's side by side but I'm having trouble doing that.
.logo {
display: grid;
grid-column: span 2;
justify-content: start;
}
.logo h4 {
grid-column: 2;
}
nav {
display: grid;
}
ul {
text-transform: uppercase;
list-style: none;
gap: 20px;
}
<header>
<div class="logo">
<img src="image 17.png" alt="My Learning Journal logo">
<h4>My learning journal</h4>
</div>
<nav>
<ul>
<li>About Me</li>
<li>Contact</li>
</ul>
</nav>
</header>
You can use display:flex to put the li's side by side
ul {
text-transform: uppercase;
list-style: none;
gap: 20px;
display: flex
}
<ul>
<li>About Me</li>
<li>Contact</li>
</ul>
Horizontal menu can be done on both Flex and Grid.
If you are mastering Grid, either set general flow direction using grid-auto-flow rule, or declare dynamic column layout using grid-template-columns along with auto-fit/auto-fill.
ul {
text-transform: uppercase;
list-style: none;
display: grid;
grid-auto-flow: column; /* first way */
grid-template-column: repeat(auto-fill, 1fr) /* second way */
column-gap: 20px;
}
There were a few problems with your posted code; mainly that you were trying to position elements within a grid that was declared on their ancestor or – in the case of the .logo CSS – trying to position the element in grid-column: 2, despite that element not being a grid-item (the element itself had display: grid but it – obviously? – can't be placed in the second column of itself.
The following approach – with explanatory comments in the code – seems to do as you require:
/* removing browser default margins and padding, setting the sizing
algorithm to border-box; this includes border-sizes and padding
in the declared width of the elements: */
*,
::before,
::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.logo {
/* you've set display: grid; which means the children of this element
become grid-items, but this element is not (unless its parent is
also set to display: grid, but you haven't shown that in your code: */
display: grid;
/* setting the same gap as declared for the <ul> element: */
gap: 20px;
/* the following rule has no effect, as this element isn't a grid-item: */
grid-column: span 2;
justify-content: start;
/* to create a two-column grid layout, we use the following: */
grid-template-columns: repeat(2, 1fr);
}
/* this is just so that we can visualise the <img> element's placement,
adjust to your taste: */
.logo img {
background-image: repeating-linear-gradient( -45deg, transparent 0 5px, #eee9 5px 7px);
/* setting the maximum width (in left-to-right, top-to-bottom languages, like Latin and
its derivatives) of the element to be 100% of the available space: */
max-inline-size: 100%;
/* and for the <img> to fill the available space: */
object-fit: cover;
}
.logo h4 {
grid-column: 2;
}
ul {
display: grid;
/* setting two grid-columns, with the repeat() function; this sets the 2 columns
to both have the size of 1fr (one fraction of the available space), so that
they are each equally sized: */
grid-template-columns: repeat(2, 1fr);
text-transform: uppercase;
list-style: none;
gap: 20px;
}
nav a {
background-color: lightskyblue;
color: #fff;
display: block;
}
<header>
<div class="logo">
<img src="image 17.png" alt="My Learning Journal logo">
<h4>My learning journal</h4>
</div>
<nav>
<ul>
<li>About Me</li>
<li>Contact</li>
</ul>
</nav>
</header>
It's worth pointing out that, in this instance, display: flex may be be preferred:
*,
::before,
::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.logo {
/* you've set display: grid; which means the children of this element
become grid-items, but this element is not (unless its parent is
also set to display: grid, but you haven't shown that in your code: */
display: grid;
/* setting the same gap as declared for the <ul> element: */
gap: 20px;
justify-content: start;
/* to create a two-column grid layout, we use the following: */
grid-template-columns: repeat(2, 1fr);
}
.logo img {
background-image: repeating-linear-gradient( -45deg, transparent 0 5px, #eee9 5px 7px);
min-inline-size: 100%;
object-fit: cover;
}
.logo h4 {
grid-column: 2;
}
ul {
/* setting flex layout: */
display: flex;
text-transform: uppercase;
list-style: none;
/* using gap as before: */
gap: 20px;
}
li {
/* instructing the <li> element(s) to expand to fill available space: */
flex-grow: 1;
}
nav a {
background-color: lightskyblue;
color: #fff;
display: block;
}
<header>
<div class="logo">
<img src="image 17.png" alt="My Learning Journal logo">
<h4>My learning journal</h4>
</div>
<nav>
<ul>
<li>About Me</li>
<li>Contact</li>
</ul>
</nav>
</header>
References:
CSS Logical Properties.
display.
gap.
grid-column.
grid-template-columns.
justify-content.
max-inline-size.
object-fit.
repeat().
I would like to have A B and C aligned in the middle.
How can I get D to go completely to the right?
BEFORE:
AFTER:
ul {
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
li:last-child {
background: #ddd;
/* magic to throw to the right*/
}
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
https://jsfiddle.net/z44p7bsx/
Below are five options for achieving this layout:
CSS Positioning
Flexbox with Invisible DOM Element
Flexbox with Invisible Pseudo-Element
Flexbox with flex: 1
CSS Grid Layout
Method #1: CSS Positioning Properties
Apply position: relative to the flex container.
Apply position: absolute to item D.
Now this item is absolutely positioned within the flex container.
More specifically, item D is removed from the document flow but stays within the bounds of the nearest positioned ancestor.
Use the CSS offset properties top and right to move this element into position.
li:last-child {
position: absolute;
top: 0;
right: 0;
background: #ddd;
}
ul {
position: relative;
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
p {
text-align: center;
margin-top: 0;
}
span {
background-color: aqua;
}
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>true center</span></p>
One caveat to this method is that some browsers may not completely remove an absolutely-positioned flex item from the normal flow. This changes the alignment in a non-standard, unexpected way. More details: Absolutely positioned flex item is not removed from the normal flow in IE11
Method #2: Flex Auto Margins & Invisible Flex Item (DOM element)
With a combination of auto margins and a new, invisible flex item the layout can be achieved.
The new flex item is identical to item D and is placed at the opposite end (the left edge).
More specifically, because flex alignment is based on the distribution of free space, the new item is a necessary counterbalance to keep the three middle boxes horizontally centered. The new item must be the same width as the existing D item, or the middle boxes won't be precisely centered.
The new item is removed from view with visibility: hidden.
In short:
Create a duplicate of the D element.
Place it at the beginning of the list.
Use flex auto margins to keep A, B and C centered, with both D elements creating equal balance from both ends.
Apply visibility: hidden to the duplicate D
li:first-child {
margin-right: auto;
visibility: hidden;
}
li:last-child {
margin-left: auto;
background: #ddd;
}
ul {
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
p { text-align: center; margin-top: 0; }
span { background-color: aqua; }
<ul>
<li>D</li><!-- new; invisible spacer item -->
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>true center</span></p>
Method #3: Flex Auto Margins & Invisible Flex Item (pseudo-element)
This method is similar to #2, except it's cleaner semantically and the width of D must be known.
Create a pseudo-element with the same width as D.
Place it at the start of the container with ::before.
Use flex auto margins to keep A, B and C perfectly centered, with the pseudo and D elements creating equal balance from both ends.
ul::before {
content:"D";
margin: 1px auto 1px 1px;
visibility: hidden;
padding: 5px;
background: #ddd;
}
li:last-child {
margin-left: auto;
background: #ddd;
}
ul {
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
p { text-align: center; margin-top: 0; }
span { background-color: aqua; }
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>true center</span></p>
Method #4: Add flex: 1 to left and right items
Starting with Method #2 or #3 above, instead of worrying about equal width for the left and right items to maintain equal balance, just give each one flex: 1. This will force them both to consume available space, thus centering the middle item.
You can then add display: flex to individual items in order to align their content.
NOTE about using this method with min-height: Currently in Chrome, Firefox, Edge and possibly other browsers, the shorthand rule flex: 1 breaks down to this:
flex-grow: 1
flex-shrink: 1
flex-basis: 0%
That percentage unit (%) on flex-basis causes this method to break when min-height is used on the container. This is because, as a general rule, percentage heights on the children require an explicit height property setting on the parent.
This is an old CSS rule dating back to 1998 (CSS Level 2) which is still in effect in many browsers to some degree or another. For complete details see here and here.
Here's an illustration of the problem posted in the comments by user2651804:
#flex-container {
display: flex;
flex-direction: column;
background: teal;
width: 150px;
min-height: 80vh;
justify-content: space-between;
}
#flex-container>div {
background: orange;
margin: 5px;
}
#flex-container>div:first-child {
flex: 1;
}
#flex-container::after {
content: "";
flex: 1;
}
<div id="flex-container">
<div>very long annoying text that will add on top of the height of its parent</div>
<div>center</div>
</div>
The solution is to not use the percentage unit. Try px or just nothing at all (which is what the spec actually recommends, despite the fact that at least some of the major browsers have appended a percentage unit for whatever reason).
#flex-container {
display: flex;
flex-direction: column;
background: teal;
width: 150px;
min-height: 80vh;
justify-content: space-between;
}
#flex-container > div {
background: orange;
margin: 5px;
}
/* OVERRIDE THE BROWSER SETTING IN THE FLEX PROPERTY */
#flex-container > div:first-child {
flex: 1;
flex-basis: 0;
}
#flex-container::after {
content: "";
flex: 1;
flex-basis: 0;
}
/* OR... JUST SET THE LONG-HAND PROPERTIES INDIVIDUALLY
#flex-container > div:first-child {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
}
#flex-container::after {
content: "";
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
}
*/
<div id="flex-container">
<div>very long annoying text that will add on top of the height of its parent</div>
<div>center</div>
</div>
Method #5: CSS Grid Layout
This may be the cleanest and most efficient method. There is no need for absolute positioning, fake elements or other hackery.
Simply create a grid with multiple columns. Then position your items in the middle and end columns. Basically, just leave the first column empty.
ul {
display: grid;
grid-template-columns: 1fr repeat(3, auto) 1fr;
grid-column-gap: 5px;
justify-items: center;
}
li:nth-child(1) { grid-column-start: 2; }
li:nth-child(4) { margin-left: auto; }
/* for demo only */
ul { padding: 0; margin: 0; list-style: none; }
li { padding: 5px; background: #aaa; }
p { text-align: center; }
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>| true center |</span></p>
The simplest solution will be to justify-content center to the parent container and giving margin-left auto to first and last child element.
ul {
display:flex;
justify-content:center;
}
.a,.d {
margin-left:auto;
}
<ul>
<li class="a">A</li>
<li>B</li>
<li>C</li>
<li class="d">D</li>
</ul>
Most easy way
.box{
display:flex;
justify-content:center;
}
.item1{
flex:1;
display: flex;
justify-content: center;
transform: translateX(10px);/*D element Width[if needed]*/
}
<div class="box">
<div class="item1">
<div>A</div>
<div>B</div>
<div>C</div>
</div>
<div class="item2">D</div>
</div>
Using the display:grid approach, you can simply put all of the ul children into the same cell and then set justify-self:
.ul {
display: grid;
}
.ul > * {
grid-column-start: 1;
grid-row-start: 1;
justify-self:center;
}
.ul > *:last-child {
justify-self: right;
}
/* Make Fancy */
.li {
display:inline-block;
margin: 1px;
padding: 5px;
background: #bbb;
}
<div class='ul'>
<span>
<span class='li'>A</span>
<span class='li'>B</span>
<span class='li'>C</span>
</span>
<span class='li'>D</span>
</div>
Inspired by the Method #5: CSS Grid Layout of #Michal Benjamin's solution and because I'm using Tailwind and as of now still don't have access to all the grid options by default. This seems to work:
ul {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
}
li {
align-self: center;
}
li:nth-child(1) {
justify-content: flex-start; /* OR margin-right: auto */
}
li:nth-child(3) {
justify-content: flex-end; /* OR margin-left:auto */
}
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
</ul>
PS: Not sure if mixing up flex and grid like this is a good idea!
If you want to make it aligned, you can simply attach an empty span and split the three child spans into them.
The easiest way:
.wrap {
display:flex;
}
.full-width {
width: 100%;
}
.centered {
display: flex;
justify-content:center;
}
.btn {
display: flex;
justify-content: end;
}
<div class="wrap">
<div class="full-width"></div>
<div class="full-width centered">
<div>A</div>
<div>B</div>
<div>C</div>
</div>
<div class="full-width btn">D</div>
</div>
Very clear question. I couldn't help but post the answer after a few hours of digging. We Could of solved this with tables, table-cell, absolute positions, transforms but we just had to do it with flexbox :)
.parent {
display: flex;
justify-content: flex-end;
}
.center {
margin: auto;
}
http://codepen.io/rgfx/pen/BLorgd
The accepted answer can be changed a bit because you can use grid template areas and do it without fake element
grid-template-areas '. b c'
grid-template-columns: 1fr 1fr 1fr
I expanded on Michael_B's answer
.center-flex__2-of-3 > :nth-child(1), .center-flex__2-of-3 > :nth-child(3) {
flex: 1;
}
.center-flex__2-of-3 > :nth-child(1) {
justify-content: flex-start;
}
.center-flex__2-of-3 > :nth-child(3) {
justify-content: flex-end;
}
.center-flex__1-of-2 > :nth-child(1) {
margin: auto;
}
.center-flex__1-of-2 > :nth-child(2) {
flex: 1;
justify-content: flex-end;
}
.center-flex__2-of-2 > :nth-child(1) {
flex: 1;
justify-content: flex-start;
}
.center-flex__2-of-2 > :nth-child(2) {
margin: auto;
}
.center-flex__1-of-2:before, .center-flex__1-of-1:before {
content: '';
flex: 1;
}
.center-flex__1-of-1:after, .center-flex__2-of-2:after {
content: '';
flex: 1;
}
[class*=center-flex] {
display: flex;
list-style: none;
margin: 0;
padding: 0;
border: 10px solid rgba(0, 0, 0, 0.1);
}
[class*=center-flex] > * {
display: flex;
}
li {
padding: 3px 5px;
}
2 of 3
<ul class="center-flex__2-of-3">
<span>
<li>Accusamus</li>
<li>Porro</li>
</span>
<span>
<li>Center</li>
<li>this</li>
</span>
<span>
<li>Accusamus</li>
<li>Porro</li>
<li>Culpa</li>
<li>Sit</li>
</span>
</ul>
<br><br>
1 of 2
<ul class="akex center-flex__1-of-2">
<span>
<li>Center</li>
<li>this</li>
</span>
<span>
<li>Accusamus</li>
<li>Porro</li>
<li>Culpa</li>
<li>Sit</li>
</span>
</ul>
<br><br>
2 of 2
<ul class="akex center-flex__2-of-2">
<span>
<li>Accusamus</li>
<li>Porro</li>
<li>Culpa</li>
<li>Sit</li>
</span>
<span>
<li>Center</li>
<li>this</li>
</span>
</ul>
<br><br>
1 of 1
<ul class="center-flex__1-of-1">
<span>
<li>Center</li>
<li>this</li>
</span>
</ul>
Here with the help of SASS as a codepen
ul {
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
li:last-child {
background: #ddd;
position:absolute;
right:10px;
}
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
So I'm having a problem centering items from a menu I'm making.
I have tried to put justify-content: center but that does not seem to work. Can someone help?
Right now the menu is stuck on the left corner. I want to center it.
.header2 {
background-color: rgb(190, 13, 13);
display: flex;
flex-wrap: wrap;
align-items: center;
padding: 15px;
}
.menu {
display: flex;
}
.menu li {
margin-right: 15px;
}
.menu li a {
display: block;
padding: 10px;
}
<nav class="header2">
<ul class="menu">
<li>Home</li>
<li>About</li>
<li>Products</li>
<li>Contacts</li>
</ul>
</nav>
The nested flexbox (.menu) is set, by default, to flex-grow: 0, which means it won't occupy the full length of the parent.
Therefore, applying justify-content: center has no effect because there's no free space available in the container.
Adding flex-grow: 1 provides the extra space you need:
Add this to your code:
.menu {
display: flex;
flex: 1;
justify-content: center;
}
Also, since you're already using the semantically meaningful nav element, there's really no need for a nested list element. Try this simplified code instead:
.menu {
display: flex;
justify-content: center;
background-color: rgb(190, 13, 13);
}
.menu a {
padding: 25px 10px;
}
.menu a:hover {
background-color: orangered;
}
<nav class="menu">
Home
About
Products
Contacts
</nav>
Try:
.menu {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
flex-grow: 1; /* or width: 100% */
}
if you want the elements evenly distributed by all the width.
And:
.menu {
display: flex;
flex-wrap: wrap;
justify-content: center;
flex-grow: 1; /* or width: 100% */
}
otherwise.
I have a horizontal flex box (i.e. flex-direction: row, i.e. side-by-side) with a few items. Each item can be a single line of text, or can have multiple lines. I want to vertically-align the contents of each flex item.
If each item had a transparent background, I could easily use align-items: center. However, I want each item to be stretched vertically, because I want to set a background (or maybe borders, or maybe it is a clickable region) to the entire available height.
So far, I know:
Stretching: align-items: stretch
Aligning: align-items: center
Stretching and aligning: ???
Demo available at http://codepen.io/denilsonsa/pen/bVBQNa
ul {
display: flex;
flex-direction: row;
}
ul.first {
align-items: stretch;
}
ul.second {
align-items: center;
}
ul > li {
flex-grow: 1;
flex-shrink: 0;
flex-basis: 5em;
text-align: center;
}
ul > li:nth-child(2) {
background: #CFC;
}
/* Visual styles, just ignore. */
html, body { font-family: sans-serif; font-size: 25px; }
ul, li { list-style: none; margin: 0; padding: 0; }
ul { background: #CCF; width: 25em; }
<ul class="first">
<li>Sample</li>
<li><span>span</span></li>
<li><span>multiple</span> <span>span</span></li>
<li>text <span>span</span></li>
<li>multi<br>line</li>
</ul>
<hr>
<ul class="second">
<li>Sample</li>
<li><span>span</span></li>
<li><span>multiple</span> <span>span</span></li>
<li>text <span>span</span></li>
<li>multi<br>line</li>
</ul>
Similar questions:
Question 14012030 and question 23442692 and question 27729619 and question 25311541 ask essentially the same thing, but they either have a single element or plain text as child of each flex item. As soon as we have mixed content, possibly with multiple elements, those solutions do not work.
Question 19026884 is unrelated, the issue there was the wrong markup.
Unfortunately, it is impossible to achieve the desired effect while using the exact markup posted in the question.
The solution involves:
Setting display: flex; on <li>.
Wrapping the <li> contents into another element.
This is required because <li> is now a flex container, so we need another element to prevent the actual contents from becoming flex items.
In this solution, I introduced a <div> element, but it could have been other element.
Now that <li> is a flex container and it contains only a single child, we can use align-items and/or justify-content to align this new and only child.
The DOM tree looks like this:
<ul> flex-parent, direction=row
├ <li> flex-item && flex-parent && background && JavaScript clickable area
│ └ <div> flex-item as a single transparent element
│ ├ Actual contents
│ └ Actual contents
├ …
Note: The solution in this answer uses 2 nested flex boxes. The solution by Michael_B uses 3 nested flex boxes, because it has the added challenge of expanding the <a> element to fill the entire <li>. Which one is preferred depends on each case. If I could, I would accept both answers.
/* New code: this is the solution. */
ul > li {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
/* Old code below. */
ul {
display: flex;
flex-direction: row;
align-items: stretch;
}
ul > li {
flex-grow: 1;
flex-shrink: 0;
flex-basis: 5em;
text-align: center;
}
ul > li:nth-child(2) {
background: #CFC;
}
/* Visual styles, just ignore. */
html, body { font-family: sans-serif; font-size: 25px; }
ul, li { list-style: none; margin: 0; padding: 0; }
ul { background: #CCF; width: 25em; }
button:focus + ul {
font-size: 14px;
width: auto;
}
<button>Click here to set <code>width: auto</code> and reduce the font size.</button>
<!-- New code: there is a single <div> between each <li> and their contents. -->
<ul>
<li><div>Sample</div></li>
<li><div><span>span</span></div></li>
<li><div><span>multiple</span> <span>span</span></div></li>
<li><div>text <span>span</span></div></li>
<li><div>multi<br>line</div></li>
</ul>
I want each item to be stretched vertically, because I want to set a
background (or maybe borders, or maybe it is a clickable region) to
the entire available height.
You can achieve this layout without any changes to your HTML structure. There's no need for additional containers.
You already have a primary flex container and a group of flex items. Simply make those flex items into nested flex containers. That will enable you to align the content with flex properties.
(Since you mentioned that you may need clickable regions, I switched from li to a elements.)
nav {
display: flex;
background: #CCF;
width: 25em;
}
nav > a {
flex: auto; /* flex-grow: 1, flex-shrink: 1, flex-basis: auto */
text-align: center;
text-decoration: none;
display: flex;
align-items: center;
justify-content: center;
}
nav > a:nth-child(2) {
background: #CFC;
}
html, body {
font-family: sans-serif;
font-size: 25px;
}
<nav>
Sample
<span>span</span>
<span>multiple</span> <span>span</span>
text <span>span</span>
multi<br>line
</nav>
revised codepen
Note that content placed directly inside a flex container is wrapped in an anonymous flex item:
From the spec:
4. Flex Items
Each in-flow child of a flex container becomes a flex item, and each contiguous run of text that is directly contained inside a flex
container is wrapped in an anonymous flex item.
So, because the text is automatically wrapped in flex items, you can keep the full height of each item (align-items: stretch from the primary container) and vertically center the content (align-items: center from the nested containers).
Make the li flex-containers with flex-direction:column. I think that's what you are after.
html,
body {
font-family: sans-serif;
font-size: 25px;
}
ul,
li {
list-style: none;
margin: 0;
padding: 0;
}
ul {
background: #CCF;
width: 25em;
display: flex;
flex-direction: row;
}
ul.first {
align-items: stretch;
}
ul > li {
flex-grow: 1;
flex-shrink: 0;
flex-basis: 5em;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
/*outline: 1px dotted #444;*/
}
ul > li:nth-child(2) {
background: #CFC;
}
<ul class="first">
<li>Sample</li>
<li><span>span</span>
</li>
<li><span>multiple</span> <span>span</span>
</li>
<li>text <span>span</span>
</li>
<li>multi
<br>line</li>
</ul>
Flex-child items can also be flex-parent items.
*,
*:before,
*:after {
box-sizing: inherit;
}
html {
box-sizing: border-box;
font-family: sans-serif;
font-size: 25px;
}
body {
display: flex;
flex-flow: column nowrap;
background-color: #333;
overflow: hidden;
}
html,
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
.List {
padding: 0;
margin: 0;
background: #CCF;
width: 25em;
list-style: none;
display: flex;
flex-flow: row nowrap;
justify-content: center;
}
.ListItem {
flex-basis: 5em;
display: flex;
flex-flow: row wrap;
text-align: center;
align-items: center;
}
.ListItem:nth-child(2) {
background: #CFC;
}
.ListItem__content {
width: 100%;
}
<ul class="List">
<li class="ListItem">
<span class="ListItem__content">Sample</span>
</li>
<li class="ListItem">
<span class="ListItem__content">span</span>
</li>
<li class="ListItem">
<span class="ListItem__content">multiple <br> span</span>
</li>
<li class="ListItem">
<span class="ListItem__content">span</span>
</li>
<li class="ListItem">
<span class="ListItem__content">multi<br>line</span></li>
</ul>
I have a problem centering a fixed-postioned flexbox by using margin: 0 auto;. I can change position into relative to make it look like what I want, but a fixed one is what I hope.
Please view it on JSBIN output, and if you'd like to see the code.
HTML
<header class="header l-container">
<div class="site-title"> Home</div>
<nav class="nav-box">
<ul class="menu-box">
<li>About</li>
<li>Blog</li>
<li>Contact</li>
</ul>
</nav>
</header>
CSS
/* change position into relative or fixed */
.header {
position: fixed;
z-index: 100;
}
/* some other settings below */
.l-container {
margin: 0 auto;
padding: 0 6rem;
max-width: 108rem;
}
.header,
.menu-box {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.header {
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
}
.site-title .link {
float: left;
}
.menu-box .link {
float: right;
}
ul {list-style: none;}
li {margin-left: 20px;}
.link {font-size: 20px;}
Note: I'd like to center the whole .header container and use flexbox to make the .site-title and .nav-box separated apart in both ends of .header.
How about adding left: 0 and right: 0 to your fixed .header? The max-width, margin and padding will still be applied, but it will be positioned from the left and right.
JSBin
.header {
position: fixed;
z-index: 100;
left: 0;
right: 0;
}
It will work
.header {
position: fixed;
z-index: 100;
left:0;
top:0;
}