ThrowawayJs
ThrowawayJs

Reputation: 210

CSS Flex align 3 divs, 1 and 2 top, 3 at the bottom

I am trying to make a side bar, where I have a drop down option at the top, then my nav, then some controls at the bottom of the nav:

Desired Outcome

-My Dropdown
-My main nav
-nav item
-nav item

-space
-space

-My controls
-control
-control

Current Outcome

-My Dropdown
-My main nav
-nav item
-nav item
-My controls
-control
-control

SCSS

.nav-container {
  height: 100vh;
  background-color: #111720;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-items: flex-start;
  justify-content: flex-start;
  .nav {
    width: 100%;
    h2 {
      color: #fff;
      margin: 20px 10px;
      font-size: 18px;
      font-weight: 400;
    }


    &.bottom {
      align-self: flex-end;
    }

    .nav-list {
      list-style: none;
      padding: 0;
      width: 100%;
      .menu-divider{
        margin-left: 20px;
        border: 0;
        border-top: 1px solid rgba(236, 237, 239, 0.1);
      }
      .nav-list-item {
        width: 90%;
        padding-left: 10%;
        color: $text-color-light;
        font-size: 15px;
        height: 50px;
        line-height: 50px;
        &.active {
          border-left: 5px solid $text-color-blue;
          color: $text-color-blue;
          padding-left: calc(10% - 5px);

          a {
            color: $text-color-blue;
          }
        }

        &:hover {
          border-left: 5px solid $text-color-blue;
          padding-left: calc(10% - 5px);
          transition: all 0.2s ease-in-out;
        }

        img {
          margin-right: 20px;
          width: 18px;
        }
        a {
          color: #fff;

          &:hover {
            color: $text-color-blue;
            transition: all 0.2s ease-in-out;
            cursor: pointer;
          }
        }
        .inline {
          display: inline-block;
          vertical-align: middle;
        }
      }
    }
  }

  .dropdown-container {

    ul {
      list-style: none;
      margin-bottom: 0;
    }
    li {
      &.selected 
      {
        color: white !important; 
      }

      &:hover {
        border-left: 5px solid #111720 !important;
      }
    }
  }

}

HTML Example

<section class="nav-container">
  <div class="dropdown-container">
    <ul>
      <li class="selected">
        DROPDOWN WILL BE HERE
      </li>
    </ul>
</div>


  <div class="nav top">


    <ul class="nav-list">
      <li class="nav-list-item">
          <a><span class="inline">Nav Item 1</span></a>
      </li>

      <li class="nav-list-item">
          <a><span class="inline">Nav Item 1</span></a>
      </li>

    </ul>
  </div>
  <div  class="nav bottom">
    <ul class="nav-list">
      <li class="nav-list-item">
          <a><span class="inline">Nav Item 1</span></a>
      </li>
      <li class="nav-list-item">
          <a><span class="inline">Nav Item 1</span></a>
      </li>
    </ul>
  </div>
</section>

Any suggestions on how I can approach this? I have tried flex: 1 1 auto on the main nav.

I have also tried self justify bottom etc.

If I justify the items with space between, it's closer to being correct, but I dont want the space between item 1 and 2.

Upvotes: 1

Views: 2706

Answers (1)

Artur Noetzel
Artur Noetzel

Reputation: 453

First of all your example scss code is not complete, so I added some random values for your color variables. I also shortened the html code, so the real issue is more obvious.

What you are trying to do is to align the third element in your flex-box (nav.bottom) to the bottom, while the other two containers (.dropdown-container and nav.top) stay on top. As a result the space in between will stretch so the flex-box will always have the same height as the screen. Am I right?

If so, then this code here &.bottom {align-self: flex-end;} is not going to work since the direction of your flex box is column and not row. In this case align is responsible for the horizontal alignment while justify is responsible for aligning the items vertically. (With flex-direction: row this would be the other way round.)

However, you cannot just replace align-self with justify-self since this property is being ignored in flex-box containers. Instead you can set your bottom navigation to stretch while the other two elements keep their natural height. For the navigation to be at the bottom, you can then make the bottom container a flex-box as well and align the list within to the bottom using justify-content.

This will look like this:

HTML

<div class="main">
  <section class="nav-container">
    <div class="dropdown-container">
      ...DROPDOWN WILL BE HERE...
    </div>


    <!-- using the nav element here instead of div for better semantics -->
    <nav class="top">
        <ul>
            ...top nav...
        </ul>
      top nav
    </nav>

    <nav  class="bottom">
        <ul>
            ...bottom nav...
        </ul>
      
    </nav>
  </section>
</div>

SCSS

$text-color-blue: skyblue;
$text-color-light: #ddd;

.nav-container {
  height: 100vh;
  background-color: #111720;
  display: flex;
  flex-flow: column nowrap;
  align-items: flex-start;
  justify-content: flex-start;
  
  .dropdown-container { 
    flex: 0 0 auto;
  }

  nav {
    width: 100%;

    &.top { 
      flex: 0 0 auto;
    }

    &.bottom {      
      flex: 1 1 auto;
      display: flex;
      flex-flow: column nowrap;
      justify-content: flex-end;
    }
  }
}

Of course there are more solutions for this, depending what your exact requirements are. You could for example also group the dropdown and the top nav in a div element. You would then have two elements in your flex-box instead of three and so it would be easy to use space-between to reach your goal.

Upvotes: 2

Related Questions