38

Situation:

I have a simple nav bar that I'm building in Flexbox. I want to float one item to the left and keep the others pegged to the right.

Example:

<nav>
  <ul class="primary-nav">
    <li><a href="#" id="item1">ListItem1</a></li>
    <li><a href="#" id="item2">ListItem2</a></li>
    <li><a href="#" id="item3">ListItem3</a></li>
    <li><a href="#" id="item4">ListItem4</a></li>
  </ul>
</nav> 

Problem

Typically answers involve just floating items left and right but supposedly in Flexbox it is bad to use Floats. I was thinking about using justify-content and using flex-start and flex-end but that Isn't working out too well.

I tried applying flex-start to the first item and then flex-end to the others but that didn't work so well.

Like So:

.primary-nav #item1 {
  justify-content: flex-start;
}

.primary-nav #item2 {
  justify-content: flex-end;
}

.primary-nav #item3 {
   justify-content: flex-end; 
}

.primary-nav #item4 {
    justify-content: flex-end;    
}

Praise and thanks to anyone who has Flexbox skills and can help show me the proper way to handle this situation. :)

Nick Pineda
  • 6,354
  • 11
  • 46
  • 66

4 Answers4

53

If you're looking to have just one element on the left and all others on the right, the simplest solution is to use justify-content:flex-end on the parent element to move all elements to the right and then add margin-right:auto to the element you want to have on the left

.primary-nav {
    display:-webkit-flex;
    display:flex;
    list-style-type:none;
    padding:0;
    justify-content:flex-end;
}

.left {
    margin-right:auto;
}
<nav>
  <ul class="primary-nav">
    <li class="left"><a href="#">ListItem1</a></li>
    <li class="right"><a href="#">ListItem2</a></li>
    <li class="right"><a href="#">ListItem3</a></li>
    <li class="right"><a href="#">ListItem4</a></li>
  </ul>
</nav> 
mmgross
  • 3,064
  • 1
  • 23
  • 32
  • Awesome that looks good! If we extended it to 2 items floating left is the solution a lot more trickier? – Nick Pineda May 31 '15 at 04:55
  • 1
    This does not work in IE v10. Try to remove the line `justify-content:flex-end;`, it will then work in all browsers. – Paskins Loe May 09 '16 at 08:30
  • This only works in the convenient situation where you only have a single item to be on the far end – vsync Oct 12 '16 at 15:46
  • 1
    @vsync If by "far end" you mean on the left side, you're absolutely right. That's also the very first thing I mention in my answer. If you mean something else that I've missed: Please explain, so I can update my answer. – mmgross Oct 17 '16 at 08:43
37

There is no need for margin hacks or pseudo-elements.

Simply create a division in your flex container and make the flex container justify by space between.

Inside the first division you put the items that will be on left, and inside the second division you put the items that will be on right.

nav.menu{
    display: flex;
    justify-content: space-between;
}
nav.menu ul{
    margin: 0;
    padding: 0;
    list-style: none;
}
nav.menu ul li{
    display: inline-block;
}
<nav class="menu">
    <ul class="menu-left">
        <li><a href="#">HOME</a></li>
        <li><a href="#">SERVICES</a></li>
    </ul>
    <ul class="menu-right">
        <li><a href="#">MEMBERS</a></li>
        <li><a href="#">CONTACT</a></li>
        <li><a href="#">PROFILE</a></li>
    </ul>
</nav>
leoap
  • 1,684
  • 3
  • 24
  • 32
14

You can insert a pseudo-element at the right place and make it grow to fill the available space.

.primary-nav::after {
  content: '';
  flex-grow: 1;
  order: 0;
}
.right {
  order: 1;
}

.primary-nav {
  display: flex;
  list-style-type: none;
  padding: 0;
}
.primary-nav::after {
  content: '';
  flex-grow: 1;
  order: 0;
}
.right {
  order: 1;
}
.left, .right {
  border: 1px solid;
  padding: 0 5px;
}
<ul class="primary-nav">
  <li class="left">Left 1</li>
  <li class="right">Right 1</li>
  <li class="right">Right 2</li>
  <li class="right">Right 3</li>
</ul>
<ul class="primary-nav">
  <li class="left">Left 1</li>
  <li class="left">Left 2</li>
  <li class="right">Right 1</li>
  <li class="right">Right 2</li>
</ul>
<ul class="primary-nav">
  <li class="left">Left 1</li>
  <li class="left">Left 2</li>
  <li class="left">Left 3</li>
  <li class="right">Right 1</li>
</ul>
<ul class="primary-nav">
  <li class="left">Left 1</li>
  <li class="right">Right 1</li>
  <li class="left">Left 2</li>
  <li class="right">Right 2</li>
  <li class="left">Left 3</li>
  <li class="right">Right 3</li>
</ul>
Oriol
  • 274,082
  • 63
  • 437
  • 513
2

Here's a more CSS-concise form of mmgross's solution:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html><head><title></title>
<style type="text/css">
.container {
    display:flex;
    list-style-type:none;
    padding:0;
}

.container > li:first-child {
    margin-right:auto;
}

td { border:1px black solid } /* for debug */
</style>
</head>
<body>
<table>
<tr><td colspan=2>
  <ul class="container">
    <li>leftitem</li>
    <li>rightitem</li>
  </ul>
<tr><td>otherotherotherother<td>otherotherotherother
</table>

yielding:

enter image description here

Fiddle: https://jsfiddle.net/hbszf61x/ . Ignore the red - this is due to a JSfiddle bug. The code is valid https://i.stack.imgur.com/V9hWZ.png

ChrisJJ
  • 2,191
  • 1
  • 25
  • 38