FULLALLGOL 技術ノート

style.display = '' は「元に戻す」ではない

2026-08-31

表示と非表示を el.style.display = 'none'el.style.display = '' のペアで書くのは定石だ。
ほとんどの場合は正しく動く。動かないのは、その要素の display が inline 属性にしか書かれていないときだ。

= '' は「元に戻す」ではなく、inline style から display 宣言を削除する操作だ。
削除された結果、その要素の display は CSS のカスケードで決まる。
どこにも規則が無ければ、div の既定値である block に落ちる。

<div id="bar" style="display:flex">…</div>

この要素を一度でも = 'none'= '' すると、flex は永久に失われる
以後この行は横並びにならない。

「JS が触る値をクラスに入れない」方針と噛み合うと最悪になる

ある社内 Web ツールのユーティリティ CSS は、
「JS が inline へ書くプロパティは 1 つも入れない」という方針で書かれていた。
.u-wrapflex-wrap だけ、.u-gap-8gap だけを持ち、display は持たない

この方針そのものは正しい。クラス側に display を入れると、
JS が書く inline style と競合して !important の応酬になる。

ところがこの方針は、= '' に対するフォールバック先を消すという副作用を持っていた。
削除された flex を拾ってくれる規則がどこにも無いので、確実に block へ落ちる。

実際、ビューを切り替えた瞬間にツールバーが display: block に化け、
横並びだったはずの 2 つの入力欄(受領元と対象月)が縦に積み上がっていた。

なぜスクリーンショットで気づけないか

狭い幅では、縦積みが自然に見える。

レスポンシブなツールバーは、そもそも幅が足りなければ折り返す設計になっている。
だから縦に並んだ画面を見ても「そういうレイアウトだ」としか思わない。
色が消えたりテキストが欠けたりする欠陥と違って、目視レビューが機能しない類の壊れ方だ。

見えない以上、読むしかない。

const before = getComputedStyle(bar).display;  // 'flex'
bar.style.display = '';                        // 旧コードと同じ書き込み
const after = getComputedStyle(bar).display;   // 'block'  ← これが証拠

計算済みスタイルを実測すれば 2 行で決着がつく。
スクリーンショットの比較では、いつまでも決着しない。

直し方は「親を触らない」

3 通りある。上ほど安全だ。

  1. display を inline に持つ要素の display を、JS から触らない。

出し入れするのはその中の子要素にする(親コンテナは常設・子だけトグル

  1. どうしても親をトグルするなら、= '' ではなく = 'flex' を明示的に書き戻す
  2. display をクラス側に持たせ、JS は classList.toggle('is-hidden') だけを触る

(ただしこれは前述の方針転換になるので、既存の inline 書き込みを全部数えてからにする)

採用したのは 1 番だ。親のツールバーは常に flex のまま置きっぱなしにして、
ビューによって出し入れしたい入力欄だけを子として切り替える。
JS が display を書く要素と、display を inline に持つ要素を、重ねないという規律に落ちる。

同じ穴は display 以外にもある

= '' が「inline の宣言を削除する」である以上、inline にしか値が無いプロパティは全部同型だ。

プロパティ= '' で落ちる先
display: flexblock(要素の既定値)
visibility: hiddenvisible
position: absolutestatic(絶対配置が解けて文書の流れに戻る)

position は特に厄介で、レイアウトが崩れるのは離れた場所になる。

まとめ