CSS 書いても背景色が変わらない!
モダールを作成するのに超便利な dialog 要素ですが、ハマりがちな罠があります。
dialog::backdrop {
background-color: rgba(0, 0, 0, 0.5);
}
それが上記のような CSS を書いていても dialog の背景色が変わらない!というものです。
これを CSS やブラウザーのせいにして諦めかけていませんか?
確認事項
- dialog の open に boolean 値を入れない
- dialog の 開閉は
showModal()
とclose()
で行う - クラスの付け替えで表示・非表示を行わない
これらを守れば ::backdrop
で背景色がつくはずです。
ダメな例: 一番やりがちなやつ
// モーダルの開閉状態を管理するフラグ
const [hasModalOpened, setHasModalOpened] = useState(false);
return(
{/* 背景色を変えたいときに open に boolean 値を入れるな!!! */}
<dialog open={hasModalOpened}>
{/* ...ここにモーダルの内容が入る... */}
</dialog>
);
サンプルコード
モーダルを使用する際、大抵は下記のような要件になると思います。
- 上位のコンポーネントで何かクリックするとモーダルを開く
- モーダル内には閉じるためのボタンが付いている
これを簡単に実装してみます。
import React, { useState } from "react";
import SampleModal from "./components/SampleModal";
import "./styles.css";
const App = () => {
// Modal の開閉状態は下記の useState で持つ
const [hasModalOpened, setHasModalOpened] = useState(false);
return (
<div className="App">
{/* このボタンを押すと dialog が開く */}
<button type="button" onClick={() => setHasModalOpened(true)}>
Modal Open
</button>
<SampleModal
{/* ここで Modal の開閉状態を渡す */}
hasModalOpened={hasModalOpened}
{/* SampleModal 内で onClose が呼び出されると hasModalOpened に false がセットされる */}
onClose={() => setHasModalOpened(false)}
/>
</div>
);
};
export default App;
import React, { useEffect, useRef } from "react";
interface Props {
hasModalOpened: boolean;
onClose: () => void;
}
// モーダル本体
const SampleModal = ({ hasModalOpened, onClose }: Props) => {
// dialog 要素が関連付けされると参照される
const modalRef = useRef<HTMLDialogElement>(null);
// hasModalOpened に反応して showModal() か close() が実行される
useEffect(() => {
if (hasModalOpened) {
// showModal() を使うとモーダルが表示されて ::backdrop が有効になる
modalRef.current?.showModal();
} else {
// close() でモーダルが閉じられる
modalRef.current?.close();
}
// hasModalOpened を監視している
}, [hasModalOpened]);
return (
{/* dialog 要素と modalRef を関連付けている */}
<dialog ref={modalRef}>
{/* このボタンを押すと onClose が呼ばれモーダルが閉じる */}
<button type="button" className="close-button" onClick={onClose}>
x
</button>
<p>サンプルモーダル</p>
</dialog>
);
};
export default SampleModal;
.App {
font-family: sans-serif;
text-align: center;
}
dialog::backdrop {
background-color: rgba(0, 0, 0, 0.5);
}
SampleModal.tsx
では useRef
フックを使用して dialog
要素を参照しています。
そして useEffect
フックを使用して hasModalOpened
の変化を監視し、変化に応じて取得した dialog
要素の showModal()
または close()
を呼び出しています。
サンプルコード実行結果
解説
そもそも ::backdrop
という疑似要素は showModal()
とともに呼び出されます。
そのため open
属性に値を代入しても ::backdrop
は呼び出されません。
その点を踏まえて先の確認事項であげたリストがなぜダメなのか軽く解説をつけます。
- dialog の open に boolean 値を入れない
-
open
属性はあくまでモーダルが表示されているかどうかの状態を示すものなのでopen
属性に直接 boolean 値を入れても::backdrop
は機能しません。 - dialog の開閉は
showModal()
とclose()
で行う -
showModal()
メソッドを使うことで::backdrop
が初めて有効になります。close()
メソッドも同様にモーダルを閉じる際に使用します。 - クラスの付け替えで表示・非表示を行わない
- CSS クラスの付け替えでモーダルの表示・非表示を管理すると
::backdrop
が適切に動作しません。
関連情報
ブラウザーのサポート状況
dialog
要素は 2022 年 3 月以降のバージョンであれば、IE などを除くほとんどのブラウザーで動作します。
上記の変更を行なっても背景色が変わらない場合はブラウザーの更新を試してみて下さい。