DEV Community

mikebui
mikebui

Posted on

Nghệ thuật dựng component trong thực tế-Phần 2

Bài viết được dịch từ:
https://ishadeed.com/article/building-real-life-components/

Các khu vực của component

Để triển khai một component chuẩn, trước tiên chúng ta cần suy nghĩ kỹ về HTML trước. Trong trường hợp này, chúng ta có hai khu vực của component có nhiều biến thể đó là hình đại diện và khu vực nội dung.

Ảnh đại diện

Image avatar-1

Để code HTML cho phần avatar, trước tiên chúng ta cần hiểu các trạng thái của nó. Dưới đây là các biến thể có thể có:

  • Hình đại diện duy nhất
  • Hình đại diện duy nhất có trạng thái trực tuyến
  • Nhiều hình đại diện cho trò chuyện nhóm
  • Nhiều hình đại diện có trạng thái trực tuyến

Xem xét đoạn HTML sau, chúng ta muốn đảm bảo rằng .card__avatar có thể xử lý tất cả các biến thể ở trên.

<div class="card">
  <div class="card__avatar"></div>
  <div class="card__content">
    <!-- Name, message, badge.. -->
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode
Hình đại diện duy nhất

Hãy tập trung vào biến thể đầu tiên, đó là một hình đại diện duy nhất. Hình đại diện phải có đường viền bên trong (hoặc bóng trong) để làm cho nó trông giống như một vòng tròn ngay cả khi hình đại diện được sử dụng toàn màu trắng.

Image avatar-2

Trong CSS, không thể áp dụng box-shadow (inner) cho phần tử img. Chúng ta có hai lựa chọn:

  • Sử dụng thêm một thẻ div có đường viền trong suốt.
  • Sử dụng thẻ svg.

Mục tiêu nếu đường viền bên trong là hiển thị đường viền xung quanh hình đại diện trong các trường hợp:

  • hình đại diện toàn màu trắng ở chế độ ánh sáng
  • hình đại diện toàn màu đen ở chế độ tối

Image inset-shadow

Không có đường viền bên trong, sử dụng hình đại diện toàn màu trắng sẽ làm cho nó hòa trộn với nền gốc của nó. Điều tương tự cũng áp dụng cho chế độ tối. Đây là hình ảnh trực quan về những gì sẽ xảy ra có và không có đường viền bên trong.

Image inner-shadow-2

Sử dụng thẻ div cho đường viền bên trong

Đối với giải pháp này, một phần tử bổ sung (chính là thẻ div) được đặt hoàn toàn phía trên hình ảnh với độ mờ là 0,1.

<div class="card__avatar">
  <img src="assets/shadeed.jpg" alt="" />
  <div class="border"></div>
</div>
Enter fullscreen mode Exit fullscreen mode
.card__avatar {
  position: relative;
}

.card__avatar img {
  width: 56px;
  height: 56px;
  border-radius: 50%;
}

.border {
  position: absolute;
  width: 56px;
  height: 56px;
  border: 2px solid #000;
  border-radius: 50%;
  opacity: 0.1;
}
Enter fullscreen mode Exit fullscreen mode

Giải pháp này đúng, nhưng có một số hạn chế mà tôi sẽ giải thích sau đây.

Sử dụng thẻ svg

Đối với giải pháp này, chúng tôi sẽ sử dụng một thẻ svg. Ý tưởng là sử dụng mặt nạ hình tròn cho hình đại diện và phần tử circle cho đường viền bên trong. SVG hoạt động tuyệt vời cho điều này.

<svg role="none" style="height: 56px; width: 56px">
  <mask id="circle">
    <circle cx="28" cy="28" fill="white" r="28"></circle>
  </mask>
  <g mask="url(#circle)">
    <image
      x="0"
      y="0"
      height="100%"
      preserveAspectRatio="xMidYMid slice"
      width="100%"
      xlink:href="/assets/shadeed.jpg"
      style="height: 56px; width: 56px"
    ></image>
    <circle class="border" cx="28" cy="28" r="28"></circle>
  </g>
</svg>
Enter fullscreen mode Exit fullscreen mode
.border {
  stroke-width: 3;
  stroke: rgba(0, 0, 0, 0.1);
  fill: none;
}
Enter fullscreen mode Exit fullscreen mode

Cả hai giải pháp đều hoạt động được khi chỉ xây dựng với ví dụ hình đại diện duy nhất. Tuy nhiên, mọi thứ bắt đầu trở nên thú vị hơn khi chúng ta thêm yếu tố trực tuyến.

Hình đại diện duy nhất có trạng thái trực tuyến

Ở chế độ ánh sáng, hình tròn màu xanh lục có viền trắng. Tuy nhiên, ở chế độ tối, điều này nên được bị khỏi chính hình đại diện. Nói cách khác, nên sử dụng mặt nạ.

Image avatar-3

Làm thế nào chúng ta có thể làm điều đó? Nếu chúng ta sử dụng giải pháp svg cho hình đại diện duy nhất, điều này có thể được giải quyết dễ dàng bằng cách sử dụng mặt nạ SVG.

<svg role="none" style="height: 56px; width: 56px">
  <mask id="circle">
    <!-- [1] -->
    <circle cx="28" cy="28" fill="white" r="28"></circle>
    <!-- [2] -->
    <circle cx="48" cy="48" fill="black" r="7"></circle>
  </mask>
  <!-- [3] -->
  <g mask="url(#circle)">
    <image
      x="0"
      y="0"
      height="100%"
      preserveAspectRatio="xMidYMid slice"
      width="100%"
      xlink:href="/assets/shadeed.jpg"
      style="height: 56px; width: 56px"
    ></image>
    <circle class="border" cx="28" cy="28" r="28"></circle>
  </g>
</svg>
Enter fullscreen mode Exit fullscreen mode

Hãy để tôi chia nhỏ đoạn code SVG trên:

  1. Một vòng tròn để che hình đại diện thực tế.
  2. Một hình tròn nhỏ để cắt từ góc dưới bên phải của hình đại diện.
  3. Một group chứa imagecircle cho đường viền bên trong trong suốt.

Dưới đây là hình ảnh giải thích cách hoạt động:

Image avatar-4

Cùng với đó, đây là đoạn code HTML.

<div class="card__avatar">
  <svg role="none" style="height: 56px; width: 56px">
    <mask id="circle">
      <circle cx="28" cy="28" fill="white" r="28"></circle>
      <circle cx="48" cy="48" fill="black" r="7"></circle>
    </mask>
    <g mask="url(#circle)">
      <image
        x="0"
        y="0"
        height="100%"
        preserveAspectRatio="xMidYMid slice"
        width="100%"
        xlink:href="/assets/shadeed.jpg"
        style="height: 56px; width: 56px"
      ></image>
      <circle class="border" cx="28" cy="28" r="28"></circle>
    </g>
  </svg>
  <div class="badge"></div>
</div>
Enter fullscreen mode Exit fullscreen mode
.card__avatar {
  position: relative;
  display: flex;
  margin-right: 12px;
}

.badge {
  position: absolute;
  right: 3px;
  bottom: 3px;
  width: 10px;
  height: 10px;
  background: #5ad539;
  border-radius: 50%;
}
Enter fullscreen mode Exit fullscreen mode

Khi một component như thế này cần phải thích ứng với cả bố cục sáng và tối, bạn nên sử dụng các biến CSS để xử lý nhằm lưu trữ các giá trị của màu cần thay đổi.

:root {
  --primary-text: #050505;
  --secondary-text: #65676b;
  --bg-color: #fff;
}

html.is-dark {
  --primary-text: #e4e6eb;
  --secondary-text: #b0b3b8;
  --bg-color: #242526;
}

.card {
  background-color: var(--bg-color);
}

.card__title {
  color: var(--primary-text);
}

.card__subtitle {
  color: var(--secondary-text);
}
Enter fullscreen mode Exit fullscreen mode

Hết phần 2

Top comments (0)