Align mat-cards content (image, text and buttons)
Asked Answered
T

3

8

I'm working with mat-card in a list and I have a problem with the alignment.

Here is what I have:

enter image description here

Here is what I want:

enter image description here

The code :

<div class="margin-top-20" fxFlexFill fxLayout="row wrap" fxLayout.xs="column" fxLayout.sm="column" fxLayoutGap="15px grid">
  <div fxFlex="20" fxFlex.md="33" *ngFor="let advert of adverts; let i = index" class="padding-fix">
    <div fxFlexFill fxLayoutAlign="center stretch">
      <mat-card class="ad">
        <div fxLayoutAlign="space-between center">
          <img mat-card-image src="test" alt="test">
        </div>
        <mat-card-title>test</mat-card-title>
        <mat-card-content>
          <p>
            test
          </p>
        </mat-card-content>
        <mat-card-actions align="end">
        </mat-card-actions>
      </mat-card>
    </div>
  </div>
</div>

I didn't understand I can I centre the image (resize it if necessary).

EDIT: Thank coreuter's answer, I'm close to getting what I want.

enter image description here

the first block is not at the same height as the others. And I've got some blank space at the end of each row (I would like 5 elements per row).

The updated code:

<div class="margin-top-20" fxLayout="row wrap" fxLayoutAlign="start center" fxLayoutGap="15px">
  <mat-card fxFlex="20" (click)="addProduct()" class="mat-card-add-button">
    <div>
      <span style="font-size:32px;text-align:center">+<br/>Add product</span>
    </div>
  </mat-card>
  <mat-card fxFlex="20" *ngFor="let product of products; let i = index" class="product">
    <img class="image" mat-card-image src="{{product.picture.uri}}" alt="photo">
    <mat-card-title>{{product.name}}</mat-card-title>
    <mat-card-content>
      <p>
        test
      </p>
    </mat-card-content>
    <mat-card-actions align="end">
    </mat-card-actions>
  </mat-card>
</div>

EDIT 2:

I think it's almost perfect. I tried with a big content inside the mat-card-content div and I don't know if it's good. Here is a screenshot of what I have:

enter image description here

Do you think it possible to get the buttons at the same height as the big mat-card (the last one)? Another thing, I can't see the border-left of the first element of each row.

Here the updated code :

<div class="margin-top-20" fxFlexFill fxLayout="row wrap" fxLayoutAlign="start start" fxLayoutGap="20px">
    <mat-card fxLayoutAlign="center center" fxFlex="0 1 calc(20% - 20px)" (click)="addProduct()" class="product" style="height:413px">
        <div>
            <span fxLayoutAlign="center center" style="font-size:32px;text-align:center">+<br />Add product</span>
        </div>
    </mat-card>
    <mat-card fxFlexFill fxFlex="0 1 calc(20% - 20px)" *ngFor="let product of products; let i = index" class="product">
        <img class="image" mat-card-image src="{{product.picture.uri}}" alt="photo">
        <mat-card-title>{{product.name}}</mat-card-title>
        <mat-card-content>
            <p *ngIf="i == 3">
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam dapibus, leo id pulvinar vestibulum, ligula nisl tincidunt magna, eu volutpat leo neque quis justo. Fusce semper ante id mi porta porta. Pellentesque nec pretium purus. Curabitur lobortis tempus consectetur. Nam ullamcorper gravida erat sed suscipit. Morbi quis porttitor nunc. Suspendisse lacinia a turpis vitae laoreet. Aliquam pellentesque scelerisque urna. Cras vulputate nisi sed elit commodo cursus. Aenean interdum, erat at convallis dictum, urna enim tincidunt nisi, vitae tempor nisi nisi a tellus. Aliquam volutpat dui eget gravida eleifend. Nullam pulvinar justo eget tellus commodo, eget molestie dui convallis. Curabitur at fermentum lorem. Maecenas porttitor sem ut enim efficitur bibendum et vel metus.
            </p>
            <p *ngIf="i != 3">
                   test
            </p>
        </mat-card-content>
        <mat-card-actions align="end">
            <button mat-icon-button>
                <mat-icon>mode_edit</mat-icon>
            </button>
            <button mat-icon-button>
                <mat-icon>delete</mat-icon>
            </button>
        </mat-card-actions>
    </mat-card>
</div>

Thank you again for your help, I really appreciate it!

EDIT 3: This version works! Thank you very much coreuter! See it on StackBlitz.

The mat-card-content is not fixed by the "fxFlex" property. The content goes outside the mat-card. (It's working on the last StackBlitz but not for me).

enter image description here

.mat-card {
    padding: 18px !important; /* less padding than per default */
}

.mat-card-image {
    width: calc(100% + 36px) !important; /* update padding */
    margin: 0 -24px 16px -18px !important; /* update padding */
}

.mat-tab-label {
    font-size: 16px !important;
}

.mat-card-title {
    font-size:24px !important;
    font-weight: 500 !important;
}

.mat-card-content {
    font-size: 14px !important;
    min-height: 30px; /* <--- to remove !!! */
}

.product {
    margin-bottom: 25px;
    /*min-width: 180px;
    text-align: center;*/
} 

/* desktop button */
.mat-card-add-button {
    border: 1px dashed grey;
    box-shadow:none !important;
    cursor:pointer;
}

.product img {
    height: 250px;
    object-fit: contain;
}
<div *ngIf="products.length > 0" style="margin-left:10px;">
    <div fxLayout="row wrap" fxLayoutAlign="start stretch" fxLayoutGap="20px">
        <mat-card fxLayoutAlign="center center" fxFlex="0 1 calc(20% - 20px)" fxFlex.md="0 1 calc(25% - 20px)" fxFlex.sm="0 1 calc(33% - 20px)" fxHide.xs="true" (click)="addProduct()" class="product mat-card-add-button">
            <div fxLayoutAlign="center center" style="font-size:32px;text-align:center">+<br />Add product</div>
        </mat-card>
        <mat-card fxLayout="column" fxFlex.md="0 1 calc(25% - 20px)" fxFlex="0 1 calc(20% - 20px)" fxFlex.sm="0 1 calc(33% - 20px)" fxFlex.xs="100" *ngFor="let product of products; let i = index" class="product">
            <img mat-card-image src="{{product.picture.uri}}" alt="photo">
            <mat-card-title>{{product.name}}</mat-card-title>
            <mat-card-content fxFlex>
                    <p *ngIf="i == 3">
                        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam dapibus, leo id pulvinar vestibulum, ligula nisl tincidunt
                        magna, eu volutpat leo neque quis justo. Fusce semper ante id mi porta porta. Pellentesque nec pretium purus. Curabitur
                        lobortis tempus consectetur. Nam ullamcorper gravida erat sed suscipit. Morbi quis porttitor nunc. Suspendisse lacinia
                        a turpis vitae laoreet. Aliquam pellentesque scelerisque urna. Cras vulputate nisi sed elit commodo cursus. Aenean interdum,
                        erat at convallis dictum, urna enim tincidunt nisi, vitae tempor nisi nisi a tellus. Aliquam volutpat dui eget gravida
                        eleifend. Nullam pulvinar justo eget tellus commodo, eget molestie dui convallis. Curabitur at fermentum lorem. Maecenas
                        porttitor sem ut enim efficitur bibendum et vel metus.
                    </p>
                    <p *ngIf="i != 3">
                        test
                    </p>
            </mat-card-content>
            <mat-card-actions fxFlexAlign="end" align="end">
                <button mat-icon-button>
                    <mat-icon>mode_edit</mat-icon>
                </button>
                <button mat-icon-button>
                    <mat-icon>delete</mat-icon>
                </button>
            </mat-card-actions>
        </mat-card>
    </div>
</div>
Tetramethyldiarsine answered 6/9, 2018 at 14:38 Comment(5)
Can you tell me a little more about the goal?Is the problem the shuttle is too tall? or that the burger is too wide?Neckar
The goal is to display cards with content and actions at the same height. The main problem is about images size. If an image is too high, the content and the buttons aren't at the same height compare to previous image. I hope I am clearTetramethyldiarsine
Could you please add your current css as well?Welsh
I've added the css :) My bad... I found the problem (min-height...). I though it was about the fxFlex I didn't read my css until now.Tetramethyldiarsine
yeah, I just found that nasty min-height just now, too :D . I'm glad your problem is solved. :) To keep SO tidy you should mark your other question as solved, too.Welsh
W
12

Since I answered your previous SO question, I'll build my answer to this question upon my previous answer. Please refer to this updated Stackblitz with images of different width and height.

Preview

EDIT: Adjusted the answer/stackblitz to make a row containing 5 elements.

Explanation

In order to keep the image always the same height I've added the class "image" to the <img>-tag (you can of course apply the css to the img-tag directly with .product img{...} as well).

<img class="image" mat-card-image src="{{product.picture.url}}" alt="photo">

and applied the following CSS:

.image{
  height: 150px; /* adjust as needed */
  object-fit: contain;
}

With object-fit: contain your image will always properly scaled and fully visible within the available area.

Keep in mind that object-fit is currently only fully supported by the following browsers.

EDIT:

In order to get 5 Elements within each row you have to adjust the fxLayoutGap and the calculation of the width for each element using the fxFlex attribute. Please change your code as follows..

<div class="container" fxLayout="row wrap" fxLayoutAlign="center center" fxLayoutGap="20px">

    <!-- Add addProduct-button outside loop -->
    <mat-card fxFlex="0 1 calc(20% - 20px)" (click)="addProduct()" class="product">
     ...
    </mat-card>

        <!-- loop over the products -->
    <mat-card fxFlex="0 1 calc(20% - 20px)" *ngFor="let product of products; let i = index" class="product">
      ...
    </mat-card>

</div>

.. and change the 20px set on the fxLayoutGap and the within the calculation of fxFlex to your desired value.

With those values now set you have to apply a min-width value, otherwise all elements will just get smaller in width and the row won't wrap:

.product{
  min-width: 180px; /* adjust as desired */
  min-height: 250px;
  margin-bottom: 20px; /* same as fxLayoutGap for even distribution */
}

EDIT 2

To make the first element the same height as the others you have to adjust to (min-)height of the .product CSS-class to be equal to the height of the highest product.

EDIT 3 (to answer edit 2 of the question)

Since you didn't mark your question answered yet, I've modified the code you provided in your edit #2 to accomplish your desired design: stackblitz

I've changed the following:

  • changed the fxLayoutAlign on the container to "space-evenly stretch" instead of fxLayoutAlign="start start" this distributes all items in a row on the x-axis evenly and makes them stretch as high as the highest element of the row.
  • removed all fxFlexFill
  • added fxFlex to the mat-card-content
  • removed the height from the .product CSS-class

Regarding the border on the left side.. I assume your container is too close to the browser windows left side. I've change the container css in my stackblitz as well.

Welsh answered 6/9, 2018 at 15:44 Comment(8)
Thank to you I'm close to get what I want. I have some problem about the first element (the "add product button") and the blank space after the 4th element of each row. Maybe you have a solution ?Tetramethyldiarsine
@JoeAllen I've adjusted my answer to respond to your question. If this (and my answer on your other question) helped you in finding a solution for your problem it would be nice if you accept both of them. Let me know if you need further assistance.Welsh
Of course, you already helped a lot ! I will edit my answer, i'm testing different cases at the momentTetramethyldiarsine
Do you think it's possible to get all items align on the left ? I noticed the tow last elements are centered (on your last stackblitz) (sample : ibb.co/bEbXS9)Tetramethyldiarsine
@JoeAllen You can change fxLayoutAlign of the container to fxLayoutAlign="start" which aligns everything left-top or fxLayoutAlign="start center" which aligns the items left on the x-axis but center on the y-axisWelsh
Of course, fxLayoutAlign="start stretch" works (I knew it and I didn't try...). By the way, the mat-card-content is not good (ibb.co/ipMVfU). I've just added the "fxFlex" property to mat-card-contentTetramethyldiarsine
@JoeAllen yeah, that's what I did in my last stackblitz, too. I failed to create those stackblitz'es with my account that's why I had to create a new one instead of updating the old one. sorry for that. The link is in the edit of my answer though.Welsh
I've updated my first post. I have a last bug with the mat-card-content. It goes out of the mat-card. Any idea ?Tetramethyldiarsine
L
0
.ad{
 display:flex;
 flex-direction:coloumn;
 height:100%;
}
img,mat-card-content{
flex-grow: 1;
}
mat-card-actions{
display: inline-block;
align-self: flex-end;
}

You can try this.

Libbi answered 6/9, 2018 at 15:24 Comment(1)
Thank you for your answer. Unfortunately, it doesn't work. The images aren't not at the same height, the buttons are not at the bottom of my cardTetramethyldiarsine
M
0

You may have to work with fixed sizes for the mat-card and just make sure the images fit in whatever space is available.

.margin-top-20>div>div {
  display: flex;
  width: 100%;
}

.ad {
  width: 200px;
  height: 250px;
  min-height: 250px;
  max-width: 200px;
  border: thin solid #eee;
}

.ad>div {
  width: 100%;
  height: 200px;
  display: flex;
  justify-content: center;
  align-items: center;
}

.ad>div>img {
  flex: 0 1;
  width: 100%;
  height: auto;
}
<div class="margin-top-20" fxFlexFill fxLayout="row wrap" fxLayout.xs="column" fxLayout.sm="column" fxLayoutGap="15px grid">
  <div fxFlex="20" fxFlex.md="33" *ngFor="let advert of adverts; let i = index" class="padding-fix">
    <div fxFlexFill fxLayoutAlign="center stretch">
      <mat-card class="ad">
        <div fxLayoutAlign="space-between center">
          <img mat-card-image src="https://via.placeholder.com/150x50" alt="test">
        </div>
        <mat-card-title>test</mat-card-title>
        <mat-card-content>
          <p>
            test
          </p>
        </mat-card-content>
        <mat-card-actions align="end">
        </mat-card-actions>
      </mat-card>
      <mat-card class="ad">
        <div fxLayoutAlign="space-between center">
          <img mat-card-image src="https://via.placeholder.com/50x150" alt="test">
        </div>
        <mat-card-title>test</mat-card-title>
        <mat-card-content>
          <p>
            test
          </p>
        </mat-card-content>
        <mat-card-actions align="end">
        </mat-card-actions>
      </mat-card>
      <mat-card class="ad">
        <div fxLayoutAlign="space-between center">
          <img mat-card-image src="https://via.placeholder.com/350x150" alt="test">
        </div>
        <mat-card-title>test</mat-card-title>
        <mat-card-content>
          <p>
            test
          </p>
        </mat-card-content>
        <mat-card-actions align="end">
        </mat-card-actions>
      </mat-card>
    </div>
  </div>
</div>
Milk answered 6/9, 2018 at 16:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.