Bagian 2 menghasilkan kartu yang lengkap tetapi datar: semua kartu hanya dibedakan oleh garis 1 px. Bagian 3 menambahkan kedalaman dengan bayangan dan penekanan border. Yang menarik, tidak ada nilai bayangan baru yang ditulis di sini; ketiga token --bayangan-* sudah disiapkan sejak Bagian 1, dan tugas bagian ini hanyalah memasangkannya ke varian kartu yang tepat. Perubahan kodenya pendek, hanya tujuh aturan, tetapi dampak visualnya besar.
Tiga Tingkat Elevasi #
Aturan pertama memberi setiap kartu elevasi dasar: .kartu { box-shadow: var(--bayangan-1); }. Tingkat pertama ini sengaja sangat halus, hanya 1 px blur dengan opasitas 0.08, sehingga kartu terasa sedikit terangkat tanpa terlihat berat. Semua kartu berbagi dasar yang sama; yang membedakan varian adalah tingkat di atasnya.
.kartu--produk naik ke --bayangan-2 dan sekaligus melepas garisnya dengan border-color: transparent. Pasangan ini disengaja: bila bayangan mulai tebal, garis 1 px di tepi justru membuat tepi kartu tampak ganda, maka varian yang lebih “dekat ke pembaca” dilepas dari garisnya. Sebaliknya, .kartu--artikel justru mendapat box-shadow: none. Kartu artikel adalah tautan yang seluruh bidangnya bisa diklik, dan di galeri yang padat, kartu tanpa bayangan terbaca sebagai isi, bukan sebagai tombol beli. Kontras elevasi antarvarian itulah yang menyampaikan hierarki, bukan sekadar hiasan.
Kebiasaan sehat lainnya adalah menahan diri: tiga tingkat sudah cukup untuk satu aplikasi. Begitu jumlah tingkat bayangan bertambah, hierarki kehilangan makna karena pembaca tidak lagi bisa menebak mana yang paling penting. Kalau suatu komponen terasa membutuhkan tingkat keempat, biasanya masalahnya ada di komposisi, bukan di bayangannya.
Perlu diingat bahwa token bayangan memakai rgba dari rona cokelat teks, bukan hitam murni. Karena itu bayangan menyatu dengan palet hangat halaman dan tidak terlihat seperti coretan abu-abu di atas latar krem.
Aksen Border #
Elevasi bukan satu-satunya alat; border juga bisa menyampaikan makna. .kartu--statistik menambahkan border-left: 4px solid var(--warna-utama), sebuah bilah vertikal tipis yang menandai kartu angka sebagai kategori berbeda di galeri. Trik kecil ini murah dari sisi performa maupun kode, tetapi sangat efektif saat galeri memuat campuran tipe kartu.
Aksen serupa diterapkan pada .kartu-avatar: border 3 px berwarna --warna-permukaan plus --bayangan-1. Karena lingkaran avatar berisi gradient gelap, garis berwarna permukaan ini bekerja seperti cincin pemisah sehingga inisial tidak menyatu dengan latar kartu. Pola “border berwarna latar di belakang elemen bulat” ini muncul di banyak antarmuka nyata dan layak dicatat sebagai resep.
/* ============================================================
Koleksi Kartu UI — stylesheet utama
Urutan: token → base → kerangka halaman → tombol → kartu
→ varian → elevasi → tipografi → state → tema gelap
============================================================ */
/* ---------- 1. Design token ---------- */
:root {
/* Warna semantik, tema terang */
--warna-latar: #f6f1e7; --warna-permukaan: #ffffff;
--warna-teks: #2a2118; --warna-teks-lembut: #6d5c48;
--warna-garis: #e4d9c6; --warna-utama: #7a4a21;
--warna-utama-pekat: #5c3517; --warna-utama-kontras: #ffffff;
--warna-utama-lembut: #f0e2cf; --warna-aksen: #b3541e;
--warna-sukses: #1f7a4d; --warna-bahaya: #b3372b;
--warna-fokus: #1d4ed8;
/* Skala spasi, basis empat dan delapan piksel */
--jarak-1: 4px; --jarak-2: 8px;
--jarak-3: 12px; --jarak-4: 16px;
--jarak-5: 24px; --jarak-6: 32px;
--jarak-7: 48px; --jarak-8: 64px;
/* Radius sudut */
--radius-kecil: 6px; --radius: 12px;
--radius-penuh: 999px;
/* Elevasi bayangan, tiga tingkat */
--bayangan-1: 0 1px 2px rgba(42, 33, 24, 0.08);
--bayangan-2: 0 4px 12px rgba(42, 33, 24, 0.14);
--bayangan-3: 0 12px 28px rgba(42, 33, 24, 0.18);
/* Skala tipografi */
--font-dasar: system-ui, "Segoe UI", sans-serif;
--ukuran-teks-kecil: 0.8125rem;
--ukuran-teks-sedang: 0.9375rem;
--ukuran-teks-dasar: 1rem;
--ukuran-teks-subjudul: 1.25rem;
--ukuran-teks-judul: 1.5rem;
--ukuran-angka: 2.25rem;
--tinggi-baris: 1.55;
--jejak-huruf-lebar: 0.08em;
/* Gerak */
--durasi-cepat: 120ms; --durasi: 200ms; --pelunakan: ease-out;
/* Kerangka halaman */
--lebar-isi: 1080px;
}
/* ---------- 2. Base ---------- */
*, *::before, *::after {
box-sizing: border-box;
}
body {
margin: 0;
font-family: var(--font-dasar);
line-height: var(--tinggi-baris);
background-color: var(--warna-latar);
color: var(--warna-teks);
}
h1, h2, h3, p, figure { margin: 0; }
img { display: block; max-width: 100%; }
/* ---------- 3. Kerangka halaman ---------- */
.pembungkus {
max-width: var(--lebar-isi);
margin-inline: auto;
padding-inline: 16px;
}
.laman-kepala {
padding-block: 24px;
background-color: var(--warna-permukaan);
border-bottom: 1px solid var(--warna-garis);
}
.kepala-baris {
display: flex; align-items: center;
justify-content: space-between;
gap: 16px; flex-wrap: wrap;
}
.brand { display: flex; align-items: center; gap: 12px; }
.brand img { width: 40px; height: 40px; }
.brand-nama { font-size: 20px; font-weight: 700; }
.laman-utama { padding-block: 48px 64px; }
.section-judul { font-size: 28px; font-weight: 800; }
.pengantar { margin-top: 8px; max-width: 65ch; color: var(--warna-teks-lembut); font-size: 15px; }
.pamer-token {
display: flex; flex-wrap: wrap;
gap: 12px 24px; margin-top: 24px;
padding: 16px; background-color: var(--warna-permukaan);
border: 1px solid var(--warna-garis); border-radius: 12px;
}
.token { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.token-contoh { width: 24px; height: 24px; border-radius: 6px; border: 1px solid var(--warna-garis); }
.token-nama { color: var(--warna-teks-lembut); }
.galeri-kartu {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 24px; margin-top: 32px;
}
.laman-kaki {
background-color: var(--warna-permukaan);
border-top: 1px solid var(--warna-garis);
}
.kaki-baris {
display: flex; justify-content: space-between;
flex-wrap: wrap; gap: 8px 16px;
padding-block: 24px; font-size: 13.5px;
color: var(--warna-teks-lembut);
}
/* ---------- 4. Tombol ---------- */
.tombol {
display: inline-block;
padding: 9px 18px; border: none; border-radius: 6px;
background-color: var(--warna-utama);
color: var(--warna-utama-kontras);
font: inherit; font-weight: 600; cursor: pointer;
}
.tombol:hover { background-color: var(--warna-utama-pekat); }
.tombol--sekunder { background-color: var(--warna-utama-lembut); color: var(--warna-utama-pekat); }
.tombol--sekunder:hover { background-color: var(--warna-garis); }
/* ---------- 5. Kartu ---------- */
.kartu {
display: flex; flex-direction: column;
gap: 12px; padding: 16px;
background-color: var(--warna-permukaan);
border: 1px solid var(--warna-garis); border-radius: 12px;
}
.kartu-lencana {
align-self: flex-start;
padding: 4px 12px; border-radius: var(--radius-penuh);
background-color: var(--warna-utama-lembut); color: var(--warna-utama-pekat);
font-size: 11.5px; font-weight: 700;
}
.kartu--produk .kartu-lencana { background-color: var(--warna-aksen); color: #ffffff; }
.kartu-media {
aspect-ratio: 16 / 10;
border-radius: 8px;
background: linear-gradient(135deg, #d8a26a 0%, #7a4a21 100%);
}
.kartu-judul { font-size: 20px; line-height: 1.3; font-weight: 700; }
.kartu-teks { font-size: 14.5px; color: var(--warna-teks-lembut); }
.kartu-meta {
display: flex; align-items: center;
gap: 8px; font-size: 12.5px;
color: var(--warna-teks-lembut);
}
.kartu-aksi {
margin-top: auto;
display: flex; align-items: center;
justify-content: space-between; gap: 8px;
}
.kartu-harga { font-size: 16px; font-weight: 700; color: var(--warna-utama-pekat); }
/* ---------- 6. Varian kartu ---------- */
.kartu--artikel { color: inherit; text-decoration: none; }
.kartu--artikel .kartu-meta { margin-top: auto; padding-top: 4px; }
.kartu--profil { align-items: center; text-align: center; }
.kartu-avatar {
width: 72px; height: 72px;
display: grid; place-items: center;
border-radius: var(--radius-penuh);
background: linear-gradient(135deg, #b3541e, #7a4a21);
color: #ffffff; font-size: 26px; font-weight: 700;
}
.kartu-peran { font-size: 13px; color: var(--warna-teks-lembut); }
.kartu-angka { font-size: 34px; font-weight: 800; line-height: 1.1; }
.kartu-tren { align-self: flex-start; padding: 2px 10px; border-radius: var(--radius-penuh); font-size: 12.5px; font-weight: 700; }
.kartu-tren--naik { color: var(--warna-sukses); }
.kartu-tren--turun { color: var(--warna-bahaya); }
/* ---------- 7. Elevasi dan aksen border ---------- */
.kartu { box-shadow: var(--bayangan-1); }
/* Kartu promosi naik satu tingkat dan melepas garis */
.kartu--produk {
box-shadow: var(--bayangan-2);
border-color: transparent;
}
/* Kartu artikel mengandalkan garis, bukan bayangan */
.kartu--artikel { box-shadow: none; }
/* Aksen kiri menandai kartu angka */
.kartu--statistik { border-left: 4px solid var(--warna-utama); }
.kartu-avatar {
border: 3px solid var(--warna-permukaan);
box-shadow: var(--bayangan-1);
}Ringkasan #
Tahap ini membuktikan bahwa kedalaman tidak butuh kode banyak bila tokennya sudah disiapkan: satu deklarasi untuk dasar, satu pasangan untuk kartu promosi, satu pengecualian untuk kartu tautan, dan dua aksen border. Pelajaran utamanya adalah elevasi harus bervariasi sesuai peran kartu, bukan seragam; bayangan tebal untuk hal yang menunggu aksi, garis untuk hal yang bisa dibaca.