baumgarb
baumgarb

Reputation: 2167

Full Content Height & Aligning Cards Using Flexbox

I am struggling with aligning items in Angular 4 w/ Angular Material using Flexbox. I want to accomplish a layout like the one shown in attachment #1 where the first card is at the top and the second card is at the bottom of the component's content. The component itself should take the rest of the space on the screen in height (device height minus toolbar height).

Attachment #2 shows what I've accomplished so far. The following HTML markup and CSS show the code behind attachment #2.

Can anyone tell me what's the correct way to do this? I don't want to mess around with fixed positions or whatever, I would like to implement a solution that is compatible with Angular Material and doesn't effect the layout of other components.

Thanks in advance!

Attachment #1:

My current solution looks like this, of course, due to the height of 100% given to div#home-content. See HTML markup and CSS code below which reflect the source code of this solution.

Attachment #2:

div#home-content with the black border should take the rest of the space in height. The cards have a red border here. The first card should be at the top/start and the second card should be at the bottom/end.

HTML markup of HomeComponent:

<div id="home-content"> 
  <mat-card id="title-card">
    <mat-card-title>Lorem.</mat-card-title>
    <mat-card-content>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Blanditiis magnam sint accusamus facere ducimus modi non voluptates consectetur exercitationem ullam.</mat-card-content>
  </mat-card>
  <mat-card>
    <mat-card-header>
      <img mat-card-avatar src="http://lorempixel.com/200/200" alt="">
      <mat-card-title>Lorem, ipsum dolor.</mat-card-title>
      <mat-card-subtitle>Lorem ipsum dolor sit amet consectetur adipisicing elit.</mat-card-subtitle>
    </mat-card-header>
    <mat-card-content>Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptate repellat animi reiciendis eius mollitia totam sint natus hic unde iusto.</mat-card-content>
    <mat-card-actions>
      <button mat-raised-button color="primary">Challenge!</button>
    </mat-card-actions>
  </mat-card>
</div>

Corresponding CSS code:

div#home-content {
    display: flex;
    flex-direction: column;
    height: 100%;
    border: 3px solid black;
    justify-content: space-between;
}

Upvotes: 0

Views: 11192

Answers (2)

baumgarb
baumgarb

Reputation: 2167

@LGSon: thank you for your answer. I did it like you said and made the parent container a flex container too. Now it works, but I am not sure if it will affect other layouts in other components where this layouting is not needed.

For others who may have the same problem here is the CSS code that worked for me. In the screenshot #1 you can see the result with colored borders for all relevant elements. Thanks again to @LGSon for the tip:

html, body {
    margin: 0;
    height: 100%; // html and head must be 100% height in order to make that work
}

app-root {
    height: 100%; // app-root needs to be 100% too
    display: flex; // make the app-root a flex container
    flex-direction: column; // flex-direction is column so that the toolbar is above the component's content
}

md-toolbar {
    flex-grow: 0; // if there is more space in height than needed toolbar won't grow
}

app-root > *:nth-child(3) { // the third child of app-root contains the component's content. The first child is the toolbar, the second one is the empty router-outlet element. Perhaps this is different in your HTML structure. 
    border: 3px solid black;;
    flex-grow: 1;
    display: flex; // is also a flex container with just one item which is div#home-content
}

div#home-content {
    align-self: stretch; // use the whole space available in height
    border: 3px solid greenyellow;
    display: flex; // is a flex-container too so that the cards can be aligned accordingly
    flex-direction: column;
    justify-content: space-between; // space-between is responsible for the first card to be at the top and the second card to be at the bottom
}

Screenshot #1:

Black border: component, greenyellow border: div#home-content, red border: cards

Upvotes: 0

Asons
Asons

Reputation: 87191

When using percent for height, also each parent, all the way to the html/body, need one too.

One option is to use viewport units, so change from height: 100% to height: 100vh and the #home-content will fill the viewport.

div#home-content {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    height: 100vh;                        /*  changed  */
    border: 3px solid black;
    box-sizing: border-box;               /*  added, to avoid scroll and make
                                              border size be included in set height  */
}

Another is to set its parent to display: flex; flex-direction: column, and then remove height: 100% and add flex-grow: 1, and the #home-content will fill its parent.

div#home-content {
    flex-grow: 1;                         /*  added  */
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    border: 3px solid black;
}

Upvotes: 1

Related Questions