0

I'm trying to position three elements side-by-side using flexbox, but the align-self properties are having no effect. I'm not using space-around or space-between on the parent (#subnav-cont) because each element needs to be positioned individually since the far-left element (#site-logo) is not always present.

To recap, #site-logo should sit on the far-left (when present), #site-links should be centered in relation to its parent, and #nav-social should sit on the far-right.

Demo: http://codepen.io/ourcore/pen/jyBNzZ

#subnav {
  z-index: 99999999;
  width: 100%;
  overflow: auto;
  font-size: 1.1rem;
  background-color: yellow;
}
#subnav #subnav-cont {
  display: flex;
  margin: 0 auto;
  padding: 0 1.5%;
  max-width: 1280px;
  background-color: red;
}
#subnav #subnav-cont #site-logo {
  align-self: flex-start;
  padding: 10px 0;
  height: 50px;
}
#subnav #subnav-cont #site-logo img {
  display: inline-block;
  margin: 0;
  padding: 0;
  height: 30px;
}
#subnav #subnav-cont > ul li {
  display: inline-block;
  padding: 0 20px;
  height: 50px;
  font-size: 1em;
  line-height: 50px;
  white-space: nowrap;
}
#subnav #subnav-cont #nav-links {
  align-self: center;
}
#subnav #subnav-cont #nav-social {
  align-self: flex-end;
}
#subnav #subnav-cont #nav-social li {
  padding: 0 5px;
}
<nav id="subnav">
  <div id="subnav-cont">
    <div id="site-logo">
      <img src="https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png">
    </div>
    <ul id="nav-links">
      <li>
        <a href="#" class="subnav-link">Link</a>
      </li>
      <li>
        <a href="#" class="subnav-link">Link</a>
      </li>
      <li>
        <a href="#" class="subnav-link">Link</a>
      </li>
      <li>
        <a href="#" class="subnav-link">Link</a>
      </li>
    </ul>
    <ul id="nav-social">
      <li>
        <a href="#" class="icon-facebook">Facebook</a>
      </li>
      <li>
        <a href="#" class="icon-twitter">Twitter</a>
      </li>
      <li>
        <a href="#" class="icon-instagram">Instagram</a>
      </li>
    </ul>
  </div>
</nav>
Stickers
  • 75,527
  • 23
  • 147
  • 186
Mario Parra
  • 1,504
  • 3
  • 21
  • 46
  • Add a width to each of your elements. – Andrew Ice Jan 19 '17 at 18:00
  • Possible duplicate of [How to arrange three flex div side by side](http://stackoverflow.com/questions/31476024/how-to-arrange-three-flex-div-side-by-side) – Heretic Monkey Jan 19 '17 at 18:03
  • @MikeMcCaughan This statement, _since the far-left element (#site-logo) is not always present._ makes it not a dupe of that question – Asons Jan 19 '17 at 18:05
  • So, as usual, when something is proposed as a duplicate, editing the question to make it more clear why it's not a duplicate is a good idea... I've done that for future readers. – Heretic Monkey Jan 19 '17 at 18:09
  • Now I got surprised .... how does the accepted answer make _`#site-links` should be centered in relation to its parent,_ ??? – Asons Jan 19 '17 at 18:19
  • I accidentally accepted it. I None of the answer place `#nav-links` perfectly centered, which is what I'm trying to achieve, regardless of its adjacent elements. I also can't use static widths because they will vary. – Mario Parra Jan 19 '17 at 18:21
  • So how will the left and right elements width change? .. even or different or ..? – Asons Jan 19 '17 at 18:25
  • `#subnav-cont` has padding of 1.5%, so `#site-logo` and `#nav-social` should be pressed up against these margins, while `#nav-links` should be centered within `#subnav-cont`, not within `#site-logo` and `#nav-social`. – Mario Parra Jan 19 '17 at 18:29

2 Answers2

3

You were looking for justify-self but that doesn't exist in flexbox. align-self works on cross-axis.

Try this:

#nav-links {
  margin: auto;
}

codepen

If you need #nav-links to be centered within #subnav-con, regardless if the other two elements are present and their widths. You can set it to position: absolute; along with other tweaks.

#nav-links {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
}

codepen

Stickers
  • 75,527
  • 23
  • 147
  • 186
  • This is very close to what I'm trying to achieve, but I can't tell if `#nav-links` is exactly centered. Also, this only works when `#site-logo` is present. Otherwise, `#nav-links` shifts to the left. – Mario Parra Jan 19 '17 at 18:32
  • @MarioParra it's only centered in the space it takes, unless the left and right items are the same width. Do you need it to be centered in the viewport width? – Stickers Jan 19 '17 at 18:37
  • I need #nav-links to be centered within `#subnav-con`, regardless if the other two elements are present and their widths. – Mario Parra Jan 19 '17 at 18:38
  • @MarioParra Updated above, let me know. – Stickers Jan 19 '17 at 18:49
  • I wanted to avoid using absolute positioning and thought I could benefit from flexbox's dynamic layouts, but this is the closest answer to what I'm looking for so far. – Mario Parra Jan 19 '17 at 19:01
  • @MarioParra I agree that flexbox is not like the super hero that can solve everything, you can achieve that layout just fine without it. – Stickers Jan 19 '17 at 19:05
  • @Pangloss Agree on that :) – Asons Jan 19 '17 at 19:06
  • Almost used this, but the layout breaks when `#site-logo` isn't present (`#nav-social` jumps to the far-left). This is why I tried controlling the position of each element independently. – Mario Parra Jan 19 '17 at 19:09
  • @MarioParra Just add `#nav-social {margin-left: auto;}` that should be fixed. – Stickers Jan 19 '17 at 19:17
  • Yes, it does. Thanks! Will accept this answer. Can you explain how this works? – Mario Parra Jan 19 '17 at 19:22
  • @MarioParra See this great article on [Medium](https://medium.com/@samserif/flexbox-s-best-kept-secret-bd3d892826b6#.48e8unak8). – Stickers Jan 19 '17 at 19:29
1

align-self in this case adjust the item vertically.

Is this what you are looking for?

Also, for this to work properly, both the #site-logo and #nav-social needs to be equal width, and if not, the #nav-links needs to be positioned in another way, i.e. position: absolute

#subnav {
  z-index: 99999999;
  width: 100%;
  overflow: auto;
  font-size: 1.1rem;
  background-color: yellow;
}
#subnav #subnav-cont {
  display: flex;
  margin: 0 auto;
  padding: 0 1.5%;
  max-width: 1280px;
  background-color: red;
}
#subnav #subnav-cont #site-logo {
  flex: 1;
  padding: 10px 0;
  height: 50px;
  /*visibility: hidden;*/
  text-align: left;
}
#subnav #subnav-cont #site-logo img {
  display: inline-block;
  margin: 0;
  padding: 0;
  height: 30px;
}
#subnav #subnav-cont > ul li {
  display: inline-block;
  padding: 0 20px;
  height: 50px;
  font-size: 1em;
  line-height: 50px;
  white-space: nowrap;
}
#subnav #subnav-cont #nav-links {
  flex: 2;
  text-align: center;
}
#subnav #subnav-cont #nav-social {
  flex: 1;
  text-align: right;
}
#subnav #subnav-cont #nav-social li {
  padding: 0 5px;
}
<nav id="subnav">
    <div id="subnav-cont">
      <div id="site-logo">
        <img src="https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png">
      </div>
      <ul id="nav-links">
        <li>
          <a href="#" class="subnav-link">Link</a>
        </li>
        <li>
          <a href="#" class="subnav-link">Link</a>
        </li>
        <li>
          <a href="#" class="subnav-link">Link</a>
        </li>
        <li>
          <a href="#" class="subnav-link">Link</a>
        </li>
      </ul>
      <ul id="nav-social">
        <li>
          <a href="#" class="icon-facebook">Facebook</a>
        </li>
        <li>
          <a href="#" class="icon-twitter">Twitter</a>
        </li>
        <li>
          <a href="#" class="icon-instagram">Instagram</a>
        </li>
      </ul>
    </div>
  </nav>
Asons
  • 84,923
  • 12
  • 110
  • 165
  • In both examples, the far-left (`#site-logo`) and far-right (`#nav-social`) elements are not flush against the edges, – Mario Parra Jan 19 '17 at 18:33
  • @MarioParra Outer edges ? – Asons Jan 19 '17 at 18:39
  • The edges of `#subnav-cont`. – Mario Parra Jan 19 '17 at 18:41
  • @MarioParra Updated my answer. Better? – Asons Jan 19 '17 at 18:42
  • @MarioParra Also, for this to work properly, both the #site-logo and #nav-social needs to be equal width, and if not, the #nav-links needs to be positioned in another way – Asons Jan 19 '17 at 18:47
  • Ideally, I want each element to occupy whatever width is necessary, which is why I'm using flexbox. – Mario Parra Jan 19 '17 at 19:00
  • @MarioParra Yes, get that, though since flex items adjust to its content and `flex-grow` expand based on what is left when content consumed its space, having 2 outer elements with different width you won't be able to center the middle 100% accurate. – Asons Jan 19 '17 at 19:03
  • I see. I may have to use the answer with absolute positioning. – Mario Parra Jan 19 '17 at 19:04
  • @MarioParra Made a 2:nd update ... where I played with the `flex: nn` values some, maybe this can be a compromise? – Asons Jan 19 '17 at 19:12