31

I can't seem to wrap my head around having this container in an md card.

In my material cards, I have this:

<div class="mat-card-header-text"> </div>

I've seen other people notice it. It causes a 40px space on the left of my title. No CSS seems to affect it either.

I am using Angular 4.x and Material2.

flamusdiu
  • 1,722
  • 2
  • 14
  • 31

13 Answers13

54

This extra div is actually quite annoying. As it turns out though, you can use shadow-piercing to apply a style to it without changing the CSS emulation mode. You can do this using the ::ng-deep combinator as such:

::ng-deep .mat-card-header-text {
  /* CSS styles go here */
  margin: 0px; // for example to remove the margin
}

You can also just replace the whole header with your own CSS classes instead:

<mat-card>
  <div class="your-header">
    <div class="your-title">
      Your title here
    </div>
  </div>
  <mat-card-content>
    Stuff goes here
  </mat-card-content>
</mat-card>
Dre
  • 1,985
  • 16
  • 13
18

Per their recent recommendation https://angular.io/guide/component-styles, this worked for me:

 :host /deep/ .mat-card-header-text {
     margin: 0;
 }
Serge Makarov
  • 351
  • 2
  • 7
  • Tried many solutions, but did not effect. But this one worked for me. – Sovichea Cheth Mar 30 '20 at 23:58
  • 1
    Although ::ng-deep is adviced for broader compatibility, angular will drop support for these /deep/, >>>, and ::ng-deep. In my problem, /deep/ didn't work but ::ng-deep is working properly – whitefang Oct 10 '20 at 19:22
  • 2
    yes, for angular please use ``` :host ::ng-deep .mat-card-header-text { margin: 0; } ``` – Sanjay Verma Sep 05 '21 at 04:10
10

I fixed it by providing negative left margin to md-card-title

<md-card-title style="margin-left:-8px;">
Aidan Ryan
  • 11,389
  • 13
  • 54
  • 86
Lakhwinder
  • 101
  • 1
  • 4
8

This behavior is the result of Angular 2/4's view encapsulation, which in Emulated mode will only inject (via style elements) component styles that match elements actually in your view template.

So if you try to override a .mat-* style like so:

.mat-card-header-text {
  height: auto;
  margin: 0;
}

but your HTML looks like this:

<md-card-header>
  <md-icon md-card-avatar>face</md-icon>
  <md-card-title>{{user.name}}</md-card-title>
  <md-card-subtitle>{{user.status | userStatus}}</md-card-subtitle>
</md-card-header>

then the .mat-card-header-text rule won't be injected into the DOM, since the injector doesn't see such an element in your template.

The simplest workaround is to directly include the div.mat-card-header-text element in your template:

<md-card-header>
  <md-icon md-card-avatar>face</md-icon>
  <div class="mat-card-header-text">
    <md-card-title>{{user.name}}</md-card-title>
    <md-card-subtitle>{{user.status | userStatus}}</md-card-subtitle>
  </div>
</md-card-header>

Edit: as you pointed out, this generates an extra empty div.mat-card-header-text, so it's not an ideal solution. The only way to fix that is if you create your own card component based on md-card (possibly using component inheritence), but at that point you'd just modify the component's CSS directly.

Otherwise, you can switch the view encapsulation mode for your component to None:

import { ViewEncapsulation } from '@angular/core';

@Component({
  moduleId: module.id,
  selector: 'user-card',
  templateUrl: 'user-card.component.html',
  styleUrls: ['user-card.component.css'],
  encapsulation: ViewEncapsulation.None
})
...

Though if you do that, the :host selector will no longer work, so you'll need to replace it with the selector you specified in the @Component decorator:

user-card {
   ...
}
Lèse majesté
  • 7,923
  • 2
  • 33
  • 44
  • 2
    I tried to directly use the div directly as you show. However, I ended up with my div and the one inserted. Still, which why should it be done? The way you show or the way I did it finally? – flamusdiu Apr 18 '17 at 21:44
  • 1
    @flamusdiu I personally try to avoid using additional elements to counteract prior CSS rules. So I use the `ViewEncapsulation.None` solution currently, but that doesn't really sit well with me, either. I'll probably end up using component inheritance when I get the time. – Lèse majesté Apr 18 '17 at 22:03
  • Yeah, I may just stay what I have then. It's crazy how it add an extra element like that. =\ – flamusdiu Apr 18 '17 at 22:12
2

Give a negative left-margin to the mat-card-title solve the issue.

.mat-card-title {
   margin-left: -16px;
 }
Morlo Mbakop
  • 3,518
  • 20
  • 21
1
mat-card-header{
  justify-content: center;
}
Srikrushna
  • 4,366
  • 2
  • 39
  • 46
1

If you need to change Angular Material styles, do that in the main styles.css/scss file, like this:

/* Angular Material styles override start */    
.messages-list-wrapper {
  .message-card {
    .mat-card-header-text {
      width: 100%;
    }
  }
}

/* Angular Material styles override end */

Also, always make sure that you are not directly targeting the Material classes, because this will affect them project-wise, include one of your classes before it, so that the change is applied only for the component you want.

Bullsized
  • 362
  • 4
  • 7
0

Fixed it using the following css and html:

md-card-title > span {
    background-color: #fff;
    background-color: rgba(255, 255, 255, 0.5);
    position: absolute;
    margin-top: -81px;
    margin-left: -24px;
    font-size: 20px;
    padding: 10px;
}

<div class="main" mat-padding fxLayout="row" fxLayoutWrap="no-wrap" fxLayoutAlign="center start" fxLayoutGap="15px">
    <md-card class="mat-elevation-z2" mat-whiteframe="8" (click)="goToArticle(article)" *ngFor="let article of articleStore.articles() | async">
        <img md-card-image src="{{ article.getCover() }}">
        <md-card-title fxFlex>
            <span>{{ article.title }}</span>
        </md-card-title>
        <md-card-content>
            <p>{{ article.description }}</p>
        </md-card-content>  
    </md-card>
</div>

Using <md-card-header></md-card-header>gives some odd spacing issues. Not sure if this is a bug or not.

flamusdiu
  • 1,722
  • 2
  • 14
  • 31
0

If you want to support both a version with image in the header and without, this is one possible solution. The idea is to toggle a class which fixes the margin when there is no image available (set through the link input in the example). This way to card looks fine with and without an image.

Html:

<mat-card>
  <mat-card-header [ngClass]="{'fix-margin': !link}">
    <mat-card-title>{{content}}</mat-card-title>
    <mat-card-subtitle>{{content}}</mat-card-subtitle>
    <img *ngIf="link" mat-card-avatar [src]="link">
  </mat-card-header>
  <mat-card-content>
    {{content}}
  </mat-card-content>
  <mat-card-actions>
    <button mat-button>SHOW</button>
  </mat-card-actions>
</mat-card>

Css

.fix-margin {
  margin: 0 -8px;
}

Ts

export class component {
  @Input() content;
  @Input() link;    
}
Tomnar
  • 357
  • 2
  • 11
0

I Know is an old question, but still today is an issue. The way I solved was overriding it like this in the ts file:

ngAfterViewInit() {
    document.getElementsByClassName('mat-card-header-text')[0].setAttribute('style', 'margin: 0 0');
  }
  • Using a lifecycle hook, vanilla JS targeting and array magic numbers all in the same row just to change a CSS property is _really_ not a good idea. – Bullsized Jun 15 '22 at 09:06
0

<mat-card-header> is ment to be used when you have an img (like an avatar) to the left of it, just use <mat-card-title> without the <mat-card-header> wrapper around it

0
::ng-deep .mat-card-header .mat-card-header-text{
   margin: 0px;
}
mohan mu
  • 73
  • 1
  • 4
  • Remember that Stack Overflow isn't just intended to solve the immediate problem, but also to help future readers find solutions to similar problems, which requires understanding the underlying code. This is especially important for members of our community who are beginners, and not familiar with the syntax. Given that, **can you [edit] your answer to include an explanation of what you're doing** and why you believe it is the best approach? – Jeremy Caney Aug 02 '23 at 00:14
  • That's even more true here since it's very similar to the top-voted answer. – Jeremy Caney Aug 02 '23 at 00:15
-3

make a class for the mat-card container and add

border-collapse:collapse;

worked wonders for me.

Maurice
  • 6,698
  • 9
  • 47
  • 104