覆盖mat-form-field的第一个div的样式

5

如何覆盖由<mat-form-field>生成的第一个div的CSS样式?

背景

我在一个<mat-card>中有一堆字段,最后一个字段在卡片底部产生了太多的填充。

<mat-form-field id="this-feels-hacky-and-wrong"...>
    <!-- I want to remove the padding-bottom from this element -->
    <div class="mat-input-wrapper mat-form-field-wrapper">
      ...
    </div>
</mat-form-field>

padding to remove

在我的 style.css 文件中,我添加了如下内容:

#this-feels-hacky-and-wrong div{
  padding-bottom: 0;
}

这样做是可行的,但一定有更好/更正确的方法,不是吗?

我希望在我的component.scss文件中找到一个解决方案。


1
您能否创建一个小的可运行示例,并详细解释一下您想要做什么? - Hubert Grzeskowiak
5个回答

13

尝试使用这个::ng-deep

HTML

<mat-form-field class="this-feels-better"...>

组件.scss

:host ::ng-deep .this-feels-better div.mat-input-wrapper.mat-form-field-wrapper{
  padding-bottom: 0;
}

替代方案

如果您真的不想使用 ng-deep,因为它将在未来被删除,并且您真的想要将您的 CSS 规则放在您的 component.scss 文件中,那么您可以将组件的视图封装更改为 None

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

@Component({
   //...
   encapsulation: ViewEncapsulation.None
})

但是,在这种情况下,您需要确保在该组件中为所有CSS规则添加一些唯一于该组件的选择器前缀,以防止规则泄漏到其他组件。

.uniqueClassOnComponent .this-feels-better div.mat-input-wrapper.mat-form-field-wrapper{
   padding-bottom: 0;
}

//Other generic rules
.uniqueClassOnComponent span { ... }

2
他们不会放弃它,直到找到替代品为止。否则,将组件的viewEncapsulation设置为none,你的代码应该可以在component.scss中工作。但是,你应该在组件中为所有规则添加前缀,以便样式不会泄漏到其他组件中。 - David
好的,他们不会!根据我的研究,这是vNext解决方案:添加对Shadow DOM V1的支持 - spottedmahn
刚刚注意到这个(或者它刚刚被添加了)"...在那之前,应该优先使用::ng-deep以获得更广泛的工具兼容性。" - spottedmahn
有一种替代方案。如果您有一个全局的CSS文件,您可以在那里放置您的类,您的组件可以使用这些CSS规则而不改变ViewEncapsulation。 - andreisrob
在 github/. 中搜索 ::ng-deep。目前有41k个使用情况。如果没有斗争,它就不会消失。在每个库控件可以自己解决所有这些愚蠢的填充和边距问题之前,认为影子DOM可以解决这个问题是妄想! - Simon_Weaver

9

对我来说,使用::ng-deep/deep/不是一个解决方案,因为它即将被弃用

ViewEncapsulation.None也不是一个好的解决方案,因为它会在使用时破坏其他组件的样式。

您可以将自定义样式(例如no-padding)添加到全局样式表中。

//example:
mat-form-field.no-padding .mat-form-field-wrapper {
    padding: 0;
}

然后根据需要将其应用于您的Material UI表单字段中。

//example:
<mat-form-field class="no-padding">
    <mat-label>First Name</mat-label>
    <input matInput placeholder="First Name">
</mat-form-field>

0

使用CSS可以使用n-th term。只要你想要定位的div与其他div具有相同的父div,你就可以像这样引用第一个和最后一个子div:
.my-div-class:first-child {}

.my-div-class:last-child {}

因此,nth-term可用于定位任何子元素,如下所示:
.my-div.class:nth-child(2) {}
这将定位到第二个子元素。

为了进一步澄清您的问题,这是您的CSS应该是什么样子的:

mat-form-field:last-child div {
   padding-bottom: 0;
}

因为这并没有真正回答问题,所以被踩了。 - Hubert Grzeskowiak
是的,他们想知道如何定位第一个生成的 div 并移除其填充,而我的答案展示了如何实现。 - lewisnewson
1
Shadow DOM(影子DOM)是Web组件技术的一部分,它允许开发人员将HTML、CSS和JavaScript封装在一个独立的、可重用的自定义元素中。使用Shadow DOM可以避免样式和脚本冲突,并提高代码的可维护性和可重用性。在使用Shadow DOM时,可以使用::shadow伪类选择器来选择Shadow DOM内部的元素,也可以使用::content伪类选择器来选择Shadow DOM外部传递进来的内容。此外,还可以使用:first-child选择器来选择Shadow DOM内部的第一个子元素。 - spottedmahn

0

更新:请参考pistol-pete的答案。本质上是一样的。

对于后来者,还有另一种方法可以实现这个功能。不要使用ng-deep及其各种形式,因为它已经被弃用了。破坏封装不被推荐,并且违反了Angular的设计原则。解决方案是全局CSS,但需要使用特定的选择器。

mat-form-field是Angular Material的一部分。它有自己的封装。全局样式而不是组件样式可以覆盖它。然而,您可能不想覆盖所有这些元素,只想覆盖其中的一两个。我通过使用一个唯一的类来隔离我想要更改的元素,然后添加.mat-form-field-wrapper来定位具有填充的元素。以下是一个示例:

<mat-form-field class="pb-0">
  <mat-label>Not so hacky</mat-label>
  <imput matInput formControlName="notHacky" />
</mat-form-field>

然后使用pb-0类或您想要的任何名称,在全局CSS空间中进行目标定位。在Angular中,这是styles.css。使用Sass时,您可能会导入其他全局文件到样式文件中。添加以下内容:

/* sass */
mat-form-field {
  &.pb-0 {
    .mat-form-field-wrapper {
      padding-bottom: 0;
    }
  }
}

/* plain css */
mat-form-field.pb-0 .mat-form-field-wrapper
 {
  padding-bottom: 0;
} 

您可以针对任何框架中的任何组件重复此操作,因为全局样式将应用于所有地方。我建议创建一个独特的文件来保存所有这些覆盖。


0

试试这个。

HTML

<div style="width: 100%" class="time-period-area">
  <mat-form-field class="no-padding" appearance="outline">
    <mat-label>Time Period</mat-label>
    <input matInput style="height: 0; width: 100%" value=" " />
    <div class="mat-input-wrapper mat-form-field-wrapper">
      ...
    </div>
  </mat-form-field>
</div>

css

.time-period-area {
  mat-form-field.no-padding {
    width: 100%;
    padding: 0;
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接