简体   繁体   中英

Add dividing line between flex items with equal space distribution

I have a list with different items which have auto widths (no fixed width can be given in my case). I use justify-content: space-between because my first item has to start at the beginning of the container and my last item at the end.

All of the above works fine, but whenever I try to add a line between these list items, the problems start to emerge. I have no way to determine how many px or % I have to position these lines. Is there any way to 'dynamically' position the lines between the different list-items or not?

The html we are using is not editable as it is rendered by the CMS we are using.

This is what I have:

这就是我所拥有的

This is what I try to achieve

这就是我想要实现的目标

Here is the code I currently have

 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 { background: red; position: relative; } .Flex-item:after { content: ""; position: absolute; background: white; width: 1px; height: 40px; top: 50%; transform: translateY(-50%); } 
 <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> 

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:

  1. Make .flex-item also a flexbox with the text in a span (this would have the red background now) and the separator as an :after element

  2. Apply flex-grow and flex-shrink to 1 and flex-basis to auto for the Flex-item .

  3. The flex: 0 to the last Flex-item and margin-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> 

Instead of :after try using a set of <li class="separator"></li>

 .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> 

PS: yes, I tried using display: list-item initially on the :after pseudo but naah.

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> 

Try this

 html { box-sizing: border-box; } .Container { max-width: 90%; margin-right: auto; margin-left: auto; background: blue; padding-top: 11px; padding-bottom: 50px; } .Flex { list-style: none; margin: 0; padding: 0; position: relative; left: 50%; transform: translateX(-50%); float: left; } .Flex-item { position: relative; float: left; padding: 5px 10px; border-right:1px solid #fff; } .Flex-item:last-child{border-right:none;} .Flex-item >div{ margin:0 5px; background:red; padding:5px; } 
 <div class="Container"> <ul class="Flex"> <li class="Flex-item"><div> Lorem </div></li> <li class="Flex-item"><div> consectetur </div></li> <li class="Flex-item"><div> vestibulum </div></li> <li class="Flex-item"><div> nec </div></li> <li class="Flex-item"><div> condimentum </div></li> </ul> </div> 

if you imbricate flex , you might get something close to what you try to do without any extra markup.

It involves pseudos, order & css3 selectors(fine aside flex ).

http://codepen.io/gc-nomade/pen/BpzYWP

 body { margin:0; } .Flex, .Flex-item { display:flex; padding:0.5em 0; margin:0; } .Flex-item { flex:1;/*spray them evenly*/ } .Flex-item:before, .Flex-item:after {/* add pseudos to fill extra space */ content:''; flex:1;/* thats where it takes room not use by the text */ margin:-1em 0;/* grow them taller */ border-right:solid 1px white; } .Flex-item:first-child:before { order:2;/* put both pseudo after text*/ flex:.5;/* shrink that one can be .75 to .25 */ border:none; /* remove the border useless for the show */ } .Flex-item:last-child:after { order:-1;/* put both pseudos before text */ flex:0.5;/* shrink that one can be .75 to .25 */ } .Flex-item:first-child + .Flex-item:before , .Flex-item:nth-last-child(1):after{ border:none; /* remove the border useless for the show */ } body, :after, :before { background:tomato;/* pseudo will hide li background */ } li { background:turquoise; } /* give some space around the text */ .Flex-item:first-child { padding-left:1em; } .Flex-item:last-child { padding-right:1em; } .Flex-item:before { border:none;/* we do not need those after all */ margin-right:1em; } .Flex-item:after { margin-left:1em; } .Flex-item:first-child:before { margin:-1em 0; }.Flex-item:last-child:after { margin:-1em 0; } 
 <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> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2025 STACKOOM.COM