This question already has answers here:
In CSS Flexbox, why are there no "justify-items" and "justify-self" properties?
(6 answers)
Closed 4 months ago.
For a layout, I need to have three flex items (rows) in a flex container, and I want them justified as space-between... The first row will contain some cloud tags, the second a price, and the third a Read more link.
But there will be cases where for specific items, only the last row (the Read more) will need to exist.
So, in those cases, for uniformity, I want the Read more link to be placed at the bottom of the container; but space-between doesn't help much towards that approach...
What can I do to have a fallback justify-content property set to end for when there is only one child item?
.container {
background-color: #aaa;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-end;
height: 200px;
margin-bottom: 20px;
}
.tags {
display: flex;
}
.tags span {
background-color: #f0f;
padding: 10px;
margin: 0 0 0 10px;
}
.price {
display: flex;
background-color: #ff0;
padding: 10px;
font-size: 150%
}
.read-more {
display: flex;
background-color: #0ff;
padding: 10px;
}
<div class="container">
<div class="tags">
<span>tag 1</span><span>tag2</span><span>tag 3</span>
</div>
<div class="price">
$100
</div>
<div class="read-more">
Read more >>
</div>
</div>
<div class="container">
<div class="read-more">
Read more >>
</div>
</div>
If you are able/willing to change the order of the flex-items in your HTML code, you can reverse them there and use flex-direction: column-reverse; on the container. That way the "read more" element is the first flex-item and due to the reversed direction at the bottom of the container:
.container {
background-color: #aaa;
display: flex;
flex-direction: column-reverse;
justify-content: space-between;
align-items: flex-end;
height: 200px;
margin-bottom: 20px;
}
.tags {
display: flex;
}
.tags span {
background-color: #f0f;
padding: 10px;
margin: 0 0 0 10px;
}
.price {
display: flex;
background-color: #ff0;
padding: 10px;
font-size: 150%
}
.read-more {
display: flex;
background-color: #0ff;
padding: 10px;
}
<div class="container">
<div class="read-more">
Read more >>
</div>
<div class="price">
$100
</div>
<div class="tags">
<span>tag 1</span><span>tag2</span><span>tag 3</span>
</div>
</div>
<div class="container">
<div class="read-more">
Read more >>
</div>
</div>
You can give the container a position: relative; tag, the .read-more class, and the :only-child pseudo class. Then when it is the only child in the container, it will add the attributes position:absolute; bottom:0; right:0; to it.
This moves it to the bottom right of the container. The justify-content: end !important; doesn't move the container to where you want it to be.
Example:
.container {
background-color: #aaa;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-end;
height: 200px;
margin-bottom: 20px;
position:relative;
}
.tags {
display: flex;
}
.tags span {
background-color: #f0f;
padding: 10px;
margin: 0 0 0 10px;
}
.price {
display: flex;
background-color: #ff0;
padding: 10px;
font-size: 150%
}
.read-more {
display: flex;
background-color: #0ff;
padding: 10px;
}
.read-more:only-child{
position:absolute;
bottom:0;
right:0;
}
<div class="container">
<div class="tags">
<span>tag 1</span><span>tag2</span><span>tag 3</span>
</div>
<div class="price">
$100
</div>
<div class="read-more">
Read more >>
</div>
</div>
<div class="container">
<div class="read-more">
Read more >>
</div>
</div>
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>
I'm constructing a simple layout with a title and sub-title. When the two can be displayed on one line without the text wrapping, they should do so with a small amount of spacing between them. In all other cases, the title and sub-title should occupy 100% width. There should be no margin-left on the sub title.
I have created this using Flexbox and the gap property. It renders properly in Firefox:
Here's the code:
header {
font-family: sans-serif;
background-color: rebeccapurple;
color: #fff;
padding: 0 5px;
}
.container {
max-width: 800px;
width: 100%;
flex-grow: 1;
margin-left: auto;
margin-right: auto;
}
header .container {
display: flex;
flex-wrap: wrap;
flex-direction: row;
gap: 0.5rem;
align-items: baseline;
}
<header>
<div class="container">
<h1>Long title for the page itself</h1>
<h2>Subtitle</h2>
</div>
</header>
<br />
<header>
<div class="container">
<h1>Shorter title</h1>
<h2>Subtitle</h2>
</div>
</header>
Unfortunately, popular browsers such as Google Chrome have failed to implement support for gap used in conjunction with a display: flex layout.
Is there a way I can implement this using e.g. display: inline-block elements and negative margins such that it will work in legacy browsers like Chrome and Internet Explorer?
Instead of gap: .5rem, use margin-right: .5rem on the h1.
h1 {
margin-right: .5rem;
}
.container {
max-width: 800px;
margin-left: auto;
margin-right: auto;
display: flex;
flex-wrap: wrap;
align-items: baseline;
}
header {
font-family: sans-serif;
background-color: rebeccapurple;
color: #fff;
padding: 0 5px;
}
<header>
<div class="container">
<h1>Long title for the page itself</h1>
<h2>Subtitle</h2>
</div>
</header>
<br />
<header>
<div class="container">
<h1>Shorter title</h1>
<h2>Subtitle</h2>
</div>
</header>
I would like in CSS force break-line on space and not break words like "Plan[break-line]individual"
I'm using Flexbox to make an easy responsive code.
HTML
<section class="card-container">
<div class="card card-inline text-center">
<div class="card-block">
<h4 class="card-title">Plan individual</h4>
<p class="card-text">€10.00 / year</p>
<button click="#'">Sign in</button>
</div>
</div>
...
</section>
style.css
.card-container{
display: flex;
height: inherit;
width: inherit;
}
.card{
position: relative;
display: flex;
flex-direction: column;
min-width: 0;
background-color: #fff;
background-clip: border-box;
border: 1px solid rgba(0,0,0,.125);
border-radius: .25rem;
width: 170px;
}
.card-inline{
display: inline-flex;
margin: .75rem;
}
.card-block {
flex: 1 1 auto;
padding: 1.25rem;
display: flex;
flex-direction: column;
justify-content: space-between;
}
h4.card-title{
margin: .5rem !important;
font-size: 100% !important;
}
.text-center{
text-align: center !important;
}
I tried white-space, word-wrap, flex-wrap... without success.
Does anyone have an idea how to prevent the words from being hyphenated?
The code you included doesn't give the result you show in your image, so you must have a CSS rule somewhere else that's causing it.
However, you should be able to override it with the following:
h4 {
hyphens: none;
}
For a simpler solution, just at a <br/> tag to your html in between the words. You can add a class if you want to target it with media queries to turn the break on and off based on the screen width.
Here is my attempt at what I'm trying to solve, but all answers are we:
https://jsfiddle.net/L2qukchc/
it's just doing this:
.box {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.box-front {
display: flex;
z-index: 1;
flex-direction: column;
align-items: center;
justify-content: center;
box-shadow: 0 0 5px rgba(57,70,78,1.2);
}
.box-back {
display: flex;
z-index: -1;
flex-direction: column;
align-items: center;
justify-content: center;
box-shadow: 0 0 5px rgba(57,70,78,1.2);
margin-top: -10px;
}
But I'm using negative margin (boo!).
I am using flexbox, but I want to have multiple layers [as would be attained through position:absolute and z-index]. The reason I am having trouble with absolute is that the layers are relative to each other, so writing a lot of breakpoints to solve this is not ideal.
The general question, "What are all the options with css to overlap divs", refers to whether or not I can position elements relatively but preventing my flexbox divs from making space for the newer elements I want to add [a la, layers]. Thanks!
Edit: A suggestion given to use relative layout works well:
https://jsfiddle.net/vdv09549/
wondering if there were others?
As the mentioned negative margin is not suitable for this (see sample 3), I can only think of 2, position: relative in combo with top/left and transform: translate, where I would say the latter is probably the recommended one in most cases.
.parent {
display: flex;
height: 100px;
}
.parent ~ .parent {
margin-top: 30px;
}
.child {
flex: 1;
border: 1px dashed #000;
}
.parent.nr1 .child.nr2 {
position: relative;
left: -20px;
top: 20px;
}
.parent.nr2 .child.nr2 {
transform: translate(-20px,20px);
}
.parent.nr3 .child.nr2 {
margin-left: -20px;
margin-top: 20px;
}
<div class="parent nr1">
<div class="child">Sample 1
</div>
<div class="child nr2">
</div>
</div>
<div class="parent nr2">
<div class="child">Sample 2
</div>
<div class="child nr2">
</div>
</div>
<div class="parent nr3">
<div class="child">Sample 3
</div>
<div class="child nr2">
</div>
</div>