空要素に:emptyでスタイルを指定したのになぜか効かない・・・。:emptyの意外な落とし穴

空要素に:emptyでスタイルを指定したのになぜか効かない・・・。 :emptyの意外な落とし穴 CSS

テキストも画像も入っていない空のHTML要素ってありますよね。

特にPHPのような動的に生成したHTMLでは、場合によって中身が空の要素が出てくることが多いと思います。

しかし、ムダな余白を作ったり親要素でFlexGridなどを指定していると意図しないレイアウト崩れを引き起こすこともしばしば。

そんな子要素を持たない空要素を非表示にしたり特定のスタイルを指定したいときに便利なのが:emptyという疑似クラスです。

:emptyとは?どんなときに使う?

前述した通り、親要素でFlexやGridなどを指定してレイアウトを組んでいる場合、子要素の一つが空だとムダな余白ができてしまいます。

例えばこんなスタイルを指定しているとします。

<div class="flex">
  <div class="child">子要素1</div>
  <div class="child">子要素2</div>
  <div class="child"></div> <!-- 子要素3は空 -->
  <div class="child">子要素4</div>
  <div class="child">子要素5</div>
</div>
.flex {
  display: flex;
  gap: 40px;
}

.flex div {
  padding: 16px;
  background-color: rgb(100,150,200);
  color: #ffffff;
}

flexを付与した親要素に横並びになった5つの子要素が含まれていますが、その内1つがテキストもなにもない空要素です。

この場合、空要素はどうなるでしょうか?

無視されて子要素が4つ横並びになるでしょうか?

残念ながら5つの子要素が横並びになり、空要素は背景色と余白を持って表示されてしまいます。

各子要素にpaddingを指定しているため、空要素にも余白を含んでしまう

ここで:emptyの出番です。

上記のコードに以下のスタイルを追加することで空要素は非表示になりムダな余白が生まれません。

.flex div:empty { // 空のdiv要素を指定
  display: none;
}

:emptyの落とし穴

ここからが今回の本題です。

見た目で空要素だから:empty使えばいいや!というのはちょっと待ってください。

以下の例を見てください。

<div class="flex">
  <div>子要素1</div>
  <div>子要素2</div>
  <div> </div> <!-- 子要素3は空? -->
  <div>
</div> <!-- 子要素4も空? -->
  <div>子要素5</div>
</div>

子要素に:emptyを指定するとどうなるでしょうか?

この場合子要素はすべて表示されてしまいます

実は:emptyは中身が完全に空の状態でしかスタイルを反映させることができません。

上記のコードの場合、子要素3は「空白」という要素を持っているため空要素とみなされません。

子要素4の改行も同様です。空白はなくとも「改行」という要素を持つことになり、空要素判定されず:emptyが効かなくなるのです。

CMSやASPなどで起こる問題

直接HTMLを編集して空白を削除すれば簡単なのですが、WordPressなどのCMSやfutureshopなどといったSaasやASPでは、動的にHTMLを生成されるため、場合によっては制御できずどうしても空白や改行が含まれてしまうことがあります。

そうなるとそのままでは:emptyが使えないので別の方法をとる必要がありますが、残念ながら今のところ:emptyに代わるものはなく、JavaScriptでクラスを付与するか直接DOMを操作するしかありません。

:emptyの代替として、空白を含む空要素に適応できる:-moz-only-whitespaceという疑似クラスが存在しますがFirefoxでしか適用されません。
W3CのSelectors Level 4では:empty:-moz-only-whitespaceと同等の動作をするように変更されたということですが、まだ対応するブラウザはありません。今後に期待です。

JavaScriptで空要素にクラスを付与、または要素を直接操作する

空白や改行がある空要素へのJavaScriptによる対処方法は、クラスを対象の要素に付与するか、直接要素を操作する方法になります。

クラスを付与する方法

クラスを付与して空要素を非表示にしたい場合、display:none;を設定したクラスをJavaScriptによって付与します。

上記のサンプルコードの場合は以下のような記述になります。

// 要素を非表示にするemptyというクラス
.flex div.empty {
  display: none;
}
const els = document.querySelectorAll(".flex > div");

els.forEach((el) => {
  if (el.innerHTML === null || !el.innerHTML.match(/\S/g)) {
    el.classList.add("empty");
  }
})

flexクラスが付与されているdivの子要素を一つずつ条件分岐にかけています。

上記の場合、子要素の中身が完全に空(=null)、もしくは空白以外の文字列を含まないときにemptyクラスを付与して非表示にしています。

直接要素を操作する場合

クラスを付与する方法と流れは同じですが、空白や改行のみ含む子要素だけを操作しています。

const els = document.querySelectorAll(".flex > div");

els.forEach((el) => {
  if (el.innerHTML === null || !el.innerHTML.match(/\S/g)) {
    el.remove(); // 条件に当てはまる子要素だけを削除
  }
})

最後に

いかがでしょうか?

:emptyは完全な空要素には有効ですが空白や改行が一つでも含まれると効かなくなってしまうのがネックです。

直接HTMLを操作できるなら:emptyを、そうでなければJavaScriptを使って非表示用クラスを付与したり直接操作したりするなど、管理しやすいやり方で使い分けていきましょう。

タイトルとURLをコピーしました