Flexbox内でのテキスト省略の謎を解く

はじめに

こんにちは!株式会社ユーザベース SaaS事業 Product Team の沖です。

この記事では、私がプロダクト開発中に遭遇した問題とその解決方法について共有します。具体的には、Flexbox 内の要素にカードのタイトルが「…」で省略される仕様を追加した際の課題に焦点を当てます。解決までの道のりを、レイアウト例を用いて説明していきます。この記事が、同様の問題に直面している方の参考になれば幸いです。

仕様を追加する前の画面の説明

仕様を追加する前の画面は、以下のようなレイアウトになっています。

  • ページ全体はヘッダー、サイドバー、コンテンツ領域で構成されています
  • サイドバーとコンテンツ領域は Flexbox によって横並びに配置されており、サイドバーの幅は固定、コンテンツ領域は残りのスペースを埋めるような幅になっています
  • コンテンツ領域には、Flexbox によって 2 つのセクションが横に並んでおり、それぞれのセクションには複数のカードが縦に並んでいます
  • 各カードにはタイトルが含まれており、カードの内容が一目でわかるようになっています

具体的なコード例を以下に示します(React と Tailwind CSS を使用しています)。

export function Page() {
  return (
    <>
      <header className="fixed flex w-full h-20 bg-white items-center justify-between border-b p-4 font-bold text-3xl">
        ヘッダー
      </header>
      <div className="flex pt-20 min-h-screen">
        <div className="border-r w-44 p-4 shrink-0 font-bold text-lg">
          サイドメニュー
        </div>
        <Content />
      </div>
    </>
  );
}
function Content() {
  return (
    <main className="p-4 w-full flex-1">
      <div className="flex [&>*]:w-1/2 gap-4 w-full">
        <div>
          <h2 className="text-2xl font-bold mb-2">セクション1</h2>
          <div className="flex flex-col gap-4">
            <Card title="Strike while the iron is hot" />
            <Card title="Don't judge a book by its cover" />
            <Card title="The grass is always greener on the other side of the fence" />
          </div>
        </div>
        <div>
          <h2 className="text-2xl font-bold mb-2">セクション2</h2>
          <div className="flex flex-col gap-4">
            <Card title="窮鼠猫を噛む" />
            <Card title="犬も歩けば棒に当たる" />
            <Card title="虎穴に入らずんば虎子を得ず" />
          </div>
        </div>
      </div>
    </main>
  );
}
interface CardProps {
  title: string;
}

export function Card({ title }: CardProps) {
  return (
    <div className="border p-4 rounded-lg flex flex-col gap-1">
      <h3 className="font-bold text-xl">{title}</h3>
    </div>
  );
}

追加する仕様

次に、今回追加する仕様について説明します。この仕様では、カード内のタイトルを 1 行で表示し、タイトルが長い場合には省略記号として「…」を末尾に表示します。

この変更は、CSS で次のようなスタイルを適用することで実現できます。

.card-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

Tailwind CSS を使用する場合、truncateクラスを追加することで同様のスタイルを適用できます。

export function Card({ title }: CardProps) {
  return (
    <div className="border p-4 rounded-lg flex flex-col gap-1">
      <h3 className="font-bold text-xl truncate">{title}</h3>
    </div>
  );
}

しかし、この変更により新たな問題が発生しました...。

省略記号のスタイルを適用した際に発生した問題

カード内のタイトルの末尾に「…」を表示するスタイルを適用すると、コンテンツ領域の右側が見切れる問題が発生しました。これまでは、flex: 1によってコンテンツ領域がブラウザの幅に合わせて表示されていたのが、うまく機能しなくなったのです。

この問題について調べたところ、この記事で、Flexbox の中でテキストを省略するとこのような問題が発生することがあると説明されていました。

この問題の対策として、Flexbox の子要素にmin-width: 0を設定する方法が紹介されていました。これを受けて、コンテンツのルート要素にmin-width: 0を設定してみました(Tailwind CSS では、min-w-0を使用します)。

function Content() {
  return (
    <main className="p-4 w-full flex-1 min-w-0">
      {/* 中身は省略 */}
    </main>
  );
}

この変更によって、以下のようなレイアウトになりました。

一見すると問題は解決したよう見えましたが、ブラウザの幅によっては、セクション 2 の右端にあるはずの余白がなくなってしまうことに気づきました。

セクションを横に並べている部分も Flexbox で実装していたことを思い出し、ここにもmin-width: 0を設定しました。

function Content() {
  return (
    <main className="...">
      <div className="...">
        <div className="min-w-0">
          {/* 中身は省略 */}
        </div>
        <div className="min-w-0">
          {/* 中身は省略 */}
        </div>
      </div>
    </main>
  );
}

これにより、以下のようなレイアウトになりました。

これで、ブラウザの幅に合わせてコンテンツが表示される仕様を保ちつつ、タイトルが長い場合には末尾に「…」を表示する仕様を追加できました!

おわりに

今回の記事では、Flexbox 内の要素にカードのタイトルが「…」で省略される仕様を追加した際に発生した問題とその解決方法について共有しました。具体的には、Flexbox の子要素にmin-width: 0を適用することで、コンテンツがブラウザの幅に収まるように修正しました。

この記事が同様の問題に直面している方々の参考になれば幸いです。

参考記事

https://css-tricks.com/flexbox-truncated-text/

Page top