Search code examples
htmlcssflexboxvertical-alignment

I don't manage to get an element sticking to the bottom using flexbox


I want to align two elements in such a way, that one sticks to the top, and one to the bottom of the viewport. I'm trying to achieve this with flexbox, but don't want to use absolute positioning.

Whatever I tried, didnt work: I found this question on stock overflow, and tried to implement those answers - yet I still can't achieve the wanted result. Can anybody point me in the right direction, or explain what I did wrong?

Below is my html / css, here you can find the code snippets on jsbin, with different stuff i tried.

All of the other stackoverflow questions I found regarding this topic didn't work for me either - I really don't get why. Any help would be really appreciated.

<html>
  <body>
    <div class="top">
      <p class="text">Top</p>
    </div>
    <div class="bottom">
      <p class="text">Bottom</p>
    </div>
  </body>
</html>
body {
  min-height: 100%;
  display: flex;
  flex-direction: column;
}

.top {
  flex-grow: 1;
}

.bottom {
  margin-top: auto;
}

Solution

  • The CSS in the snippet contains a full explanation of what I did and why, so here just a summary:

    • min-height: 100% needs to be min-height: 100vh as with 100% body will only take up the summarized height of the direct child elements it contains.
    • Flexbox justify-content: space-between to move outermost child elements to either side of the flexbox container. With flex-direction: column that would be top and bottom of the container.
    • The above makes .top and .bottom CSS as-is obsolete.

    Snippet

    /* Demo, to better see space distribution */
    * { outline: 1px dashed }
    
    p {
        /* BEWARE: by default a <p> has 'margin: 1em 0'
                   adding extra space above and below */
    }
    
    body {
        min-height: 100vh; /* from 100% */
        /* as 100% will make body only use up total height
           of elements it contains. 100vh will force it to
           fill the entire viewport height.
        */
    
        margin: 0; /* to remove HTML default 8px spacing */
        /* Margin adds to the total height of body
           causing the vertical scrollbar to appear
           when using 100vh */
    
        display: flex; flex-direction: column;
    
        /* moves two outer elements to either side */
        /* more elements get distributed inbetween */
        justify-content: space-between;
        /* I put in extra <div> between top and bottom
           to show what happens.
        */
    }
    
    .top {/* [OBSOLETE] */
        /* makes this element fill the entire screen */
    /*    flex-grow: 1; /* probably unwanted, disabled */
    }
    
    .bottom {/* [OBSOLETE] */
    /*    margin-top: auto; /* not required for effect */
        /* handled by flexbox parent justify property */
    }
    
    /*
        As body grows with content it can (and probably will)
        exceed 100vh, making .bottom move downward out of the 
        viewport. And when you scroll down, .top will move out
        of view.
    
        If you need either top/bottom permanently fixed you
        will have to use the position: fixed property
        on the elements instead of the Flexbox solution.
    
        - .top    { position: fixed; top: 0 }
        - .bottom { position: fixed; bottom: 0 }
    */
    <div class="top">
        <p class="text">Top</p>
    </div>
    
    <div>
        <p>extra div &gt; p 1</p>
    </div>
    
    <div>
        <p>extra div &gt; p 2</p>
    </div>
    
    <div class="bottom">
        <p class="text">Bottom</p>
    </div>