How to center flexbox sticky footer with a set width - html

I'm using flexbox to make my footer stick to the bottom, and for the most part it's working. My problem is, I need the content to be within a specified width, that I set with max-width and center with margin-left:auto; and margin-right:auto;. When I activate flexbox, the contents are squished by the margin-left and margin-right rules, and do not take up the space defined by max-width. I would like to know why this is happening and how to get my footer to look how I want it to look.
Here is how I want my footer to look:
And here is how flexbox is affecting it:
body {
display: flex;
flex-direction: column;
min-height: 100%;
}
div#content {
flex: 1 0 auto;
}
footer {
flex: 0 0 auto;
max-width: 67.5rem;
margin-left: auto;
margin-right: auto;
padding-left: 1.25rem;
padding-right: 1.25rem;
padding-bottom: 1.875rem;
padding-top: 3.5rem;
}
<body>
<header>...</header>
<div id="content">...</div>
<footer>
<span id="left">left text</span>
<span id="mid">right text url#mail</span>
<span id="icons">...</span>
</footer>
</body>
If I change max-width to width then it works, but then when I test it in my browser using the device-mobile setting to see how it would look on a mobile device, the width property makes the footer too big and messes up the content. If I take out the margin-left and margin-right properties, then my footer looks like this:
As you can see it's no longer centered. I can't use the flex-basis property because that only affects the height of the footer. Please help.
Edit
Here is a snippet with margin-left and margin-right taken out and replaced with display:flex; and justify-content:space-around;. Be sure to click "Full page" to view with a larger viewport.
body {
display: flex;
flex-direction: column;
min-height: 100%;
}
div#content {
flex: 1 0 auto;
}
footer {
flex: 0 0 auto;
max-width: 67.5rem;
padding-left: 1.25rem;
padding-right: 1.25rem;
padding-bottom: 1.875rem;
padding-top: 3.5rem;
display: flex;
justify-content: space-around;
}
<body>
<header>...</header>
<div id="content">...</div>
<footer>
<span id="left">left text</span>
<span id="mid">right text url#mail</span>
<span id="icons">...</span>
</footer>
</body>

This can be done easily with justify-content: space-between;, but looking at your code I feel you may misunderstand a bit how Flexbox itself works. You want your footer to act as a flex container so you can manipulate the child spans as well.
Consider checking out freeCodeCamp's Flexbox Challenges to get a better idea how Flexbox works.
EDIT: CodePen now reflects what OP was meaning to immitate.
Here's a CodePen to play around with.
What this does is makes your footer both a child and container.
First your body becomes a container to allow the main content to grow to fill the space pushing your footer to the bottom of the page. The flex-direction is set to column to flow vertically.
You create a wrapper for your footer, because currently your footer is in the body container which is set to flex-direction:column; where in this case, you want the direction to be row to style horizontally. By default display:flex; will assume you wanted row so direction doesn't need declared. We then justify-content to the center so no matter the width the footer itself will be centered.
You treat your <footer> as both a child and container. As a child we tell it not to grow or shrink and set the basis to auto. As a container, we tell it to distribute space-between its children which allows a consistently equal amount of space between the left & right spans.
body {
display: flex;
height: 100%;
flex-direction: column;
}
.main {
flex: 1 0 auto;
border: 1px solid #000;
}
.wrapper {
display: flex;
justify-content: center;
}
footer {
flex: 0 0 auto;
display: flex;
margin: 1em;
width: 80%;
border: 1px solid #000;
justify-content: space-between;
}
<body>
<div class="main">
<h1>Hello Flex</h1>
<p>This is Flexbox</p>
<h1>Hello Flex</h1>
<p>This is Flexbox</p>
</div>
</body>
<div class="wrapper">
<footer>
<span id="left">left text</span>
<span id="mid">right text url#mail</span>
</footer>
</div>

I gave up trying to get this to center with flexbox. Instead I used the calc function to calculate the padding-left and padding-right of my <footer> tag. Here is what I came up with (I'm using 47.5rem instead of 67.5rem because I think it's easier to see the behavior).
body {
display: flex;
flex-direction: column;
min-height: 100%;
}
div#content {
flex: 1 0 auto;
}
footer {
flex: 0 0 auto;
display: flex;
align-items: center;
padding-left: calc(((100vw - 47.5rem)/2) + 1.25rem);
padding-right: calc(((100vw - 47.5rem)/2) + 1.25rem);
padding-bottom: 1.875rem;
padding-top: 3.5rem;
}
#left {
flex: 1;
order: 1;
}
#mid {
flex: 0 0 auto;
order: 2;
}
#icons {
order: 3;
}
<body>
<header>...</header>
<div id="content">...</div>
<footer>
<span id="left">left text</span>
<span id="mid">right text url#mail</span>
<span id="icons">...</span>
</footer>
</body>

Related

Flex box isn't filling remaining space when using flex-grow 1

I am trying to fill the remaining space of a containing flex box with the green div. I want the top flex row (blue) to only be the height of its contents and then the row below (green) to fill the rest. For some reason it just seems to split the flex rows evenly down the div. I have read a few questions on here already which all say to make sure the containing div has its height set to 100%. I have set the containing div height to 200px as this is my desired height, but I have also tried adding another container within this to 100% to no avail. I've also made sure to set the flex-grow property on the second row to 1. Every time I think I'm beginning to understand flex it throws another curve ball and it's driving me up the wall. Please help! Thank you.
P.S. for some reason the HTML code snippet below refuses to include the first line of my html but it is contained in the following div: <div class="rmCtrlList_item"
.rmCtrlList_item {
width: 80vw;
margin: 3vw 8.5vw;
height: 200px;
background-color: $primary-color;
border-radius: 10px;
padding: 5px;
display: flex;
flex-flow: row;
flex-wrap: wrap;
// ROWS
&_row {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
#row-1 {
//max-height: 20px;
background-color: blue;
}
#row-2 {
flex-grow: 1;
align-items: center;
justify-content: center;
background-color: green;
}
// COLUMNS
&_col {
text-align: left;
flex-direction: column;
}
#col-1b {
flex-grow: 1;
}
}
<div class="rmCtrlList_item">
<div class="rmCtrlList_item_row" id="row-1">
<div class="rmCtrlList_item_col" id="col-1a">
<i class="icon__panel-2 fas fa-lightbulb"></i>
</div>
<div class="rmCtrlList_item_col" id="col-1b">
<a href="lights.html">
<h1 class="panel__title">Lights</h1>
</a>
</div>
<div class="rmCtrlList_item_col" id="col-1c">
<i class="icon__enlarge fas fa-plus-circle"></i>
</div>
</div>
<div class="rmCtrlList_item_row" id="row-2">
div to fill remaining space
</div>
</div>
how about to use flex-direction and below code what I used? green will fill ramaining space automatically, if you use its height's 100%
.container{
display: flex;
flex-direction: column;
width: 200px;
height: 300px;
border: 1px solid black;
}
.blue{
width: 100%;
height: 90px; /*change only blue's height size, green will be filled automatically*/
background: blue;
}
.green{
width: 100%;
height: 100%;
background: green;
}
<div class="container">
<div class="blue"></div>
<div class="green"></div>
</div>

Confusion when combining flex and absolute positioning

I have an app that is essentially a header, main content, and a footer which is always visible. The footer can change size, and there are some tools I want to place on the main content panel above the footer. The main layout is done with flex, and my understanding reading the docs is that absolute positioning combines with flex layouts by positioning relative to the nearest descendant, but that doesn't appear to be my experience. Hoping someone can help me out here.
In the code example below, I am expecting to see the "bottom" div positioned above the footer, but it's actually at the bottom of the window.
Here's the jsfiddle link: http://jsfiddle.net/L809zbey/
The HTML:
<div class="flex">
<div class="header">Sweet header</div>
<div class="content">Main content
<div class="bottom">
This guy should be fixed above the footer.
</div>
</div>
<div class="footer">Equally sweet footer</div>
</div>
CSS:
.flex{
border: 1px solid #ddd;
font: 14px Arial;
display: flex;
flex-direction: column;
}
.header{
background : #007AA2;
flex: 0 0 auto;
}
.content{
background : #FFF;
flex: 1 1 auto;
height: 200px;
}
.footer{
background : #7FCADE;
flex: 0 0 auto;
}
.bottom {
position: absolute;
bottom: 20px;
}
Try adding position:relative; to your .flex class. The .bottom element is currently relative to the body hence why it's stuck to the bottom of the page.
you'll want to add position: relative; to .flex. Things that are positioned absolutely will be positioned relative to the nearest positioned ancestor. If there are none it will be relative to the body
You don't need to position the element absolutely...just make sure it's always at the bottom of the .content div. In this way it will never overlay any actual content which it would do if it has absolute position.
You can achieve this by making the .content div a flex-column and applying margin-top:auto your tools div.
.flex {
border: 1px solid #ddd;
font: 14px Arial;
display: flex;
flex-direction: column;
}
.header {
background: #007AA2;
flex: 0 0 auto;
}
.content {
background: pink;
flex: 1;
display: flex;
flex-direction: column;
height: 200px;
}
.footer {
background: #7FCADE;
flex: 0 0 auto;
}
.bottom {
margin-top: auto;
background: orange;
}
<div class="flex">
<div class="header">Sweet header</div>
<div class="content">Main content
<div class="bottom">
This guy should be fixed above the footer.
</div>
</div>
<div class="footer">Equally sweet footer</div>
</div>

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>

image is not resizing in a flexbox layout

I tried to follow the advice in this answer, and as shown in this CodePen, but the image that needs to flex is still keeping its original dimensions unless the screen is so narrow it is alone on the row.
There is another set of divs in the real page in a similar situation - it would help the page work across a much larger range of widths if the side divs would shrink.
The div it is wrapped in has flex: auto; on it and img {width: 90%; height: auto;} for any image in it, the parent of that div has style="flex: 0 1 250px;" on it.
Here is a CodePen of it.
I guess there is a simple mistake, if not I suppose I'll make the image the background of the div it is currently in, and set background-size: 100% auto; on it.
section {
padding: 15px;
display: flex;
flex-wrap: wrap;
margin-top: 3vw;
margin-left: 6vw;
}
.outerDiv {
background-color: rgba(50, 50, 0, 0.5);
}
.innerDiv {
background-color: rgba(10, 10, 10, 0.6);
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
margin: 15px;
}
.innerDiv p {
padding: 6px 18px 0 15px;
}
.imgResize {
flex: auto;
align-self: center;
padding: 15px;
}
.imgResize img {
width: 90%;
height: auto;
}
<section>
<div class="outerDiv">
<div class="innerDiv" style="flex: 0 1 250px;">
<h2>The Rocket Equation</h2>
<p>Mass ratio:</p>
<div class="imgResize">
<a href="rotovator.html">
<img src="http://www.moonwards.com/img/animatedRotovatorLink.png">
</a>
</div>
</div>
</div>
<div class="outerDiv">
<div class="innerDiv">
<h2>Suborbital Hop</h2>
<img src="http://www.moonwards.com/img/mapmini.jpg" width="512" height="256">
<canvas id="subOrbitalCanvas" width="512" height="256"></canvas>
</div>
</div>
</section>
An initial setting on flex items is min-width: auto. This means that a flex item, by default, cannot shrink below the size of its content.
In this case, the section element is the primary flex container.
The flex items are .outerDiv.
Because these flex items contain images, they cannot shrink below the image's size. To overcome this, override the default with min-width: 0.
revised codepen
Okay, so now the item can shrink past the content, but the image is still inflexible.
You can fix that with:
img { width: 100%; height: auto; }
revised codepen
Here's more information: Why doesn't flex item shrink past content size?

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>