Hình cắt theo hình dạng

Tính năng web: Mặt nạ

Tổng quan

Tính năng Tạo mặt nạ CSS cho phép bạn cắt một phần tử thành hình dạng tuỳ chỉnh, chẳng hạn như thêm một rãnh vào thẻ hoặc tạo đường viền có hình dạng. Khi kết hợp các hình dạng cho bố cục phức tạp, hãy chọn chiến lược tạo mặt nạ dựa trên loại nội dung mà phần tử chứa:

Chiến lược che giấu Tốt nhất cho Tác động của văn bản
Tạo mặt nạ SVG cho phần tử trực tiếp Hình ảnh, biểu tượng, hình dạng trang trí, hình dạng phức tạp Không nên dùng (có thể cắt bớt văn bản)
Tạo mặt nạ SVG cho phần tử liền kề Thẻ có văn bản, nội dung quan trọng Văn bản vẫn có thể đọc được đầy đủ
Chuyển màu thuần tuý bằng CSS Hình dạng hình học đơn giản Không nên dùng (có thể cắt bớt văn bản)

Triển khai

Cách triển khai vết cắt có hình dạng:

Sử dụng mặt nạ SVG

Mặt nạ SVG cho phép bạn xác định các hình dạng để trừ hoặc thêm vào vùng hiển thị bằng cách sử dụng màu trắng (hiện) và màu đen (ẩn).

Mặt nạ độ sáng so với mặt nạ alpha: Mặt nạ SVG mặc định ở chế độ độ sáng (độ sáng), đó là lý do chúng ta sử dụng fill="white" để hiển thị các vùng và fill="black" để cắt các vùng đó. Nếu muốn sử dụng độ trong suốt (kênh alpha) của SVG thay vì màu sắc, bạn có thể đặt mask-type: alpha; trong CSS hoặc mask-type="alpha" trên phần tử <mask> của SVG.

Tạo mặt nạ SVG cho phần tử trực tiếp

Khi không có văn bản nào bên trong phần tử cần quan tâm (chẳng hạn như hình đại diện hồ sơ, hình ảnh sản phẩm hoặc hình minh hoạ), bạn có thể áp dụng mặt nạ SVG trực tiếp cho phần tử đó.

Việc sử dụng maskContentUnits="objectBoundingBox" bên trong mặt nạ SVG đảm bảo rằng mặt nạ tự động điều chỉnh theo chiều rộng và chiều cao của bất kỳ phần tử nào mà mặt nạ được áp dụng.

<!-- 1. Define the mask in SVG (hidden from view) -->
<svg width="0" height="0" style="position: absolute;" aria-hidden="true">
  <defs>
    <!-- objectBoundingBox makes the mask scale from 0 to 1 along the element's borders -->
    <mask id="splat-mask" maskContentUnits="objectBoundingBox">
      <!-- Organic Bezier path defining an artistic paint splat shape -->
      <path d="M 0.5 0.05 C 0.58 0.05, 0.58 0.21, 0.67 0.18 C 0.76 0.15, 0.79 0.08, 0.85 0.15 C 0.91 0.22, 0.83 0.32, 0.89 0.38 C 0.95 0.44, 1.03 0.45, 0.99 0.55 C 0.95 0.65, 0.82 0.62, 0.8 0.72 C 0.78 0.82, 0.89 0.92, 0.8 0.97 C 0.71 1.02, 0.64 0.88, 0.55 0.93 C 0.46 0.98, 0.44 1.06, 0.35 1.01 C 0.26 0.96, 0.31 0.81, 0.22 0.79 C 0.13 0.77, 0.01 0.88, 0.01 0.77 C 0.01 0.66, 0.16 0.62, 0.14 0.52 C 0.12 0.42, -0.02 0.39, 0.03 0.29 C 0.08 0.19, 0.23 0.27, 0.29 0.19 C 0.35 0.11, 0.3 0.01, 0.4 0.01 C 0.5 0.01, 0.42 0.05, 0.5 0.05 Z" fill="white" />
    </mask>
  </defs>
</svg>

<!-- 2. Apply the mask to the image element -->
<img src="avatar.jpg" alt="User Profile" class="shaped-avatar">

<style>
.shaped-avatar {
  width: 200px;
  height: 200px;
  object-fit: cover;
  
  /* Apply the SVG mask ID with standard and webkit-prefixed properties */
  -webkit-mask-image: url(#splat-mask);
  mask-image: url(#splat-mask);
}
</style>

Tạo mặt nạ SVG cho phần tử liền kề

Áp dụng mặt nạ cho một phần tử liền kề thay vì phần tử mẹ chứa văn bản. Điều này đảm bảo rằng văn bản không bị cắt bớt và vẫn dễ đọc.

Để giải quyết vấn đề này, hãy sắp xếp thành phần của bạn thành bố cục gồm hai phần:

  1. Vùng chứa văn bản an toàn, không bị che (.card-body) cho tất cả nội dung có thể đọc được.
  2. Một div trống để trang trí (.card-accent) được đặt bên cạnh, nhận mặt nạ SVG tuỳ chỉnh.

Bằng cách gán cùng một màu nền cho cả hai phần, chúng sẽ hợp nhất thành một thành phần có hình dạng tuỳ chỉnh.

<!-- 1. Define the SVG mask (hidden from view) -->
<svg width="0" height="0" style="position: absolute;" aria-hidden="true">
  <defs>
    <!-- Use objectBoundingBox to make the mask scale with the element -->
    <mask id="accent-stencil" maskContentUnits="objectBoundingBox">
      <!-- Fill the entire area with white (fully visible) -->
      <rect width="1" height="1" fill="white" />
      <!-- Draw a black shape to cut out a concave curve. Extending the path to x=1.1 guarantees it fully clears the right edge, preventing subpixel lines -->
      <path d="M 1.1,0 C 0.4,0.1 0.4,0.9 1.1,1 L 1.1,0 Z" fill="black" />
    </mask>
  </defs>
</svg>

<!-- 2. Create the unified card layout -->
<div class="unified-card">
  <!-- The text-bearing element remains unmasked and perfectly rectangular -->
  <div class="card-body">
    <h3>Premium Membership</h3>
    <p>Get exclusive weekly updates on modern web standards and premium UI designs.</p>
  </div>
  <!-- The empty accent element next to it is masked to form the custom shape -->
  <div class="card-accent"></div>
</div>

<style>
.unified-card {
  display: flex;
  width: 400px;
}

.card-body {
  flex: 1;
  background-color: #1e293b; /* Elegant slate color */
  color: #f8fafc;
  padding: 24px;
  border-top-left-radius: 16px;
  border-bottom-left-radius: 16px;
}

.card-accent {
  width: 60px;
  background-color: #1e293b; /* Same background color so they merge visually without seams */
  border-top-right-radius: 16px;
  border-bottom-right-radius: 16px;

  /* Reference the SVG mask */
  -webkit-mask-image: url(#card-accent-mask);
  mask-image: url(#card-accent-mask);
}
</style>

Sử dụng một dải chuyển màu CSS duy nhất cho các đường cắt đơn giản

Khi chỉ cần các đường cắt hình học đơn giản (chẳng hạn như rãnh trên cùng hình bán nguyệt, vết lõm bên hoặc đường cắt chéo thẳng), bạn không cần viết hoặc tham chiếu SVG bên ngoài. Thay vào đó, bạn có thể xác định dải chuyển màu tuyến tính hoặc dải chuyển màu tròn CSS ngay bên trong thuộc tính mask-image.

<div class="gradient-masked-card">
  <h3>Notched Coupon Card</h3>
  <p>This card uses a pure CSS radial gradient to cut out a semi-circular notch along its top edge.</p>
</div>

<style>
.gradient-masked-card {
  background: linear-gradient(135deg, #3b82f6, #1d4ed8);
  color: white;
  padding: 40px 24px 24px 24px; /* Extra top padding ensures content clears the notch */
  border-radius: 16px;
  text-align: center;

  /* radial-gradient places a circle at 50% (horizontal center) and 0% (top edge), cutting out a 20px transparent notch */
  -webkit-mask-image: radial-gradient(circle at 50% 0%, transparent 20px, black 21px);
  mask-image: radial-gradient(circle at 50% 0%, transparent 20px, black 21px);
}
</style>

Chiến lược dự phòng

Nếu trình duyệt không hỗ trợ mask-image hoặc phiên bản có tiền tố:

  • Đối với hình ảnh có hình dạng: Phần tử sẽ giảm dần một cách mượt mà, hiển thị dưới dạng phần tử hình chữ nhật thông thường với kiểu dự phòng mặc định.
  • Đối với Thẻ có hình dạng: Phần tử trang trí .card-accent liền kề sẽ vẫn là một hình chữ nhật đặc, không có mặt nạ. Vì có cùng màu nền với vùng chứa văn bản, nên toàn bộ thẻ sẽ chỉ hiển thị dưới dạng một vùng chứa hình chữ nhật tiêu chuẩn, rõ ràng.
  • Cải tiến tăng dần: Bằng cách giữ các lớp văn bản hoàn toàn bên ngoài mặt nạ, nội dung của bạn được đảm bảo luôn dễ đọc, có cấu trúc và dễ tiếp cận trên các trình duyệt cũ.