Lainbo

Lainbo's Blog

If you’re nothing without the suit, then you shouldn't have it.
github
email
follow

純CSSアバターコンポーネント内のテキスト自動調整

ant design のアバターコンポーネントには、アバター内の文字数に応じて文字サイズが自動的にスケーリングされる効果があります。

image

これは Ant Design の効果で、とても素晴らしいです。

現在、CSS のコンテナクエリユニット(Chrome 105 + サポート)を使用することで、この効果を CSS だけで簡単に実現できます。

皆さんが比較的簡単にテストできるように、ここに HTML コードを示しますので、直接コピーしてテストしてください。 ここでは CDN 上の vue2 と UnoCSS のランタイムを使用していますが、これはデモを書くための便利さのためであり、原理はこの 2 つに依存していません。この 2 つの依存関係がなくても、どこでも使用できます。

<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://cdn.jsdelivr.net/npm/@unocss/runtime"></script>
  <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
  <title>アバター内文字自適応デモ</title>
  <style>
    .avator {
      /* flexで中央揃え */
      display: flex;
      align-items: center;
      justify-content: center;

      /* 幅と高さ */
      width: 50px;
      height: 50px;

      /* 角丸の色 */
      border-radius: 8px;
      background: #eaeaea;

      /* 文字の折り返しを許可しない */
      white-space: nowrap;
    }

    .avator-inner {
      position: relative;
    }

    .avator-inner::before {
      content: attr(alt);
      visibility: hidden;
      font-size: 40px;
    }

    /* 位置を利用して、このボックスを外側の.avator-innerと同じ大きさに設定 */
    /* つまり、avator-inner::beforeが文字で広がり、avator-innerとそのbeforeが同じ大きさになり、avator-containerが位置を利用してavator-innerと同じ大きさになる */
    .avator-container {
      position: absolute;
      inset: 0;
      container-type: inline-size;
      text-align: center;
      display: flex;
      justify-content: center;
      align-items: center;
    }

    .avator-container span {
      /* cqwを使って幅に反比例させる。つまり、文字が多いほどavator-innerのbeforeが大きくなり、ここでのfont-sizeも小さくなる */
      font-size: calc(24px - 10cqw);
      /* avator-containerは中央に位置しているため、境界との距離がない。これにpaddingを加えて境界との距離を設定 */
      display: inline-block;
      padding: 0 2px;

      overflow: hidden;
      max-width: 40px;
      text-overflow: ellipsis;

    }

  </style>
</head>

<body>
  <div id="app" class="min-h-screen">
    <main class="grid place-content-center gap-16px">
      <!-- 同じテキストを作成し、外側のコンテナ(A)の幅を内部のテキストによって決定し、コンテナボックス(B)の幅を(A)と同じに設定 -->
      <!-- これによりコンテナクエリが完成 -->
      <div class="avator" v-for="(item, index) in arr" :key="index">

        <!-- 外側のコンテナのテキストは擬似要素によって生成され、文字がavator-inner::beforeを広げる -->
        <div class="avator-inner" :alt="item">
          <div class="avator-container">
            <span>{{item}}</span>
          </div>
        </div>
      </div>
    </main>
  </div>

  <script>
    let vm = new Vue({
      el: '#app',
      data() {
        return {
          arr: ['', '名前', '三文字', '四文字あります', 'A', 'AB', 'ABC', 'ABCD', '英語']
        }
      }
    })
  </script>
</body>

</html>

コードデモ:
https://codepen.io/lainbojc/pen/KKxoWpz

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。