【Angular Material15】チェックボックスのCSSを上書きしよう!

ANGULAR

みなさんこんにちは、現役エンジニアのサメハックです

未経験からWebエンジニアに転職し、
正社員として5年働いたのちフリーランスとして独立しました。

Angularの解説シリーズです。

今回はAngular MaterialのチェックボックスのCSSを上書きする方法について学んでいきましょう!

駆け出しエンジニアや未経験の方、
また新入社員を指導する先輩社員にとっても
わかりやすいように解説していきます!

この記事を読むと・・・
  • Angular MaterialのCSSで上書きできる

※PCにnpm、nodeがインストールされている前提で記述します。
 yarn等をお使いの方は読み替えてください。

環境がない人はcodesansboxを使ってね!

実行環境

今回の記事はMaterial15が対象だよ!

Angular Material
UI component infrastructure and Material Design components for Angular web applications.

AngularMaterialのCSSを上書きしよう!

Angular MaterialのCSSを”部分的に”上書きするには
以下のように記述する必要があります。

:host ::ng-deep {
  /* 変更したいスタイル */
}

これは公式サイトにも記述がある通り現在は非推奨となっていますが、
現状これ以外に部分的に上書きする手段が無いため、その前提で紹介します。

チェックボックスを上書きする構文

:host ::ng-deep {
  .mat-mdc-checkbox.mat-accent {
    // チェックマークの色
    --mdc-checkbox-selected-checkmark-color: red;
    // ボックス内の色
    --mdc-checkbox-selected-focus-icon-color: yellow;
    --mdc-checkbox-selected-hover-icon-color: yellow;
    --mdc-checkbox-selected-icon-color: yellow;
    --mdc-checkbox-selected-pressed-icon-color: yellow;
    // クリックした際の枠の色
    --mdc-checkbox-unselected-focus-icon-color: red;
    // ホバーした際の枠の色
    --mdc-checkbox-unselected-hover-icon-color: red;
    // disabledの際のチェックボックスの色
    --mdc-checkbox-disabled-selected-icon-color: aqua;
    // disabledの際の枠の色
    --mdc-checkbox-disabled-unselected-icon-color: aqua;
    // 未選択時の枠の色
    --mdc-checkbox-unselected-icon-color: limegreen;
    --mdc-checkbox-unselected-pressed-icon-color: limegreen;
  }

  // テキストの色
  .mat-mdc-checkbox .mdc-form-field {
    color: red;
  }

  // disabledの際のテキストの色
  .mat-checkbox--disabled label {
    color: aqua;
  }

  // enableにしたときのフワっと出る影
  // ※別の箇所をクリックしないと影が消えないのは仕様
  .mat-mdc-checkbox.mat-accent .mdc-checkbox--selected ~ .mdc-checkbox__ripple {
    background: yellow;
  }

   .mat-mdc-checkbox
     .mdc-checkbox__native-control:focus:checked
     ~ .mdc-checkbox__ripple {
     background: yellow;
   }

  // disabledにしたときのフワっと出る影
  // ※別の箇所をクリックしないと影が消えないのは仕様
  .mat-mdc-checkbox .mdc-checkbox__ripple {
    background: orange;
  }
}

説明が難しいですが、AngularMaterialを使うと
通常はCSSがカプセル化されて上書きできないようになっているのですが
デベロッパーツールを使うと、上のようにクラス名が特定できるので
特定したクラス名を指定してスタイルを上書きしています。

色は変数を使うと動かないことが稀にあるので注意!

ng-deepで上書きする際の注意点※超重要

先程の構文をそのまま使用してしまうと、
画面に表示されているすべてのコンポーネントの
mat-checkboxのスタイルが上書きされてしまいます。

これを回避するためには、以下のように
クラス名やIDを指定してスタイルを適用することを強く推奨します。

:host ::ng-deep {
  クラス名/ID名 {
    .mat-mdc-checkbox.mat-accent {
      // 省略
    }
  }
}
<ng-container>で囲うのがオススメだよ!

実際に動かしてみよう!

【Angular15】Angular,CLI,Materialのバージョンアップをしよう!
バージョンが重要なので、15未満のバージョンを使っている場合はアップデートしてね!

初期設定

アプリケーションの作成

ng new 好きなディレクトリ名
cd 作成したディレクトリ

Materialのインポート

ng add @angular/material
テーマカラーとアニメーションは好きな項目を選択してね!

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatRadioModule } from '@angular/material/radio';
import { MatSelectModule } from '@angular/material/select';
import { MatSliderModule } from '@angular/material/slider';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatMenuModule } from '@angular/material/menu';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatCardModule } from '@angular/material/card';
import { MatDividerModule } from '@angular/material/divider';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatGridListModule } from '@angular/material/grid-list';
import { MatListModule } from '@angular/material/list';
import { MatStepperModule } from '@angular/material/stepper';
import { MatTabsModule } from '@angular/material/tabs';
import { MatTreeModule } from '@angular/material/tree';
import { MatButtonModule } from '@angular/material/button';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { MatBadgeModule } from '@angular/material/badge';
import { MatChipsModule } from '@angular/material/chips';
import { MatIconModule } from '@angular/material/icon';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatRippleModule } from '@angular/material/core';
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
import { MatDialogModule } from '@angular/material/dialog';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,

    // Material関連モジュールのインポート
    // ※今回使用していないものも入っています
    MatCheckboxModule,
    MatAutocompleteModule,
    MatDatepickerModule,
    MatFormFieldModule,
    MatInputModule,
    MatRadioModule,
    MatSelectModule,
    MatSliderModule,
    MatSlideToggleModule,
    MatMenuModule,
    MatSidenavModule,
    MatToolbarModule,
    MatCardModule,
    MatDividerModule,
    MatExpansionModule,
    MatGridListModule,
    MatListModule,
    MatStepperModule,
    MatTabsModule,
    MatTreeModule,
    MatButtonModule,
    MatButtonToggleModule,
    MatBadgeModule,
    MatChipsModule,
    MatIconModule,
    MatProgressSpinnerModule,
    MatProgressBarModule,
    MatRippleModule,
    MatBottomSheetModule,
    MatDialogModule,
    MatSnackBarModule,
    MatTooltipModule,
    MatPaginatorModule,
    MatSortModule,
    MatTableModule,
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}
本来は必要なものだけインポートしてね!

app.component.html

<mat-checkbox>デフォルト</mat-checkbox>
<mat-checkbox disabled>デフォルト</mat-checkbox>
<section class="checkbox-wrap">
  <mat-checkbox>オリジナル色</mat-checkbox>
  <mat-checkbox disabled>オリジナル色</mat-checkbox>
</section>

app.component.scss

:host ::ng-deep {
  .checkbox-wrap {
    .mat-mdc-checkbox.mat-accent {
      // チェックマークの色
      --mdc-checkbox-selected-checkmark-color: red;
      // ボックス内の色
      --mdc-checkbox-selected-focus-icon-color: yellow;
      --mdc-checkbox-selected-hover-icon-color: yellow;
      --mdc-checkbox-selected-icon-color: yellow;
      --mdc-checkbox-selected-pressed-icon-color: yellow;
      // クリックした際の枠の色
      --mdc-checkbox-unselected-focus-icon-color: red;
      // ホバーした際の枠の色
      --mdc-checkbox-unselected-hover-icon-color: red;
      // disabledの際の枠の色
      --mdc-checkbox-disabled-selected-icon-color: aqua;
      --mdc-checkbox-disabled-unselected-icon-color: aqua;
      // 未選択時の枠の色
      --mdc-checkbox-unselected-icon-color: limegreen;
      --mdc-checkbox-unselected-pressed-icon-color: limegreen;
    }

    // テキストの色
    .mat-mdc-checkbox .mdc-form-field {
      color: red;
    }

    // enableにしたときのフワっと出る影
    // ※別の箇所をクリックしないと影が消えないのは仕様
    .mat-mdc-checkbox.mat-accent
      .mdc-checkbox--selected
      ~ .mdc-checkbox__ripple {
      background: yellow;
    }
    .mat-mdc-checkbox
      .mdc-checkbox__native-control:focus:checked
      ~ .mdc-checkbox__ripple {
      background: yellow;
    }


    // disabledにしたときのフワっと出る影
    // ※別の箇所をクリックしないと影が消えないのは仕様
    .mat-mdc-checkbox .mdc-checkbox__ripple {
      background: orange;
    }
  }
}

動作確認

ng serve -o

これで同じものが出来上がるはずです。

MaterialのCSS上書きができてえらい!

GitHubのサンプルコード

今回作ったものはGitHubにあげているので
使いたい人は是非ダウンロードしてみてください。

GitHub - same-hack/Angular_Material15
Contribute to same-hack/Angular_Material15 development by creating an account on GitHub.

まとめ

  • Materialの上書きにはng-deepを使用する
  • 公式的には非推奨となった方法だが、代替手段は現状ない

満足いただけたら、1クリックなのでSNSフォローしてもらえると嬉しいです🦈

タイトルとURLをコピーしました