Add dividing line between flex items with equal space distribution
I think the only way to accomplish this with flexbox is to wrap the text in a new element, as @Kukkuz has done in another answer.
Without that extra wrapper, you can still get the equal spaced dividers, but the red background isn't confined to the length of the text.
Below is an example with:
- No changes to the HTML.
- No need for pseudo elements.
- No need for absolute positioning.
If a background color for the text isn't necessary, then remove it and this should be all you need.
.Flex {
display: flex;
list-style: none;
margin: 0;
padding: 0;
}
.Flex-item {
flex: 1 1 auto;
background: red;
}
.Flex-item {
text-align: center;
}
.Flex-item:first-child {
text-align: left;
}
.Flex-item:last-child {
text-align: right;
}
.Flex-item + .Flex-item {
border-left: 1px solid white;
}
.Container {
max-width: 70%;
margin-right: auto;
margin-left: auto;
background: blue;
padding-top: 20px;
padding-bottom: 20px;
}
<div class="Container">
<ul class="Flex">
<li class="Flex-item">Lorem</li>
<li class="Flex-item">consectetur</li>
<li class="Flex-item">vestibulum</li>
<li class="Flex-item">nec</li>
<li class="Flex-item">condimentum</li>
</ul>
</div>
If you can add a span
around the text, which will allow you to limit the red background to the length of the text, then you're all set:
.Flex {
display: flex;
list-style: none;
margin: 0;
padding: 0;
}
.Flex-item {
flex: 1 1 auto;
display: inline-flex;
justify-content: center;
}
.Flex-item span {
background-color: red;
}
.Flex-item:first-child span {
margin-right: auto;
}
.Flex-item:last-child span {
margin-left: auto;
}
.Flex-item + .Flex-item {
border-left: 1px solid white;
}
.Container {
max-width: 70%;
margin-right: auto;
margin-left: auto;
background: blue;
padding-top: 20px;
padding-bottom: 20px;
}
<div class="Container">
<ul class="Flex">
<li class="Flex-item"><span>Lorem</span></li>
<li class="Flex-item"><span>consectetur</span></li>
<li class="Flex-item"><span>vestibulum</span></li>
<li class="Flex-item"><span>nec</span></li>
<li class="Flex-item"><span>condimentum</span></li>
</ul>
</div>
Instead of :after
use a stylistic, ARIA representational LIs
<li class="separator" aria-hidden="true" role="presentation"></li>
like:
.Container {
max-width: 70%;
margin: 0 auto;
background: blue;
}
.Flex {
display: flex;
justify-content: space-between;
list-style: none; padding: 20px 0; margin:0;
}
.Flex-item {
background: red;
}
.separator {
background: white; width: 1px;
}
<div class="Container">
<ul class="Flex">
<li class="Flex-item">Lorem</li>
<li class="separator" aria-hidden="true" role="presentation"></li>
<li class="Flex-item">consectetur</li>
<li class="separator" aria-hidden="true" role="presentation"></li>
<li class="Flex-item">vestibulum</li>
<li class="separator" aria-hidden="true" role="presentation"></li>
<li class="Flex-item">nec</li>
<li class="separator" aria-hidden="true" role="presentation"></li>
<li class="Flex-item">condimentum</li>
</ul>
</div>
P.S: yes, I tried using display: list-item
initially on the :after
pseudo but naah.
I'm using this solution on a project I'm working on.
It sets justify-content: space-between;
on the flex container and flex: 1 1 auto;
on the children with a left border on all childrens except first.
I modified your example CSS so you can have a look. I wasn't sure if you were going to have background color on the children so I just used line-height to get larger borders.
html {
box-sizing: border-box;
}
.Container {
max-width: 70%;
margin-right: auto;
margin-left: auto;
background: blue;
padding-top: 20px;
padding-bottom: 20px;
}
.Flex {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
list-style: none;
margin: 0;
padding: 0;
}
.Flex-item {
flex: 1 1 auto;
background: red;
position: relative;
text-align: center;
line-height: 40px;
}
.Flex-item + .Flex-item {
border-left: solid 1px white;
}
/** Optional for OPs exact layout */
.Flex-item:first-child {
text-align: left;
}
.Flex-item:last-child {
text-align: right;
}
<div class="Container">
<ul class="Flex">
<li class="Flex-item">Lorem</li>
<li class="Flex-item">consectetur</li>
<li class="Flex-item">vestibulum</li>
<li class="Flex-item">nec</li>
<li class="Flex-item">condimentum</li>
</ul>
</div>
No modification to HTML.
You can make it work by using a nested flexbox
es - I understand you can't change the markup, but at least you have to wrap the contents of the li
into a span
like I have here:
Make
.flex-item
also aflexbox
with the text in aspan
(this would have the red background now) and the separator as an:after
elementApply
flex-grow
andflex-shrink
to 1 andflex-basis
toauto
for theFlex-item
.The
flex: 0
to the lastFlex-item
andmargin-auto
to the:after
also contributes to the effect.
A demo may explain it better - see below:
html {
box-sizing: border-box;
}
.Container {
max-width: 70%;
margin-right: auto;
margin-left: auto;
background: blue;
padding-top: 20px;
padding-bottom: 20px;
}
.Flex {
display: flex;
justify-content: space-between;
list-style: none;
margin: 0;
padding: 0;
}
.Flex-item {
display: flex;
justify-content: space-between;
align-items: center;
flex: 1 1 auto;
}
.Flex-item span {
background: red;
}
.Flex-item:not(:last-child):after {
content: "";
border: 1px solid white;
height: 40px;
margin: auto;
}
.Flex-item:last-child {
flex: 0;
}
<div class="Container">
<ul class="Flex">
<li class="Flex-item">
<span>Lorem</span>
</li>
<li class="Flex-item">
<span>consectetur</span>
</li>
<li class="Flex-item">
<span>vestibulum</span>
</li>
<li class="Flex-item">
<span>nec</span>
</li>
<li class="Flex-item">
<span>condimentum</span>
</li>
</ul>
</div>