Halaman harga hidup dari tombolnya: setiap kartu mengakhiri daftar fitur dengan ajakan bertindak, dan saklar di hero memutuskan harga mana yang ditampilkan. Sampai Bagian 3, tombol-tombol itu masih tampil sebagai tautan polos dan saklar sebagai checkbox mentah bawaan browser. Bagian ini menambahkan dua seksi CSS — tombol dan saklar — tanpa mengubah satu pun baris HTML; snapshot beranda.html disertakan kembali apa adanya agar setiap bagian tetap bisa dijalankan sendiri, sedangkan styles.css bertambah dua seksi penuh.
Tombol Utama dan Varian Garis #
Tombol utama dibangun untuk dua elemen sekaligus — button dan a — karena markup kita memakai tautan sebagai call-to-action. Class .tombol memakai display: inline-block agar padding dan radius bekerja pada tautan, font: inherit agar ukuran hurufnya mengikuti halaman, dan satu transisi untuk dua properti:
.tombol {
transition: background-color var(--durasi) var(--pelunakan), transform var(--durasi) var(--pelunakan);
}
.tombol:hover { background-color: var(--warna-utama-pekat); }
.tombol:active { transform: translateY(1px); }State :hover menggelapkan latar ke --warna-utama-pekat, sedangkan :active menurunkan tombol satu piksel — umpan balik kecil yang membuat klik terasa nyata. Varian .tombol--garis membalik konsepnya: latar transparan, teks indigo, dan border satu piksel berwarna --warna-utama; saat dihover, latarnya terisi --warna-utama-lembut. Pemakaian di halaman: paket Pemula dan Enterprise memakai varian garis, paket terlaris memakai tombol utama penuh — hierarki visual yang mengarahkan mata ke satu aksi terpenting.
Membangun Saklar dari Checkbox #
Saklar tagihan tetap sebuah <input type="checkbox"> yang asli — hanya tampilannya yang kita ganti. Input disembunyikan dari pandangan tetapi tetap bisa diklik dan difokuskan:
.saklar input {
position: absolute; inset: 0;
margin: 0; opacity: 0;
cursor: pointer;
}Input menutupi seluruh label (inset: 0), sehingga klik di mana pun pada saklar tetap mencentangnya. Dua span di belakangnya menjadi lintasan dan kenop; keduanya diberi aria-hidden="true" karena murni dekorasi. Perubahan keadaan digambar lewat sibling selector:
.saklar input:checked + .saklar-lintasan {
background-color: var(--warna-utama);
}
.saklar input:checked + .saklar-lintasan .saklar-kenop {
transform: translateX(20px);
}Saat tercentang, lintasan berubah indigo dan kenop bergeser 20 px ke kanan dengan transisi transform — properti yang dianimasikan browser tanpa menghitung ulang tata letak. Ring fokus juga dialihkan: .saklar input:focus-visible + .saklar-lintasan menggambar outline pada lintasan, bukan pada input yang tidak terlihat, sehingga navigasi Tab tetap jelas.
Aksesibilitas Saklar dan Lencana Hemat #
Checkbox asli sudah cukup untuk pembaca layar, tetapi kita memperkuatnya dengan role="switch" agar diumumkan sebagai saklar dua keadaan; atribut aria-checked diselaraskan oleh JavaScript pada Bagian 5. Teks “Ganti ke tagihan tahunan” dibungkus class sr-only — tersembunyi secara visual, tetap terbaca teknologi bantu:
.sr-only {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap; border: 0;
}Pola ini menyingkirkan kebutuhan gambar ikon sekaligus menjaga nama yang mudah diakses. Label “Bulanan” dan “Tahunan” di sisi saklar memakai .pilih-label, dan lencana “Hemat 2 bulan” tampil sebagai pil teal dari pasangan token --warna-hemat-latar dan --warna-hemat-teks — aksen warna kedua yang sengaja beda dari indigo agar alasan promosi langsung terlihat.
/* ============================================================
Halaman Harga Layanan — stylesheet utama
Urutan: token → base → kerangka halaman → galeri harga →
kartu harga → tabel banding → tombol → saklar tagihan →
responsif → gerak dan fokus
============================================================ */
/* ---------- 1. Design token ---------- */
:root {
/* Warna semantik, tema terang */
--warna-latar: #f8fafc; --warna-permukaan: #ffffff;
--warna-teks: #0f172a; --warna-teks-lembut: #64748b;
--warna-garis: #e2e8f0; --warna-utama: #4f46e5;
--warna-utama-pekat: #4338ca; --warna-utama-kontras: #ffffff;
--warna-utama-lembut: #e0e7ff; --warna-utama-tinta: #312e81;
--warna-fokus: #1d4ed8; --warna-sukses: #15803d;
--warna-hemat-latar: #ccfbf1; --warna-hemat-teks: #0f766e;
--warna-lintasan: #cbd5e1;
/* 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: 8px; --radius: 12px;
--radius-penuh: 999px;
/* Elevasi bayangan, tiga tingkat */
--bayangan-1: 0 1px 2px rgba(15, 23, 42, 0.06);
--bayangan-2: 0 6px 16px rgba(79, 70, 229, 0.14);
--bayangan-3: 0 16px 32px rgba(79, 70, 229, 0.18);
/* Tipografi dan gerak */
--font-dasar: system-ui, "Segoe UI", sans-serif;
--tinggi-baris: 1.6;
--durasi: 180ms; --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, ul { margin: 0; }
img { display: block; max-width: 100%; }
/* ---------- 3. Kerangka halaman ---------- */
.pembungkus {
max-width: var(--lebar-isi);
margin-inline: auto;
padding-inline: var(--jarak-4);
}
.laman-kepala {
padding-block: var(--jarak-4);
background-color: var(--warna-permukaan);
border-bottom: 1px solid var(--warna-garis);
}
.kepala-baris {
display: flex; align-items: center;
justify-content: space-between;
gap: var(--jarak-4); flex-wrap: wrap;
}
.brand { display: flex; align-items: center; gap: var(--jarak-2); }
.brand img { width: 36px; height: 36px; }
.brand-nama { font-size: 19px; font-weight: 800; }
.nav-kepala { display: flex; gap: var(--jarak-4); }
.nav-kepala a { color: var(--warna-teks-lembut); font-size: 15px; font-weight: 600; text-decoration: none; }
.nav-kepala a:hover { color: var(--warna-utama); }
.hero { padding-block: var(--jarak-7) var(--jarak-5); text-align: center; }
.judul-halaman { font-size: clamp(1.8rem, 4vw, 2.6rem); line-height: 1.2; letter-spacing: -0.02em; }
.pengantar { max-width: 56ch; margin: var(--jarak-3) auto 0; color: var(--warna-teks-lembut); }
.pilih-tagihan { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: var(--jarak-3); margin-top: var(--jarak-5); }
.pilih-label { font-size: 15px; font-weight: 600; color: var(--warna-teks-lembut); }
.lencana-hemat { padding: 3px 12px; border-radius: var(--radius-penuh); background-color: var(--warna-hemat-latar); color: var(--warna-hemat-teks); font-size: 12.5px; font-weight: 700; }
.laman-kaki { margin-top: var(--jarak-8); padding-block: var(--jarak-5); background-color: var(--warna-permukaan); border-top: 1px solid var(--warna-garis); }
.kaki-baris { display: flex; justify-content: space-between; flex-wrap: wrap; gap: var(--jarak-2) var(--jarak-4); font-size: 13.5px; color: var(--warna-teks-lembut); }
/* ---------- 4. Galeri harga ---------- */
.galeri-harga { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: var(--jarak-5); align-items: stretch; margin-top: var(--jarak-6); }
/* ---------- 5. Kartu harga ---------- */
.kartu-harga {
position: relative;
display: flex; flex-direction: column;
gap: var(--jarak-3);
padding: var(--jarak-5) var(--jarak-4);
background-color: var(--warna-permukaan);
border: 1px solid var(--warna-garis);
border-radius: var(--radius);
box-shadow: var(--bayangan-1);
transition: box-shadow var(--durasi) var(--pelunakan), transform var(--durasi) var(--pelunakan);
}
.kartu-nama { font-size: 19px; font-weight: 800; }
.kartu-deskripsi { font-size: 14px; color: var(--warna-teks-lembut); }
.kartu-harga-baris { display: flex; align-items: baseline; gap: 6px; margin-top: var(--jarak-1); }
.kartu-angka { font-size: 2.1rem; font-weight: 800; letter-spacing: -0.02em; }
.kartu-angka--custom { font-size: 1.5rem; color: var(--warna-utama); }
.kartu-satuan { font-size: 14px; color: var(--warna-teks-lembut); }
.kartu-fitur { display: grid; gap: var(--jarak-2); margin-top: var(--jarak-1); padding: 0; list-style: none; font-size: 14.5px; }
.kartu-fitur li { position: relative; padding-left: 26px; }
.kartu-fitur li::before { content: "✓"; position: absolute; left: 0; color: var(--warna-sukses); font-weight: 700; }
.kartu-harga .tombol { margin-top: auto; text-align: center; }
.kartu-lencana { position: absolute; top: -12px; left: 50%; transform: translateX(-50%); padding: 4px 14px; border-radius: var(--radius-penuh); background-color: var(--warna-utama); color: var(--warna-utama-kontras); font-size: 12px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; }
.kartu-harga--unggulan {
border: 2px solid var(--warna-utama);
box-shadow: var(--bayangan-2);
}
.kartu-harga--unggulan .kartu-angka { color: var(--warna-utama); }
.kartu-harga:hover {
box-shadow: var(--bayangan-2);
transform: translateY(-2px);
}
.kartu-harga--unggulan:hover { box-shadow: var(--bayangan-3); }
/* ---------- 6. Tabel perbandingan ---------- */
.seksi-banding { margin-top: var(--jarak-7); }
.section-judul { font-size: 24px; font-weight: 800; letter-spacing: -0.01em; }
.tabel-gulir { margin-top: var(--jarak-4); overflow-x: auto; background-color: var(--warna-permukaan); border: 1px solid var(--warna-garis); border-radius: var(--radius); }
.tabel-banding { width: 100%; min-width: 560px; border-collapse: collapse; font-size: 14.5px; }
.tabel-banding th, .tabel-banding td { padding: 12px 16px; text-align: left; border-bottom: 1px solid var(--warna-garis); }
.tabel-banding thead th { background-color: var(--warna-utama-lembut); color: var(--warna-utama-tinta); font-size: 13px; letter-spacing: 0.05em; text-transform: uppercase; }
.tabel-banding tbody th { font-weight: 600; }
.tabel-banding tbody tr:nth-child(even) { background-color: var(--warna-latar); }
.tabel-banding tbody tr:last-child th, .tabel-banding tbody tr:last-child td { border-bottom: none; }
/* ---------- 7. Tombol ---------- */
.tombol {
display: inline-block;
padding: 10px 20px;
border: none; border-radius: var(--radius-kecil);
background-color: var(--warna-utama); color: var(--warna-utama-kontras);
font: inherit; font-size: 15px; font-weight: 600;
text-decoration: none; cursor: pointer;
transition: background-color var(--durasi) var(--pelunakan), transform var(--durasi) var(--pelunakan);
}
.tombol:hover { background-color: var(--warna-utama-pekat); }
.tombol:active { transform: translateY(1px); }
.tombol--garis {
border: 1px solid var(--warna-utama);
background-color: transparent;
color: var(--warna-utama);
}
.tombol--garis:hover { background-color: var(--warna-utama-lembut); }
/* ---------- 8. Saklar tagihan ---------- */
.saklar { position: relative; display: inline-flex; cursor: pointer; }
.saklar input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.saklar-lintasan { display: block; width: 46px; height: 26px; border-radius: var(--radius-penuh); background-color: var(--warna-lintasan); transition: background-color var(--durasi) var(--pelunakan); }
.saklar-kenop { position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: 50%; background-color: var(--warna-permukaan); box-shadow: 0 1px 3px rgba(15, 23, 42, 0.3); transition: transform var(--durasi) var(--pelunakan); }
.saklar input:checked + .saklar-lintasan { background-color: var(--warna-utama); }
.saklar input:checked + .saklar-lintasan .saklar-kenop { transform: translateX(20px); }
.saklar input:focus-visible + .saklar-lintasan { outline: 2px solid var(--warna-fokus); outline-offset: 2px; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Halaman Harga Layanan — LumbungKas</title>
<link rel="icon" href="assets/logo.svg" type="image/svg+xml">
<link rel="stylesheet" href="css/styles.css">
</head>
<body>
<header class="laman-kepala">
<div class="pembungkus kepala-baris">
<div class="brand">
<img src="assets/logo.svg" alt="Logo LumbungKas" width="36" height="36">
<span class="brand-nama">LumbungKas</span>
</div>
<nav class="nav-kepala" aria-label="Navigasi utama">
<a href="#paket">Paket</a>
<a href="#perbandingan">Perbandingan</a>
</nav>
</div>
</header>
<main>
<div class="pembungkus">
<div class="hero">
<h1 class="judul-halaman">Pilih paket yang pas untuk bisnismu</h1>
<p class="pengantar">Pembukuan awan untuk UMKM: catat penjualan, kirim faktur, dan pantau laporan dari satu tempat. Semua paket bisa dicoba gratis 14 hari.</p>
<div class="pilih-tagihan">
<span class="pilih-label">Bulanan</span>
<label class="saklar">
<input type="checkbox" id="saklar-tagihan" role="switch" aria-checked="false">
<span class="saklar-lintasan" aria-hidden="true"><span class="saklar-kenop"></span></span>
<span class="sr-only">Ganti ke tagihan tahunan</span>
</label>
<span class="pilih-label">Tahunan</span>
<span class="lencana-hemat">Hemat 2 bulan</span>
</div>
</div>
<section class="galeri-harga" id="paket" aria-label="Daftar paket harga">
<article class="kartu-harga">
<h2 class="kartu-nama">Pemula</h2>
<p class="kartu-deskripsi">Untuk usaha yang baru mulai mencatat transaksi.</p>
<p class="kartu-harga-baris">
<span class="kartu-angka" data-harga-bulanan="Rp49.000" data-harga-tahunan="Rp490.000">Rp49.000</span>
<span class="kartu-satuan" data-satuan-bulanan="/bulan" data-satuan-tahunan="/tahun">/bulan</span>
</p>
<ul class="kartu-fitur">
<li>1 pengguna</li>
<li>30 faktur per bulan</li>
<li>Laporan penjualan dasar</li>
<li>Dukungan lewat surel</li>
</ul>
<a class="tombol tombol--garis" href="#">Mulai gratis 14 hari</a>
</article>
<article class="kartu-harga kartu-harga--unggulan">
<span class="kartu-lencana">Terlaris</span>
<h2 class="kartu-nama">Bisnis</h2>
<p class="kartu-deskripsi">Untuk tim penjualan yang butuh laporan lengkap.</p>
<p class="kartu-harga-baris">
<span class="kartu-angka" data-harga-bulanan="Rp149.000" data-harga-tahunan="Rp1.490.000">Rp149.000</span>
<span class="kartu-satuan" data-satuan-bulanan="/bulan" data-satuan-tahunan="/tahun">/bulan</span>
</p>
<ul class="kartu-fitur">
<li>5 pengguna</li>
<li>500 faktur per bulan</li>
<li>Laporan keuangan lengkap</li>
<li>Ekspor data akuntansi</li>
</ul>
<a class="tombol" href="#">Coba paket Bisnis</a>
</article>
<article class="kartu-harga">
<h2 class="kartu-nama">Enterprise</h2>
<p class="kartu-deskripsi">Untuk jaringan cabang dengan kebutuhan khusus.</p>
<p class="kartu-harga-baris">
<span class="kartu-angka kartu-angka--custom">Hubungi kami</span>
</p>
<ul class="kartu-fitur">
<li>Pengguna tanpa batas</li>
<li>Multi gudang dan multi cabang</li>
<li>Integrasi khusus</li>
<li>Dukungan prioritas</li>
</ul>
<a class="tombol tombol--garis" href="#">Jadwalkan demo</a>
</article>
</section>
<section class="seksi-banding" id="perbandingan" aria-labelledby="judul-banding">
<h2 class="section-judul" id="judul-banding">Perbandingan fitur</h2>
<div class="tabel-gulir">
<table class="tabel-banding">
<caption class="sr-only">Perbandingan fitur antar paket LumbungKas</caption>
<thead>
<tr><th scope="col">Fitur</th><th scope="col">Pemula</th><th scope="col">Bisnis</th><th scope="col">Enterprise</th></tr>
</thead>
<tbody>
<tr><th scope="row">Pengguna</th><td>1</td><td>5</td><td>Tanpa batas</td></tr>
<tr><th scope="row">Faktur per bulan</th><td>30</td><td>500</td><td>Tanpa batas</td></tr>
<tr><th scope="row">Laporan keuangan</th><td>Dasar</td><td>Lengkap</td><td>Lengkap</td></tr>
<tr><th scope="row">Multi gudang</th><td>—</td><td>2 lokasi</td><td>Tanpa batas</td></tr>
<tr><th scope="row">Ekspor data akuntansi</th><td>—</td><td>✓</td><td>✓</td></tr>
<tr><th scope="row">Dukungan prioritas</th><td>—</td><td>✓</td><td>✓</td></tr>
</tbody>
</table>
</div>
</section>
</div>
</main>
<footer class="laman-kaki">
<div class="pembungkus kaki-baris">
<span>LumbungKas — proyek latihan CSS</span>
<span>Harga dalam Rupiah dan belum termasuk pajak</span>
</div>
</footer>
</body>
</html>Ringkasan #
Tombol kini punya dua varian dengan state hover, active, dan focus yang lengkap; saklar tagihan tampil sebagai saklar sungguhan yang tetap dibangun di atas checkbox asli, lengkap dengan ring fokus dan label tersembunyi untuk pembaca layar. Tinggal satu kekurangan: menggeser saklar belum menukar harga apa pun. Bagian 5 menutup proyek dengan JavaScript penggeraknya dan penyempurnaan responsif.