Keep one element centered between two elements of different widths in flexbox - html

I am making a music playback controller, and the container has 3 sections: left, center, and right. However, since the left and right sides have different widths, the center section isn't in the true center of the div, but I need it to be. I am using flexbox's space-between option to layout the items.
#container {
display: flex;
justify-content: space-between;
background-color: lightgrey;
}
#container > div {
height: 100px;
border: 2px dashed red;
/*This is only for looks*/
text-align: center;
padding: 5px;
}
<div id="container">
<div>Left Side</div>
<div>I want this centered</div>
<div>Right Side (Extra text for extra length)</div>
</div>

You can use margins to approximate centering. But in order to get perfect centering with flexbox that's consistent across a variety of viewports, you'll have to slightly modify your HTML somewhat.
You need to turn the direct children of #container into flex containers themselves with a display:inline-flex declaration and give them a flex value of 1 and justify-content: center.
From there, you add your content into child divs. To get alignment on the left and right divs, use margin-right: auto and margin-left: auto, respectively.
#container {
display: flex;
background-color: lightgrey;
}
.flex {
flex: 1;
display: inline-flex;
justify-content: center;
}
.flex > div {
height: 100px;
border: 2px dashed red;
text-align: center;
padding: 5px;
}
.left div {
margin-right: auto;
}
.right div {
margin-left: auto;
}
<div id="container">
<div class="left flex">
<div>Left Side</div>
</div>
<div class="center flex">
<div>I want this centered</div>
</div>
<div class="right flex">
<div>Right Side (Extra text for extra length)</div>
</div>
</div>

Related

CSS Flexbox float elements [duplicate]

This question already has answers here:
Is it possible for flex items to align tightly to the items above them?
(5 answers)
Make a div span two rows in a grid
(2 answers)
Closed 5 years ago.
I'm trying to float two elements at the right of a "figure" element using flex but it end up floating just div1 at the right of figure and div2 is moved bellow, if I make div1 and div2 narrow enough, they are floated inline at the right of figure.
This is the CSS:
.container {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
}
Desired Result:
Actual Result:
How it works?
First, you make a flex-container (flexc in this case) and apply the display:flex property on it which aligns the elements by default in row alignment. If you want an element to preserve its dimensions set it to flex:0 0 auto; else you can make use of flex:1; which shrinks or grows as the browser is resized.
Then to align the contents in column (div1 and div2) you can just wrap then in a different container and since div isn't an inline container, and the flex property doesn't have any effect on any other than the direct children of the flex parent, they are aligned in seperate lines.
.flexc {
display: flex;
justify-content: flex-start;
}
#fig {
flex: 0 0 auto;
width: 200px;
height: 200px;
background: gray;
text-align: center;
color: white;
margin: 10px;
border: 2px solid black;
}
#d1,
#d2 {
width: 200px;
height: 50px;
background: purple;
text-align: center;
color: white;
margin: 10px;
border: 2px solid black;
}
<div class="flexc">
<div id="fig">Figure</div>
<div class="col">
<div id="d1">div1</div>
<div id="d2">div2</div>
</div>
</div>
Without altering the html:
.flexc {
display: flex;
flex-direction:column;
position:relative;
}
#fig {
flex: 0 0 auto;
width: 200px;
height: 200px;
background: gray;
text-align: center;
color: white;
margin: 10px;
border: 2px solid black;
}
#d1,
#d2 {
position:absolute;
left:250px;
width: 200px;
height: 50px;
background: purple;
text-align: center;
color: white;
margin: 10px;
border: 2px solid black;
}
#d2{
top:70px;
}
<div class="flexc">
<div id="fig">Figure</div>
<div id="d1">div1</div>
<div id="d2">div2</div>
</div>
Not sure what your HTML looks like, but display: flex is best used on the container wrapping all the elements you want aligned. Imagine it to be the largest box that you put smaller boxes inside.
Codepen example demonstrating this: https://codepen.io/corviday/pen/VyYdar
Following this hierarchy with .container as your largest box, since you want two columns, you can divide it further into two smaller boxes (.left in red and .right in blue in this case).
From there you would need to group div1/div2 together to float the way you'd like, and would be the items that fill the box .right.
You can use Bootstrap to resolve or put div1 and div2 in one div main to drop div main
Bootstrap exemple
<div class='container'>
<div class="col-md-12">
<div class="col-md-6">
1 text
</div>
<div class="col-md-6">
<div class="col-md-6">
2 text
</div>
<div class="col-md-6">
3 text
</div>
</div>
</div>
</div>
I think the best layout engine to use for your use case is hinted at in your description of the problem: Floats.
Here is a solution that doesn't require you to alter your html.
<div class="container">
<div class="medium-box">figure</div>
<div class="small-box">div 1</div>
<div class="small-box">div 2</div>
</div>
.container{
width: 500px;
}
.medium-box {
height: 200px;
width: 200px;
margin: 10px;
background: grey;
float:left
}
.small-box {
float:left;
height: 30px;
width: 200px;
background: blue;
margin: 10px;
}
https://codepen.io/stacyvlasits/pen/aVPZbY

CSS Flexbox how to centre divs which are different size? [duplicate]

Imagine the following layout, where the dots represent the space between the boxes:
[Left box]......[Center box]......[Right box]
When I remove the right box, I like the center box to still be in the center, like so:
[Left box]......[Center box].................
The same goes for if I would remove the left box.
................[Center box].................
Now when the content within the center box gets longer, it will take up as much available space as needed while remaining centered. The left and right box will never shrink and thus when where is no space left the overflow:hidden and text-overflow: ellipsis will come in effect to break the content;
[Left box][Center boxxxxxxxxxxxxx][Right box]
All the above is my ideal situation, but I have no idea how to accomplish this effect. Because when I create a flex structure like so:
.parent {
display : flex; // flex box
justify-content : space-between; // horizontal alignment
align-content : center; // vertical alignment
}
If the left and right box would be exactly the same size, I get the desired effect. However when one of the two is from a different size the centered box is not truly centered anymore.
Is there anyone that can help me?
Update
A justify-self would be nice, this would be ideal:
.leftBox {
justify-self : flex-start;
}
.rightBox {
justify-self : flex-end;
}
If the left and right boxes would be exactly the same size, I get the desired effect. However when one of the two is a different size the centered box is not truly centered anymore. Is there anyone that can help me?
Here's a method using flexbox to center the middle item, regardless of the width of siblings.
Key features:
pure CSS
no absolute positioning
no JS/jQuery
Use nested flex containers and auto margins:
.container {
display: flex;
}
.box {
flex: 1;
display: flex;
justify-content: center;
}
.box:first-child > span { margin-right: auto; }
.box:last-child > span { margin-left: auto; }
/* non-essential */
.box {
align-items: center;
border: 1px solid #ccc;
background-color: lightgreen;
height: 40px;
}
p {
text-align: center;
margin: 5px 0 0 0;
}
<div class="container">
<div class="box"><span>short text</span></div>
<div class="box"><span>centered text</span></div>
<div class="box"><span>loooooooooooooooong text</span></div>
</div>
<p>↑<br>true center</p>
Here's how it works:
The top-level div (.container) is a flex container.
Each child div (.box) is now a flex item.
Each .box item is given flex: 1 in order to distribute container space equally (more details).
Now the items are consuming all space in the row and are equal width.
Make each item a (nested) flex container and add justify-content: center.
Now each span element is a centered flex item.
Use flex auto margins to shift the outer spans left and right.
You could also forgo justify-content and use auto margins exclusively.
But justify-content can work here because auto margins always have priority.
8.1. Aligning with auto
margins
Prior to alignment via justify-content and align-self, any
positive free space is distributed to auto margins in that dimension.
Use three flex items in the container
Set flex: 1 to the first and last ones. This makes them grow equally to fill the available space left by the middle one.
Thus, the middle one will tend to be centered.
However, if the first or last item has a wide content, that flex item will also grow due to the new min-width: auto initial value.
Note Chrome doesn't seem to implement this properly. However, you can set min-width to -webkit-max-content or -webkit-min-content and it will work too.
Only in that case the middle element will be pushed out of the center.
.outer-wrapper {
display: flex;
}
.item {
background: lime;
margin: 5px;
}
.left.inner-wrapper, .right.inner-wrapper {
flex: 1;
display: flex;
min-width: -webkit-min-content; /* Workaround to Chrome bug */
}
.right.inner-wrapper {
justify-content: flex-end;
}
.animate {
animation: anim 5s infinite alternate;
}
#keyframes anim {
from { min-width: 0 }
to { min-width: 100vw; }
}
<div class="outer-wrapper">
<div class="left inner-wrapper">
<div class="item animate">Left</div>
</div>
<div class="center inner-wrapper">
<div class="item">Center</div>
</div>
<div class="right inner-wrapper">
<div class="item">Right</div>
</div>
</div>
<!-- Analogous to above --> <div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">Left</div></div><div class="center inner-wrapper"><div class="item animate">Center</div></div><div class="right inner-wrapper"><div class="item">Right</div></div></div><div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">Left</div></div><div class="center inner-wrapper"><div class="item">Center</div></div><div class="right inner-wrapper"><div class="item animate">Right</div></div></div>
The key is to use flex-basis. Then the solution is simple as:
.parent {
display: flex;
justify-content: space-between;
}
.left, .right {
flex-grow: 1;
flex-basis: 0;
}
CodePen is available here.
Here's an answer that uses grid instead of flexbox. This solution doesn't require extra grandchild elements in the HTML like the accepted answer does. And it works correctly even when the content on one side gets long enough to overflow into the center, unlike the grid answer from 2019.
The one thing this solution doesn't do is show an ellipsis or hide the extra content in the center box, as described in the question.
section {
display: grid;
grid-template-columns: 1fr auto 1fr;
}
section > *:last-child {
white-space: nowrap;
text-align: right;
}
/* not essential; just for demo purposes */
section {
background-color: #eee;
font-family: helvetica, arial;
font-size: 10pt;
padding: 4px;
}
section > * {
border: 1px solid #bbb;
padding: 2px;
}
<section>
<div>left</div>
<div>center</div>
<div>right side is longer</div>
</section>
<section>
<div>left</div>
<div>center</div>
<div>right side is much, much longer</div>
</section>
<section>
<div>left</div>
<div>center</div>
<div>right side is much, much longer, super long in fact</div>
</section>
Instead of defaulting to using flexbox, using grid solves it in 2 lines of CSS without additional markup inside the top level children.
HTML:
<header class="header">
<div class="left">variable content</div>
<div class="middle">variable content</div>
<div class="right">variable content which happens to be very long</div>
</header>
CSS:
.header {
display: grid;
grid-template-columns: [first] 20% auto [last] 20%;
}
.middle {
/* use either */
margin: 0 auto;
/* or */
text-align: center;
}
Flexbox rocks but shouldn't be the answer for everything. In this case grid is clearly the cleanest option.
Even made a codepen for your testing pleasure:
https://codepen.io/anon/pen/mooQOV
You can do this like so:
.bar {
display: flex;
background: #B0BEC5;
}
.l {
width: 50%;
flex-shrink: 1;
display: flex;
}
.l-content {
background: #9C27B0;
}
.m {
flex-shrink: 0;
}
.m-content {
text-align: center;
background: #2196F3;
}
.r {
width: 50%;
flex-shrink: 1;
display: flex;
flex-direction: row-reverse;
}
.r-content {
background: #E91E63;
}
<div class="bar">
<div class="l">
<div class="l-content">This is really long content. More content. So much content.</div>
</div>
<div class="m">
<div class="m-content">This will always be in the center.</div>
</div>
<div class="r">
<div class="r-content">This is short.</div>
</div>
</div>
Here is another way to do it, using display: flex in the parents and childs:
.Layout{
display: flex;
justify-content: center;
}
.Left{
display: flex;
justify-content: flex-start;
width: 100%;
}
.Right{
display: flex;
justify-content: flex-end;
width: 100%;
}
<div class = 'Layout'>
<div class = 'Left'>I'm on the left</div>
<div class = 'Mid'>Centered</div>
<div class = 'Right'>I'm on the right</div>
</div>
A slightly more robust grid solution looks like this:
.container {
overflow: hidden;
border-radius: 2px;
padding: 4px;
background: orange;
display: grid;
grid-template-columns: minmax(max-content, 1fr) auto minmax(max-content, 1fr);
}
.item > div {
display: inline-block;
padding: 6px;
border-radius: 2px;
background: teal;
}
.item:last-child > div {
float: right;
}
<div class="container">
<div class="item"><div contenteditable>edit the text to test the layout</div></div>
<div class="item"><div contenteditable>just click me and</div></div>
<div class="item"><div contenteditable>edit</div></div>
</div>
And here you can see it in Codepen: https://codepen.io/benshope2234/pen/qBmZJWN
I wanted the exact result shown in the question, I combined answers from gamliela and Erik Martín Jordán and it works best for me.
.parent {
display: flex;
justify-content: space-between;
}
.left, .right {
flex-grow: 1;
flex-basis: 0;
}
.right {
display: flex;
justify-content: flex-end;
}
you can also use this simple way to reach exact center alignment for middle element :
.container {
display: flex;
justify-content: space-between;
}
.container .sibling {
display: flex;
align-items: center;
height: 50px;
background-color: gray;
}
.container .sibling:first-child {
width: 50%;
display: flex;
justify-content: space-between;
}
.container .sibling:last-child {
justify-content: flex-end;
width: 50%;
box-sizing: border-box;
padding-left: 100px; /* .center's width divided by 2 */
}
.container .sibling:last-child .content {
text-align: right;
}
.container .sibling .center {
height: 100%;
width: 200px;
background-color: lightgreen;
transform: translateX(50%);
}
codepen: https://codepen.io/ErAz7/pen/mdeBKLG
Althought I might be late on this one, all those solutions seems complicated and may not work depending on the cases you're facing.
Very simply, just wrap the component you want to center with position : absolute, while letting the other two with justify-content : space-between, like so :
CSS:
.container {
display: flex;
justify-content: space-between;
align-items: center;
background-color: lightgray;
}
.middle {
position: absolute;
margin-left: auto;
margin-right: auto;
/* You should adapt percentages here if you have a background ; else, left: 0 and right: 0 should do the trick */
left: 40%;
right: 40%;
text-align: center;
}
/* non-essential, copied from #Brian Morearty answer */
.element {
border: 1px solid #ccc;
background-color: lightgreen;
}
p {
margin: 5px;
padding: 5px;
}
<div class="container">
<p class="element">First block</p>
<p class="middle element">Middle block</p>
<p class="element">Third THICC blockkkkkkkkk</p>
</div>
Michael Benjamin has a decent answer but there is no reason it can't / shouldn't be simplified further:
.container {
display: flex;
}
.box {
flex: 1;
display: flex;
justify-content: center;
}
.box:first-child { justify-content: left; }
.box:last-child { justify-content: right; }
And html
<div class="container">
<div class="box">short text</div>
<div class="box">centered tex</div>
<div class="box">loooooooooooooooong text</div>
</div>

How to use flex to align button with centered text but icon to one side? [duplicate]

I'm using flexbox to align my child elements. What I'd like to do is center one element and leave the other aligned to the very left. Normally I would just set the left element using margin-right: auto. The problem is that pushes the center element off center. Is this possible without using absolute positioning?
HTML & CSS
#parent {
align-items: center;
border: 1px solid black;
display: flex;
justify-content: center;
margin: 0 auto;
width: 500px;
}
#left {
margin-right: auto;
}
#center {
margin: auto;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
</div>
Add third empty element:
<div class="parent">
<div class="left">Left</div>
<div class="center">Center</div>
<div class="right"></div>
</div>
And the following style:
.parent {
display: flex;
}
.left, .right {
flex: 1;
}
Only left and right are set to grow and thanks to the facts that...
there are only two growing elements (doesn't matter if empty) and
that both get same widths (they'll evenly distribute the available space)
...center element will always be perfectly centered.
This is much better than accepted answer in my opinion because you do not have to copy left content to right and hide it to get same width for both sides, it just magically happens (flexbox is magical).
In action:
.parent {
display: flex;
}
.left,
.right {
flex: 1;
}
/* Styles for demonstration */
.parent {
padding: 5px;
border: 2px solid #000;
}
.left,
.right {
padding: 3px;
border: 2px solid red;
}
.center {
margin: 0 3px;
padding: 3px;
border: 2px solid blue;
}
<div class="parent">
<div class="left">Left</div>
<div class="center">Center</div>
<div class="right"></div>
</div>
EDIT: See Solo's answer below, it is the better solution.
The idea behind flexbox is to provide a framework for easily aligning elements with variable dimensions within a container. As such, it makes little sense to provide a layout where the width of one element is totally ignored. In essence, that is exactly what absolute positioning is for, as it takes the element out of the normal flow.
As far as I know, there is no nice way of doing this without using position: absolute;, so I would suggest using it... but If you REALLY don't want to, or can't use absolute positioning then I suppose you could use one of the following workarounds.
If you know the exact width of the "Left" div, then you could change justify-content to flex-start (left) and then align the "Center" div like this:
#center {
position: relative;
margin: auto;
left: -{half width of left div}px;
}
If you do not know the width, then you could duplicate "Left" on the right side, use justify-content: space-between;, and hide the new right element:
Just to be clear, this is really, really ugly... better to use absolute positioning than to duplicate content. :-)
#parent {
align-items: center;
border: 1px solid black;
display: flex;
justify-content: space-between;
margin: 0 auto;
width: 500px;
}
#right {
opacity: 0;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
<span id="right">Left</span>
</div>
.parent {
display: flex;
}
.left {
flex: 1;
}
.parent::after {
flex: 1;
content: '';
}
<div class="parent">
<div class="left">Left</div>
<div>Center</div>
</div>
I have another solution. In my opinion, Adding an empty block to the center element is fine but code-wise it bit ugly.
Since this is 4 years old I figured I'd update this with a much easier CSS Grid solution.
#parent {
display: grid;
grid-template-columns: repeat(3, 1fr);
border: 1px solid black;
margin: 0 auto;
width: 500px;
}
#center {
text-align: center;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
</div>
If you don't want to rely on positioning, the only way I've found that makes it truly centered is to use a combination of auto margin and negative margin prevent the centered element to getting pushed over by the left aligned element. This requires that you know the exact width of the left aligned element though.
.container {
height: 100px;
border: solid 10px skyblue;
display: flex;
justify-content: center;
}
.block {
width: 120px;
background: tomato;
}
.justify-start {
margin-right: auto;
}
.justify-center {
margin-right: auto;
margin-left: -120px;
}
<div class="container">
<div class="block justify-start"></div>
<div class="block justify-center"></div>
</div>
As far as I know this is possible with the following code.
https://jsfiddle.net/u5gonp0a/
.box {
display: flex;
justify-content: center;
background-color: green;
text-align: left;
}
.left {
padding: 10px;
background-color: pink;
}
.center {
padding: 10px;
background-color: yellow;
margin: 0 auto;
}
<div class="box">
<div class="left">left</div>
<div class="center">center</div>
</div>
Try this no hacks :)
CSS
.container{
width: 500px;
margin: 0 auto;
}
.box{
display: flex;
align-items: center;/* just in case*/
justify-content: space-between;
}
.box p:nth-child(2){
text-align: center;
background-color: lime;
flex: 1 1 0px;
}
HTML
<div class="container">
<div class="box">
<p>One</p>
<p>Two</p>
</div>
</div>
http://codepen.io/whisher/pen/XpGaEZ
If you have a grid system you can use it to do what you want without "extra" css.
Below with bootstrap (V 4.X)
Note: It uses flex under the hood
<div class="row">
<div class="col text-left">left</col>
<div class="col text-center">center</col>
<div class="col text-right">right</col>
</div>
Doc bootstrap: https://getbootstrap.com/docs/4.6/layout/grid/
Et voilà ! :)
Solution 1: give 50% width to center element and use justify-content:space-between
#parent {
display: flex;
justify-content: space-between;
}
#center {
flex-basis: 50%;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
</div>
Solution 2: Add one dummy element and hide it.
#parent {
display: flex;
justify-content: space-between;
}
#right {
visibility:hidden;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
<span id="right">Right</span>
</div>

2 Inner divs - one should be center and not collide with the other [duplicate]

I'm using flexbox to align my child elements. What I'd like to do is center one element and leave the other aligned to the very left. Normally I would just set the left element using margin-right: auto. The problem is that pushes the center element off center. Is this possible without using absolute positioning?
HTML & CSS
#parent {
align-items: center;
border: 1px solid black;
display: flex;
justify-content: center;
margin: 0 auto;
width: 500px;
}
#left {
margin-right: auto;
}
#center {
margin: auto;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
</div>
Add third empty element:
<div class="parent">
<div class="left">Left</div>
<div class="center">Center</div>
<div class="right"></div>
</div>
And the following style:
.parent {
display: flex;
}
.left, .right {
flex: 1;
}
Only left and right are set to grow and thanks to the facts that...
there are only two growing elements (doesn't matter if empty) and
that both get same widths (they'll evenly distribute the available space)
...center element will always be perfectly centered.
This is much better than accepted answer in my opinion because you do not have to copy left content to right and hide it to get same width for both sides, it just magically happens (flexbox is magical).
In action:
.parent {
display: flex;
}
.left,
.right {
flex: 1;
}
/* Styles for demonstration */
.parent {
padding: 5px;
border: 2px solid #000;
}
.left,
.right {
padding: 3px;
border: 2px solid red;
}
.center {
margin: 0 3px;
padding: 3px;
border: 2px solid blue;
}
<div class="parent">
<div class="left">Left</div>
<div class="center">Center</div>
<div class="right"></div>
</div>
EDIT: See Solo's answer below, it is the better solution.
The idea behind flexbox is to provide a framework for easily aligning elements with variable dimensions within a container. As such, it makes little sense to provide a layout where the width of one element is totally ignored. In essence, that is exactly what absolute positioning is for, as it takes the element out of the normal flow.
As far as I know, there is no nice way of doing this without using position: absolute;, so I would suggest using it... but If you REALLY don't want to, or can't use absolute positioning then I suppose you could use one of the following workarounds.
If you know the exact width of the "Left" div, then you could change justify-content to flex-start (left) and then align the "Center" div like this:
#center {
position: relative;
margin: auto;
left: -{half width of left div}px;
}
If you do not know the width, then you could duplicate "Left" on the right side, use justify-content: space-between;, and hide the new right element:
Just to be clear, this is really, really ugly... better to use absolute positioning than to duplicate content. :-)
#parent {
align-items: center;
border: 1px solid black;
display: flex;
justify-content: space-between;
margin: 0 auto;
width: 500px;
}
#right {
opacity: 0;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
<span id="right">Left</span>
</div>
.parent {
display: flex;
}
.left {
flex: 1;
}
.parent::after {
flex: 1;
content: '';
}
<div class="parent">
<div class="left">Left</div>
<div>Center</div>
</div>
I have another solution. In my opinion, Adding an empty block to the center element is fine but code-wise it bit ugly.
Since this is 4 years old I figured I'd update this with a much easier CSS Grid solution.
#parent {
display: grid;
grid-template-columns: repeat(3, 1fr);
border: 1px solid black;
margin: 0 auto;
width: 500px;
}
#center {
text-align: center;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
</div>
If you don't want to rely on positioning, the only way I've found that makes it truly centered is to use a combination of auto margin and negative margin prevent the centered element to getting pushed over by the left aligned element. This requires that you know the exact width of the left aligned element though.
.container {
height: 100px;
border: solid 10px skyblue;
display: flex;
justify-content: center;
}
.block {
width: 120px;
background: tomato;
}
.justify-start {
margin-right: auto;
}
.justify-center {
margin-right: auto;
margin-left: -120px;
}
<div class="container">
<div class="block justify-start"></div>
<div class="block justify-center"></div>
</div>
As far as I know this is possible with the following code.
https://jsfiddle.net/u5gonp0a/
.box {
display: flex;
justify-content: center;
background-color: green;
text-align: left;
}
.left {
padding: 10px;
background-color: pink;
}
.center {
padding: 10px;
background-color: yellow;
margin: 0 auto;
}
<div class="box">
<div class="left">left</div>
<div class="center">center</div>
</div>
Try this no hacks :)
CSS
.container{
width: 500px;
margin: 0 auto;
}
.box{
display: flex;
align-items: center;/* just in case*/
justify-content: space-between;
}
.box p:nth-child(2){
text-align: center;
background-color: lime;
flex: 1 1 0px;
}
HTML
<div class="container">
<div class="box">
<p>One</p>
<p>Two</p>
</div>
</div>
http://codepen.io/whisher/pen/XpGaEZ
If you have a grid system you can use it to do what you want without "extra" css.
Below with bootstrap (V 4.X)
Note: It uses flex under the hood
<div class="row">
<div class="col text-left">left</col>
<div class="col text-center">center</col>
<div class="col text-right">right</col>
</div>
Doc bootstrap: https://getbootstrap.com/docs/4.6/layout/grid/
Et voilà ! :)
Solution 1: give 50% width to center element and use justify-content:space-between
#parent {
display: flex;
justify-content: space-between;
}
#center {
flex-basis: 50%;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
</div>
Solution 2: Add one dummy element and hide it.
#parent {
display: flex;
justify-content: space-between;
}
#right {
visibility:hidden;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
<span id="right">Right</span>
</div>

Keep the middle item centered when side items have different widths

Imagine the following layout, where the dots represent the space between the boxes:
[Left box]......[Center box]......[Right box]
When I remove the right box, I like the center box to still be in the center, like so:
[Left box]......[Center box].................
The same goes for if I would remove the left box.
................[Center box].................
Now when the content within the center box gets longer, it will take up as much available space as needed while remaining centered. The left and right box will never shrink and thus when where is no space left the overflow:hidden and text-overflow: ellipsis will come in effect to break the content;
[Left box][Center boxxxxxxxxxxxxx][Right box]
All the above is my ideal situation, but I have no idea how to accomplish this effect. Because when I create a flex structure like so:
.parent {
display : flex; // flex box
justify-content : space-between; // horizontal alignment
align-content : center; // vertical alignment
}
If the left and right box would be exactly the same size, I get the desired effect. However when one of the two is from a different size the centered box is not truly centered anymore.
Is there anyone that can help me?
Update
A justify-self would be nice, this would be ideal:
.leftBox {
justify-self : flex-start;
}
.rightBox {
justify-self : flex-end;
}
If the left and right boxes would be exactly the same size, I get the desired effect. However when one of the two is a different size the centered box is not truly centered anymore. Is there anyone that can help me?
Here's a method using flexbox to center the middle item, regardless of the width of siblings.
Key features:
pure CSS
no absolute positioning
no JS/jQuery
Use nested flex containers and auto margins:
.container {
display: flex;
}
.box {
flex: 1;
display: flex;
justify-content: center;
}
.box:first-child > span { margin-right: auto; }
.box:last-child > span { margin-left: auto; }
/* non-essential */
.box {
align-items: center;
border: 1px solid #ccc;
background-color: lightgreen;
height: 40px;
}
p {
text-align: center;
margin: 5px 0 0 0;
}
<div class="container">
<div class="box"><span>short text</span></div>
<div class="box"><span>centered text</span></div>
<div class="box"><span>loooooooooooooooong text</span></div>
</div>
<p>↑<br>true center</p>
Here's how it works:
The top-level div (.container) is a flex container.
Each child div (.box) is now a flex item.
Each .box item is given flex: 1 in order to distribute container space equally (more details).
Now the items are consuming all space in the row and are equal width.
Make each item a (nested) flex container and add justify-content: center.
Now each span element is a centered flex item.
Use flex auto margins to shift the outer spans left and right.
You could also forgo justify-content and use auto margins exclusively.
But justify-content can work here because auto margins always have priority.
8.1. Aligning with auto
margins
Prior to alignment via justify-content and align-self, any
positive free space is distributed to auto margins in that dimension.
Use three flex items in the container
Set flex: 1 to the first and last ones. This makes them grow equally to fill the available space left by the middle one.
Thus, the middle one will tend to be centered.
However, if the first or last item has a wide content, that flex item will also grow due to the new min-width: auto initial value.
Note Chrome doesn't seem to implement this properly. However, you can set min-width to -webkit-max-content or -webkit-min-content and it will work too.
Only in that case the middle element will be pushed out of the center.
.outer-wrapper {
display: flex;
}
.item {
background: lime;
margin: 5px;
}
.left.inner-wrapper, .right.inner-wrapper {
flex: 1;
display: flex;
min-width: -webkit-min-content; /* Workaround to Chrome bug */
}
.right.inner-wrapper {
justify-content: flex-end;
}
.animate {
animation: anim 5s infinite alternate;
}
#keyframes anim {
from { min-width: 0 }
to { min-width: 100vw; }
}
<div class="outer-wrapper">
<div class="left inner-wrapper">
<div class="item animate">Left</div>
</div>
<div class="center inner-wrapper">
<div class="item">Center</div>
</div>
<div class="right inner-wrapper">
<div class="item">Right</div>
</div>
</div>
<!-- Analogous to above --> <div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">Left</div></div><div class="center inner-wrapper"><div class="item animate">Center</div></div><div class="right inner-wrapper"><div class="item">Right</div></div></div><div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">Left</div></div><div class="center inner-wrapper"><div class="item">Center</div></div><div class="right inner-wrapper"><div class="item animate">Right</div></div></div>
The key is to use flex-basis. Then the solution is simple as:
.parent {
display: flex;
justify-content: space-between;
}
.left, .right {
flex-grow: 1;
flex-basis: 0;
}
CodePen is available here.
Here's an answer that uses grid instead of flexbox. This solution doesn't require extra grandchild elements in the HTML like the accepted answer does. And it works correctly even when the content on one side gets long enough to overflow into the center, unlike the grid answer from 2019.
The one thing this solution doesn't do is show an ellipsis or hide the extra content in the center box, as described in the question.
section {
display: grid;
grid-template-columns: 1fr auto 1fr;
}
section > *:last-child {
white-space: nowrap;
text-align: right;
}
/* not essential; just for demo purposes */
section {
background-color: #eee;
font-family: helvetica, arial;
font-size: 10pt;
padding: 4px;
}
section > * {
border: 1px solid #bbb;
padding: 2px;
}
<section>
<div>left</div>
<div>center</div>
<div>right side is longer</div>
</section>
<section>
<div>left</div>
<div>center</div>
<div>right side is much, much longer</div>
</section>
<section>
<div>left</div>
<div>center</div>
<div>right side is much, much longer, super long in fact</div>
</section>
Instead of defaulting to using flexbox, using grid solves it in 2 lines of CSS without additional markup inside the top level children.
HTML:
<header class="header">
<div class="left">variable content</div>
<div class="middle">variable content</div>
<div class="right">variable content which happens to be very long</div>
</header>
CSS:
.header {
display: grid;
grid-template-columns: [first] 20% auto [last] 20%;
}
.middle {
/* use either */
margin: 0 auto;
/* or */
text-align: center;
}
Flexbox rocks but shouldn't be the answer for everything. In this case grid is clearly the cleanest option.
Even made a codepen for your testing pleasure:
https://codepen.io/anon/pen/mooQOV
You can do this like so:
.bar {
display: flex;
background: #B0BEC5;
}
.l {
width: 50%;
flex-shrink: 1;
display: flex;
}
.l-content {
background: #9C27B0;
}
.m {
flex-shrink: 0;
}
.m-content {
text-align: center;
background: #2196F3;
}
.r {
width: 50%;
flex-shrink: 1;
display: flex;
flex-direction: row-reverse;
}
.r-content {
background: #E91E63;
}
<div class="bar">
<div class="l">
<div class="l-content">This is really long content. More content. So much content.</div>
</div>
<div class="m">
<div class="m-content">This will always be in the center.</div>
</div>
<div class="r">
<div class="r-content">This is short.</div>
</div>
</div>
Here is another way to do it, using display: flex in the parents and childs:
.Layout{
display: flex;
justify-content: center;
}
.Left{
display: flex;
justify-content: flex-start;
width: 100%;
}
.Right{
display: flex;
justify-content: flex-end;
width: 100%;
}
<div class = 'Layout'>
<div class = 'Left'>I'm on the left</div>
<div class = 'Mid'>Centered</div>
<div class = 'Right'>I'm on the right</div>
</div>
A slightly more robust grid solution looks like this:
.container {
overflow: hidden;
border-radius: 2px;
padding: 4px;
background: orange;
display: grid;
grid-template-columns: minmax(max-content, 1fr) auto minmax(max-content, 1fr);
}
.item > div {
display: inline-block;
padding: 6px;
border-radius: 2px;
background: teal;
}
.item:last-child > div {
float: right;
}
<div class="container">
<div class="item"><div contenteditable>edit the text to test the layout</div></div>
<div class="item"><div contenteditable>just click me and</div></div>
<div class="item"><div contenteditable>edit</div></div>
</div>
And here you can see it in Codepen: https://codepen.io/benshope2234/pen/qBmZJWN
I wanted the exact result shown in the question, I combined answers from gamliela and Erik Martín Jordán and it works best for me.
.parent {
display: flex;
justify-content: space-between;
}
.left, .right {
flex-grow: 1;
flex-basis: 0;
}
.right {
display: flex;
justify-content: flex-end;
}
you can also use this simple way to reach exact center alignment for middle element :
.container {
display: flex;
justify-content: space-between;
}
.container .sibling {
display: flex;
align-items: center;
height: 50px;
background-color: gray;
}
.container .sibling:first-child {
width: 50%;
display: flex;
justify-content: space-between;
}
.container .sibling:last-child {
justify-content: flex-end;
width: 50%;
box-sizing: border-box;
padding-left: 100px; /* .center's width divided by 2 */
}
.container .sibling:last-child .content {
text-align: right;
}
.container .sibling .center {
height: 100%;
width: 200px;
background-color: lightgreen;
transform: translateX(50%);
}
codepen: https://codepen.io/ErAz7/pen/mdeBKLG
Althought I might be late on this one, all those solutions seems complicated and may not work depending on the cases you're facing.
Very simply, just wrap the component you want to center with position : absolute, while letting the other two with justify-content : space-between, like so :
CSS:
.container {
display: flex;
justify-content: space-between;
align-items: center;
background-color: lightgray;
}
.middle {
position: absolute;
margin-left: auto;
margin-right: auto;
/* You should adapt percentages here if you have a background ; else, left: 0 and right: 0 should do the trick */
left: 40%;
right: 40%;
text-align: center;
}
/* non-essential, copied from #Brian Morearty answer */
.element {
border: 1px solid #ccc;
background-color: lightgreen;
}
p {
margin: 5px;
padding: 5px;
}
<div class="container">
<p class="element">First block</p>
<p class="middle element">Middle block</p>
<p class="element">Third THICC blockkkkkkkkk</p>
</div>
Michael Benjamin has a decent answer but there is no reason it can't / shouldn't be simplified further:
.container {
display: flex;
}
.box {
flex: 1;
display: flex;
justify-content: center;
}
.box:first-child { justify-content: left; }
.box:last-child { justify-content: right; }
And html
<div class="container">
<div class="box">short text</div>
<div class="box">centered tex</div>
<div class="box">loooooooooooooooong text</div>
</div>