河原 志乃 / shino.kawahara

自己紹介

千葉県出身のしーちゃんこと河原志乃です。 Voicyではフロントエンドエンジニアをしています。 趣味は、音声を聞くこととダンスです。

Voicyの好きなところ

同じゴールに向かって頑張る組織と仲間が大好きです!

好きなVoicyパーソナリティ

カジュアルに話してみる

ピックアップコンテンツ

Angularでセレクト部品のオプションをカスタムする - voicy tech blog
こんにちは!株式会社VoicyでWebフロントエンジニアをしているしーちゃんです。 今回は、Angular Materialを使ったセレクト部品のオプションのカスタム方法について書きます。 今回、デザインをもとに新たにセレクト部品を作る必要がありました。 デザインを見て、セレクト部品について調べたところ、 HTMLのデフォルトのオプション部品をカスタムするのは難しいと書いてあったので、諦めかけました。 しかし、いろいろ試行錯誤した結果、指定のデザインを実現できたので記録しておきます! セレクト部分(リストを表示するトリガー)とオプション部分(リスト表示)が重ならない セレクト部分の右端に、オプション部分が開いているかどうかを示す矢印を表示する オプション部分を選択すると文字が強調される、かつ、右端に指定の画像を表示する まず結論から言うと、今回Angular Materialから使用した部品はMenuだけです。 セレクト部品を1から自分で作成するのは大変なので、今回はカスタムするとしても、何かしらのもとになる部品をAngular Materialから持ってくるという方針で進めました。 候補に挙げた部品には以下があります。 Selectは、単体で見ると名前の通り動作が一番理想系に近かったのですが、セレクト部分とオプション部分がつながっているまたは重なっているデザインでした。Menuにある、 overlapTrigger のプロパティがあれば、セレクト部分とオプション部分を重ねるかどうかを指定できるのですが、Selectにはこのプロパティはなく実現できそうにありませんでした。 1.セレクト部分とオプション部分が重ならない こちらは、1を満たしていました。 しかし、2, 3が実現できません。 2.セレクト部分の右端に、オプション部分が開いているかどうかを示す矢印を表示する 3.オプション部分を選択すると文字が強調される、かつ、右端に指定の画像を表示する 3.オプション部分を選択すると文字が強調される、かつ、右端に指定の画像を表示する その結果、Menuのオプション部分は自分で作成することにしました。 次に、どのようにカスタマイズしたか書きます。 そこで::ng-deep を使います。Angularには::ng-deepを使用しないとカスタムできないスタイルが指定されていることがあります。 しかし、単純に::ng-deepだけを使用すると、他の コンポーネントで使っているスタイルに影響が出る可能性があります。 そこで今回は、::ng-deepを指定するクラスを絞るために、 MatMenuの機能である MatMenuContentの backdropClassを使用しました。 backdropClassに適当なクラスを指定して、::ng-deepと指定したクラス名で絞り込みすると、クラスを付与した コンポーネント だけでそのスタイルが適応されます。 ちなみに、通常よく行うようにMatMenuに class="select-mat-menu"を指定した場合、 CSSにおいて.select-mat-menu で絞り込みを行ってもスタイルが適応されません。 これは、以下の図を見てもらうとわかると思います。 MatMenuのオプション部分は、 cdk-overlay-containerという上部の層に表示されます。MatMenuを表示するmat-menuタグにクラスをつけても階層が異なり、絞り込みが行えません。そこで、 backdropClassにクラスを指定することで cdk-overlay-container直下の cdk-overlay-backdrop にクラスを追加します。 こうすることで、以下のように今まで直接いじれなかった mat-menu-panelや mat-menu-contentを指定した.select-mat-menu の任意のクラスで絞って上書きすることができます。 ::ng-deep { .select-mat-menu { + * .cdk-overlay-pane > div.mat-menu-panel { border-radius: 8px !important; box-shadow: none !important; border: 1px solid #dbdada !important; margin-top: 8px !important; min-height: max-content !important; max-width: 100% !important; ...

テキストアウトプット