0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

dialog の背景色が変わらないときに読んで下さい (React サンプルコード付き)

Last updated at Posted at 2024-07-01

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>
);

サンプルコード

モーダルを使用する際、大抵は下記のような要件になると思います。

  • 上位のコンポーネントで何かクリックするとモーダルを開く
  • モーダル内には閉じるためのボタンが付いている

これを簡単に実装してみます。

App.tsx
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;
SampleModal.tsx
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;
style.css
.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() を呼び出しています。

サンプルコード実行結果

SampleModal.gif

解説

そもそも ::backdrop という疑似要素は showModal() とともに呼び出されます。
そのため open 属性に値を代入しても ::backdrop は呼び出されません。

その点を踏まえて先の確認事項であげたリストがなぜダメなのか軽く解説をつけます。

dialog の open に boolean 値を入れない
open 属性はあくまでモーダルが表示されているかどうかの状態を示すものなので open 属性に直接 boolean 値を入れても ::backdrop は機能しません。

dialog の開閉は showModal()close() で行う
showModal() メソッドを使うことで ::backdrop が初めて有効になります。close() メソッドも同様にモーダルを閉じる際に使用します。

クラスの付け替えで表示・非表示を行わない
CSS クラスの付け替えでモーダルの表示・非表示を管理すると ::backdrop が適切に動作しません。

関連情報

ブラウザーのサポート状況

dialog 要素は 2022 年 3 月以降のバージョンであれば、IE などを除くほとんどのブラウザーで動作します。
上記の変更を行なっても背景色が変わらない場合はブラウザーの更新を試してみて下さい。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?