こんにちは、白々さじきです。
今回は、Google MapsのInfoWindow(吹き出し)の見た目をCSSでカスタマイズする方法についてまとめます。
「InfoWindowの背景色を変えたい」と思って style を渡してみたのですが、白い吹き出しがそのままで詰まりました。解決するまでの過程を書きます。
結論
InfoWindowの見た目はGoogleが独自のCSSクラスで管理しています。上書きするには、グローバルCSSファイルを作って !important で強制的に上書きします。
なぜ style props だけでは変わらないのか
@vis.gl/react-google-maps の <InfoWindow> に style を渡しても、変わるのは children(中のコンテンツ)だけです。
// これだと中身のテキスト部分しか変わらない
<InfoWindow anchor={selectedMarker}>
<div style={{ color: 'white' }}>スターバックス</div>
</InfoWindow>
外側の白い吹き出し(コンテナ)はGoogleのサーバーから読み込まれたCSSで管理されているため、children へのスタイル指定では届きません。
CSS Modulesが使えない理由
「じゃあCSSファイルを作ればいい」と思っても、CSS Modules(.module.css)は使えません。
CSS ModulesはビルドのタイミングでクラスX名を変換します。たとえば .gm-style-iw-c と書いても、ビルド後には .gm-style-iw-c__abc123 のような文字列になります。Googleが付けるクラス名とは一致しなくなるため、スタイルが当たりません。
普通のCSSファイルを使う必要があります。
Google Maps InfoWindowのクラス構造
開発者ツール(F12)で確認できる主なクラスは以下のとおりです。
| クラス名 | 対応する要素 |
|---|---|
.gm-style-iw-c | 吹き出しのメインコンテナ |
.gm-style-iw-d | 内側のスクロール領域 |
.gm-style-iw-tc::after | 三角の矢印部分(疑似要素) |
.gm-style-iw-chr | 閉じるボタンの領域 |
::after は疑似要素なのでHTMLタグとして存在しません。開発者ツールでは親要素を選択して展開すると確認できます。
CSSファイルで上書きする
普通のCSSファイルを作成してViteからimportします。
/* src/styles/map.css */
.gm-style-iw-c,
.gm-style-iw-d,
.gm-style-iw-chr,
.gm-style-iw-chr button {
background-color: #1a1f3a !important;
color: #fbbf24 !important;
border: none !important;
box-shadow: none !important;
}
.gm-style-iw-d {
overflow: hidden !important;
}
.gm-style-iw-tc::after {
background: #1a1f3a !important;
box-shadow: none !important;
}
.gm-style-iw-chr button img {
filter: invert(1) !important;
}
// App.tsx
import './styles/map.css';
ViteはCSSファイルのimportを検出して自動で読み込みます。document の操作は不要です。
なぜ !important が必要なのか
通常のCSSでは「詳細度(Specificity)」というスコアが高いほうのルールが優先されます。
GoogleのCSSは詳細度が高く書かれているため、普通にクラスを指定しても負けてしまいます。
/* これはGoogleのCSSに負ける */
.gm-style-iw-d {
overflow: hidden;
}
/* !important をつけると他のすべてのルールに勝てる */
.gm-style-iw-d {
overflow: hidden !important;
}
!important は「詳細度の計算を無視して最優先にする」特別な指定です。外部ライブラリのスタイルを上書きするときには有効ですが、自分のコード内では乱用すると管理が難しくなるので注意が必要です。
InfoWindow内のテキストをdivで囲む理由
テキストノード(文字列)には直接 style を渡せません。divで囲むことでスタイルを当てられます。
// NG: テキストノードにstyleは渡せない
<InfoWindow anchor={selectedMarker}>
{name}
</InfoWindow>
// OK: divで囲む
<InfoWindow anchor={selectedMarker}>
<div style={{ background: '#1a1f3a', color: '#fbbf24', padding: '4px 8px' }}>
{name}
</div>
</InfoWindow>
まとめ
- InfoWindowの外側のスタイルはGoogleのCSSクラスを上書きする必要がある
- CSS Modulesはクラス名が変換されるため使えない。普通のCSSファイルを使う
- Googleの動的CSSは詳細度が高いため
!importantで上書きする ::afterは疑似要素なのでHTMLタグとして見つからない
参考リンク
サポートのお願い
下記リンクからお買い物いただけると、ブログ運営のための費用が増え、有料サービスを利用した記事作成が可能になります。ご協力よろしくお願いします!

コメント