【React】z-indexで困る問題


今日のテーマ


私はz-indexが嫌い


なぜ?

->デモ解説


step 0

  • スクロールするとModalボタンがheaderに被ってしまう

ヘッダーの z-inedx 1、ドロワーの z-index 2、モーダルは z-index 10。
ヘッダーはしばらくスクロールするとfixedになってmainの上に表示される。
モーダルをヘッダーの上に表示したいので z-index 10 になっているが、
コンテナにz-indexがついているのでボタンまで上に表示されてしまう。

step 1

  • ヘッダーをボタンより上に表示したくて、z-index 20 にする

「Next 0」ボタンを1回押して次に進める。
Modalボタンはヘッダーの下にくるようになったが、
Modalボタンを押すとモーダルがヘッダーに下に出てしまう。
ヘッダーが20、モーダルが10なので、そりゃそうだ。

step 2

  • .modal をヘッダーより上に表示したくて、z-index 30 にする

「Next 1」ボタンを1回押して次に進める。
すると、ヘッダーが20、モーダルが30にもかかわらず、
モーダルがヘッダーの下に表示されてしまう。
モーダルのコンテナ(.modalComponent)が10だからだ。

step 3

  • .modalComponentのz-indexをinitialにする

「Next 2」ボタンを1回押して次に進める。
すると、ヘッダーが20、モーダルが30の順番通りになって、無事モーダルが表示されて!
一見うまくいったようにみえる。
しかしドロワーを開いてみると、今度はドロワーがヘッダーの下に表示されてしまっている。
ヘッダーが20、ドロワーが2なので当然である。

step 4

  • ドロワーを40にしよう!

「Next 3」ボタンを1回押して次に進める。
すると、ドロワーが z-index 40 になり、無事ヘッダーの上に表示された!

これで解決?

今回はわざとアホらしいz-indexのサンプルを作ったが、
業務中でもこういったz-index問題は意外と起る。
しかも、他人の書いたコードに影響を受けまくるし、
z-indexをいじると他人の書いたコードに影響も与えやすい。
しかもバグっていることに気づきにくいし、z-indexは調査もしずらい。
注意深く作ることで回避はできるが、健全な回避方法とは言い難い。

z-indexは、最後の手段にしよう・・・
できればちゃんとDOMtreeの順番通りに表示されるのが直感的だし、
バグも少なく扱いやすい。


めでたしめでたし


そんなわけねーだろ!


今日のお話


【React】z-indexで困る問題


自己紹介

  • 渡辺 貴明
  • nabepon_dev follow me!
  • アジアクエスト株式会社
  • フロントエンドエンジニア

直近でやったプロジェクト

某飲食サービスの姉妹サービス
お察し...
react, redux, css modules, react-router etc...


旧時代

モーダル、fixedヘッダー、ドロワーメニューなど、
手前に表示する要素の実装。

jQuery時代だと、DOM treeの最後の方に表示することで、
z-indexに頼らずとも実装することができた。


手前に表示したいやつはbodyにappend

var $modal = $('<div class="modal">modal</div>')
$(body).append($modal);

表示順もDOMをゴリゴリ弄ればいいだけなので、
jsでなんとかすることができた。


現代

Reactだとこういったことができない。
できるが、React上でDOMを探してappendするようなコードは書きたくない。
ではReactではどう実装するかというと、2パターンが考えられる。


1つはz-indexで頑張る方法。

もう1つはDOMの後ろにあらかじめ配置しておく方法。


DOMの後ろにあらかじめ配置

<div id="root">
  <HeaderComponent />

  <main>
    <div>
      ...
      <FooComponent>
        <button onClick={openFoo}>open</button>
      </FooComponent>
      ...
      <BarComponent>
        <button onClick={openBar}>open</button>
      </BarComponent>
      ...
      ...
    </div>
  </main>

  <FooterComponent />

  <ForwardLayer>
    {isFooOpen ?
      <div class="fooModal"> foo </div>
    : null }

    {isBarOpen ?
      <div class="barModal"> bar </div>
    : null }
  </ForwardLayer>
</div>

Reactだと事前にコンポーネントを配置し、
条件分岐でコンポーネントの表示非表示を行う。
面倒くさい。


Reactでも別の場所に表示したい!


ソリューション



ライブラリを書いた

react-transfer

※ Google翻訳しただけのREADME。翻訳PR待ってます...


使い方

Usageをみる。
Transporter内にある、TransportItemの要素を、Destinationに表示する。
Example
Demo


<div>- component code start</div> から
<div>- component code end</div>
間にコードが書かれているが、実際に表示されるのは
<div>- display component</div> の下。

また、表示前のソート処理を行うなどできるので、
jsで表示順を制御できる。

テストコード があるので、そっち見た方がわかりやすいかも。


【React】z-indexで困る問題


解決!(?)


アジアクエストではメンバーを無限に募集してます!

お仕事も募集してます!
受託開発も業務委託も、
どちらもご相談くださいませ。

nabepon_dev