banner
Lainbo

Lainbo's Blog

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

Pure CSS Avatar Component Text Adaptation

The avatar component of Ant Design has an effect that automatically scales the text size based on the number of characters in the avatar.

image

This is the effect of Ant Design, which is great.

Now that we have CSS container queries (supported in Chrome 105+), we can easily achieve this effect using only CSS.

To make it convenient for everyone to test, here is the HTML code for easy copying and testing. This uses Vue 2 and UnoCSS runtime from CDN, which is just for writing the demo; the principle does not rely on these two. You can still use it anywhere without these dependencies.

<!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>Adaptive Text in Avatar Demo</title>
  <style>
    .avator {
      /* flex center */
      display: flex;
      align-items: center;
      justify-content: center;

      /* width and height */
      width: 50px;
      height: 50px;

      /* border radius and color */
      border-radius: 8px;
      background: #eaeaea;

      /* prevent text wrapping */
      white-space: nowrap;
    }

    .avator-inner {
      position: relative;
    }

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

    /* Use positioning to set this box to be the same size as the outer .avator-inner */
    /* That is, avator-inner::before is expanded by text, avator-inner and its before are the same size, avator-container uses positioning to be the same size as 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 {
      /* Use cqw to make it inversely proportional to width, meaning the more text, the larger avator-inner's before, and the smaller the font-size here */
      font-size: calc(24px - 10cqw);
      /* Since avator-container is positioned in the center, there is no distance from the boundary, this adds padding to write the distance from the boundary */
      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">
      <!-- Create an identical text, allowing the outer container (A) width to be determined by the internal text, then set the container box (B) width to be the same as (A) -->
      <!-- Complete container query this way -->
      <div class="avator" v-for="(item, index) in arr" :key="index">

        <!-- The text of the outer container is generated by pseudo-elements, and the text will expand 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: ['I', 'Name', 'Three Characters', 'Four Characters', 'A', 'AB', 'ABC', 'ABCD', 'English']
        }
      }
    })
  </script>
</body>

</html>

Code demonstration:
https://codepen.io/lainbojc/pen/KKxoWpz

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.