Đến nội dung chính

Lớp bọc vùng an toàn

Chỉ đẩy nội dung của thanh cố định ra khỏi tai thỏ và vạch home, còn nền vẫn chạy hết mép.

Bố cục

Xem trước trực tiếp

Nguồn

<div class="dc-safe">
  <header class="dc-safe__top">
    <span class="dc-safe__hint">위 — padding-top: max(안전영역, 12px)</span>
    <div class="dc-safe__bar">
      <h1 class="dc-safe__title">내 정보</h1>
      <button class="dc-safe__ico" type="button">
        <span aria-hidden="true">⚙</span>
        <span class="dc-sr">설정</span>
      </button>
    </div>
  </header>
  <div class="dc-safe__body">
    <p class="dc-safe__text">배경은 화면 끝까지 깔고, 글자와 버튼만 안전영역 안쪽으로 들여놓습니다.</p>
    <p class="dc-safe__text">안전영역이 0인 기기에서도 여백이 남도록 max() 로 최소 여백을 함께 적습니다.</p>
  </div>
  <footer class="dc-safe__foot">
    <button class="dc-safe__btn" type="button">신청하기</button>
    <span class="dc-safe__hint">아래 — padding-bottom: max(안전영역, 12px)</span>
  </footer>
</div>
.dc-safe {
  display: flex; flex-direction: column;
  height: 440px; overflow: hidden;
  background: var(--dc-bg);
  border: 1px solid var(--dc-line);
  border-radius: var(--dc-r-md);
  font-family: var(--dc-font);
}
.dc-safe--dim { background: var(--dc-sunken); justify-content: flex-end; }
.dc-safe__top {
  flex: 0 0 auto;
  padding-top: max(var(--dc-safe-top), var(--dc-3));
  background: var(--dc-brand-soft);
  border-bottom: 1px solid var(--dc-line);
}
.dc-safe__hint {
  display: block;
  padding: 0 var(--dc-4) var(--dc-1);
  font-family: var(--dc-mono);
  font-size: 11px; line-height: 1.5;
  color: var(--dc-brand-text);
}
.dc-safe__bar {
  display: flex; align-items: center; gap: var(--dc-2);
  padding: 0 var(--dc-2) 0 var(--dc-4);
  background: var(--dc-surface);
}
.dc-safe__title {
  flex: 1 1 auto; min-width: 0;
  font-size: 18px; font-weight: 800; letter-spacing: -.02em;
  color: var(--dc-text);
}
.dc-safe__ico {
  flex: 0 0 auto;
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border: 0; border-radius: var(--dc-r-full);
  background: transparent; color: var(--dc-text);
  font-size: 19px; line-height: 1;
}
.dc-safe__ico:active { background: var(--dc-sunken); }
.dc-safe__body {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; gap: var(--dc-3);
  padding: var(--dc-4);
  overflow-y: auto;
}
.dc-safe__text { font-size: 14px; line-height: 1.7; color: var(--dc-text-sub); }
.dc-safe__foot {
  flex: 0 0 auto;
  padding: var(--dc-3) var(--dc-4) max(var(--dc-safe-bottom), var(--dc-3));
  background: var(--dc-brand-soft);
  border-top: 1px solid var(--dc-line);
}
.dc-safe__btn {
  display: block; width: 100%; min-height: 48px;
  border: 0; border-radius: var(--dc-r-sm);
  background: var(--dc-brand); color: var(--dc-text-on);
  font-family: inherit; font-size: 16px; font-weight: 700;
}
.dc-safe__btn:active { background: var(--dc-brand-hi); }
.dc-safe__sheet {
  flex: 0 0 auto;
  display: flex; flex-direction: column; gap: var(--dc-3);
  padding: var(--dc-2) var(--dc-4) max(var(--dc-safe-bottom), var(--dc-4));
  border-radius: var(--dc-r-lg) var(--dc-r-lg) 0 0;
  background: var(--dc-surface);
  box-shadow: var(--dc-sh-3);
}
.dc-safe__grip {
  width: 40px; height: 4px; margin: 0 auto;
  border-radius: var(--dc-r-full);
  background: var(--dc-line-bold);
}
.dc-safe__sheet-title { font-size: 17px; font-weight: 800; color: var(--dc-text); }
.dc-safe__hero {
  flex: 0 0 auto;
  display: flex; flex-direction: column; justify-content: space-between;
  min-height: 220px;
  padding-top: max(var(--dc-safe-top), var(--dc-3));
  background: linear-gradient(160deg, var(--dc-brand) 0%, var(--dc-info) 100%);
}
.dc-safe__hero-top {
  display: flex; align-items: center; gap: var(--dc-1);
  padding: 0 var(--dc-2);
}
.dc-safe__ico--onhero { color: var(--dc-text-on); }
.dc-safe__hint--onhero { color: var(--dc-text-on); opacity: .85; padding-bottom: 0; }
.dc-safe__hero-title {
  padding: var(--dc-4);
  font-size: 22px; font-weight: 800; line-height: 1.3; letter-spacing: -.02em;
  color: var(--dc-text-on);
}

Cách dùng

  • Tô nền ra hết mép, chỉ thụt nội dung vào đúng phần vùng an toàn
  • Viết thành max(vùng an toàn, một mức tối thiểu) để máy không có tai thỏ vẫn còn khoảng thở
  • Cộng vùng an toàn dưới vào padding-bottom của phần cuộn, để dòng cuối không bị vạch home che

Điểm cần lưu ý

  • Thiếu viewport-fit=cover trong thẻ meta viewport thì env() luôn bằng 0
  • Dùng padding chứ không dùng margin — margin sẽ để lộ nền phía sau thanh
  • Ở chế độ ngang còn có vùng an toàn trái và phải; màn hình tràn viền phải tính cả hai

Tiếp theo