Flex item の overflow: hidden が効かない問題の対処方法

目次

はじめに

Flex アイテムで overflow: hidden を設定しているのに Flex アイテムが縮小されずに文字列がはみ出してしまう問題の原因と対処方法を解説します。

背景

皆さんは Flex を使っていますか? 私はよく使っています。
便利な Flex ですが、仕様が複雑なため、理解していないと予期しないデザイン崩れが起こってしまうことがあります。
そのうちの一つが、長い文字列で Flex アイテムが縮小されない問題です。
例えば下記をご覧ください。
.grid {
  display: flex;
  width: 200px; /* 横幅を200pxに固定 */
}

.item {
  padding: 20px;
  border: 1px solid #000;
}

.text {
  overflow: hidden; /* はみ出さない */
  white-space: nowrap; /* 改行しない */
  text-overflow: ellipsis; /* はみ出す部分は三点リーダーにする */
}

.item:nth-child(1) {
  flex-grow: 1;
  flex-shrink: 1;
}

.item:nth-child(2) {
  flex-shrink: 0;
}
<div class="grid">
  <div class="item">
    <p class="text">
      Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch
    </p>
  </div>
  <div class="item">
    <p class="text">
      Item
    </p>
  </div>
</div>
世界一長い(執筆時現在)村名である 「Llanfairpwllgwyngyll-gogerychwyrndrobwll-llantysilio-gogogoch」 は本来3点リーダーで省略され、Grid 全体は 200 px に収まってほしいのですが、伸びてしまっています。

原因

これはバグのように見えるかもしれませんが、実は Flex の仕様で正しい動作をしているらしいです。
W3C (W3C Candidate Recommendation, 19 November 2018) の仕様を見てみましょう。 (§7.1.1. Basic Values of flex)
CSS Flexible Box Layout Module Level 1
https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#flex-common
By default, flex items won’t shrink below their minimum content size (the length of the longest word or fixed-size element). To change this, set the min-width or min-height property. (See §4.5 Automatic Minimum Size of Flex Items.)
意訳すると下記のとおりです。
デフォルトでは、Flex Item は最小コンテンツサイズ (最も長い単語または固定サイズの要素の長さ) 未満には縮小しない。 これを変更するには、 min-width または min-height プロパティを設定する。 (§4.5 Automatic Minimum Size of Flex Items を参照)
また、 §4.5 Automatic Minimum Size of Flex Items に 5000 文字ぐらいで最小サイズの算出方法についての仕様が書いてあるので、お時間あれば読んでみてください。私は理解するのに 30 分かかりました。
CSS Flexible Box Layout Module Level 1
https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#min-size-auto
私の解釈では、縮められない理由は下記のフローで発生しているのではないかと考えています。(ツッコミお待ちしております)
  • Flex item に min-width が設定されていないので、 min-width: auto が設定される
  • auto の幅を算出するために、コンテンツの幅を算出する
  • コンテンツの width を算出したら Xpx だった
  • min-width: Xpx と見なす
  • よって width が期待しているよりも広くなる

対処方法

仕様にも書いてありますし、私の解釈でもおわかり頂ける通り min-with: auto が原因であることがわかりました。
先程の例に min-width: 0 を設定してみます。
 .item {
   padding: 20px;
   border: 1px solid #000;
+  min-width: 0;
 }
無事に世界一長い村名が省略されました。

まとめ

シェア

Twitter
Facebook
はてブ
LinkedIn
LINE
Pocket