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:

css
.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:

css
.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:

css
.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:

css
.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.

css
/* ============================================================
   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; }
html
<!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.