Đến nội dung chính

Sheet nửa màn

Dùng để vẫn thấy bản đồ hay ảnh phía sau, còn danh sách bên dưới thì kéo lên đúng mức cần.

Lớp phủ

Xem trước trực tiếp

Nguồn

<div class="dc-hs-stage">
  <div class="dc-hs-map" aria-hidden="true">
    <span class="dc-hs-map__pin"></span>
  </div>
  <section class="dc-hs" role="dialog" aria-labelledby="dc-hs-t">
    <button class="dc-hs__handle" type="button" aria-expanded="false" aria-controls="dc-hs-body">
      <span class="dc-hs__grip" aria-hidden="true"></span>
      <span class="dc-sr">목록 끝까지 펼치기</span>
    </button>
    <div class="dc-hs__body" id="dc-hs-body">
      <h2 class="dc-hs__title" id="dc-hs-t">가까운 수거함 6곳</h2>
      <p class="dc-hs__sub">성수동 기준 · 걸어서 12분 안</p>
      <ul class="dc-hs__list">
        <li class="dc-hs__row">
          <span class="dc-hs__name">성수동 주민센터 앞</span>
          <span class="dc-hs__meta">180m · 24시간</span>
        </li>
        <li class="dc-hs__row">
          <span class="dc-hs__name">뚝섬역 2번 출구</span>
          <span class="dc-hs__meta">420m · 오전 6시~자정</span>
        </li>
        <li class="dc-hs__row">
          <span class="dc-hs__name">서울숲 주차장 옆</span>
          <span class="dc-hs__meta">760m · 24시간</span>
        </li>
      </ul>
      <p class="dc-hs__hint">위로 끌거나 손잡이를 눌러 6곳을 모두 봅니다.</p>
    </div>
  </section>
</div>
.dc-hs-stage {
  position: relative; overflow: hidden;
  height: 520px;
  border-radius: var(--dc-r-md);
  font-family: var(--dc-font);
}
.dc-hs-map {
  position: absolute; inset: 0;
  background:
    repeating-linear-gradient(90deg, var(--dc-line) 0 1px, transparent 1px 46px),
    repeating-linear-gradient(0deg, var(--dc-line) 0 1px, transparent 1px 46px),
    var(--dc-sunken);
}
.dc-hs-map__pin {
  position: absolute; left: 48%; top: 22%;
  width: 16px; height: 16px;
  border: 3px solid var(--dc-surface); border-radius: var(--dc-r-full);
  background: var(--dc-brand);
  box-shadow: var(--dc-sh-2);
}
.dc-hs {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; flex-direction: column;
  height: 56%;
  background: var(--dc-surface);
  border-top: 1px solid var(--dc-line);
  border-radius: var(--dc-r-lg) var(--dc-r-lg) 0 0;
  box-shadow: var(--dc-sh-3);
  transition: height var(--dc-slow);
}
.dc-hs--full { height: 100%; border-radius: 0; padding-top: var(--dc-safe-top); }
.dc-hs--peek { height: 146px; }
.dc-hs__handle {
  flex: 0 0 auto;
  display: grid; place-items: center;
  width: 100%; height: 44px;
  border: 0; border-radius: var(--dc-r-lg) var(--dc-r-lg) 0 0;
  background: transparent;
  touch-action: none;
}
.dc-hs__grip {
  display: block; width: 44px; height: 5px;
  border-radius: var(--dc-r-full);
  background: var(--dc-line-bold);
  transition: background var(--dc-fast);
}
.dc-hs__handle:active .dc-hs__grip { background: var(--dc-brand); }
.dc-hs__close {
  position: absolute; right: var(--dc-2); top: calc(var(--dc-safe-top) + var(--dc-1));
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border: 0; border-radius: var(--dc-r-full);
  background: transparent; color: var(--dc-text-sub);
}
.dc-hs__close svg { width: 22px; height: 22px; }
.dc-hs__close:active { background: var(--dc-sunken); }
.dc-hs__body {
  flex: 1 1 auto; overflow-y: auto;
  padding: 0 var(--dc-5) calc(var(--dc-4) + var(--dc-safe-bottom));
}
.dc-hs__title { margin: 0; font-size: 17px; font-weight: 700; line-height: 1.4; color: var(--dc-text); }
.dc-hs__sub { margin: var(--dc-1) 0 var(--dc-4); font-size: 12px; color: var(--dc-text-sub); }
.dc-hs__list { margin: 0; padding: 0; list-style: none; }
.dc-hs__row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--dc-3);
  min-height: 56px; padding: var(--dc-2) 0;
  border-top: 1px solid var(--dc-line);
}
.dc-hs__name { font-size: 14px; font-weight: 600; color: var(--dc-text); }
.dc-hs__meta { flex: 0 0 auto; font-size: 12px; color: var(--dc-text-mute); }
.dc-hs__hint {
  margin: var(--dc-4) 0 0;
  padding: var(--dc-2) var(--dc-3);
  border-radius: var(--dc-r-sm);
  background: var(--dc-info-soft);
  font-size: 12px; line-height: 1.6; color: var(--dc-info);
  text-align: center;
}

Cách dùng

  • Đặt ba mức dừng — hé, nửa, toàn — và không cho nó dừng ở giữa
  • Ở mức nửa, luôn thấy tiêu đề và hai ba dòng, để người dùng biết có đáng kéo không
  • Tay nắm phải là nút thật: chạm vào cũng chuyển sang mức kế tiếp
  • Ở mức toàn màn không còn thấy gì phía sau, nên phải có cách đóng riêng

Điểm cần lưu ý

  • Chỉ kéo được thì người yếu tay không dùng nổi — chạm tay nắm và bàn phím phải làm được như nhau
  • Mỗi lần đổi chiều cao, phải đổi aria-expanded theo
  • Giữ --dc-safe-top ở mức toàn màn và --dc-safe-bottom ở cuối danh sách

Tiếp theo