Navigation bar adalah komponen pertama yang dilihat dan terakhir yang dilepas pengunjung: ia menempel di tepi atas saat halaman digulir, dan ia yang harus berubah bentuk ketika layar menyempit. Pada bagian ini kita memasang .navigasi memakai position: sticky dengan latar semi transparan dan backdrop-filter: blur(), lalu menambahkan hamburger yang membuka menu tanpa satu baris JavaScript — pola checkbox memakai :checked dan kombinator sibling. Media query yang sama juga menyatukan seluruh perubahan breakpoint halaman: hero menjadi satu kolom, keunggulan menumpuk, dan grid menu runtuh menjadi satu kolom.
Tujuan Bagian dan Prasyarat #
Target bagian ini:
- Navigation sticky dengan
z-index: 20, latarrgb(255 251 235 / 90%), blur 8px, dan tinggi baris 64px. - Menu horizontal berjarak antartautan 24px dengan gaya
:hoverdan:focus-visible. - Hamburger
.tombol-menuyang tersembunyi di desktop dan tampil di bawah breakpoint 899px. - Panel menu mobile yang terbuka lewat
.menu-toggle:checked ~ .navigasi-menu.
Konsep pendukungnya: Sticky Positioning dan Z-Index untuk header, Flex Container dan Items untuk menu, Checked dan Disabled untuk pola checkbox, Focus dan Focus Visible untuk aksesibilitas, serta Media Queries dan Breakpoints .
Menempelkan Navigation Bar #
Blok berikut ditambahkan di bawah blok Bagian 2 pada styles/landing.css:
.navigasi {
position: sticky;
top: 0;
z-index: 20;
background-color: rgb(255 251 235 / 90%);
backdrop-filter: blur(8px);
border-bottom: 1px solid var(--warna-garis);
}
.navigasi-isi {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--spasi-6);
height: 64px;
}
.logo {
font-size: var(--teks-lg);
font-weight: 700;
color: var(--warna-teks);
text-decoration: none;
}
.navigasi-menu {
display: flex;
gap: var(--spasi-6);
list-style: none;
}
.navigasi-tautan {
color: var(--warna-teks-lembut);
font-weight: 500;
text-decoration: none;
}
.navigasi-tautan:hover {
color: var(--warna-primer);
}
.navigasi-tautan:focus-visible {
outline: 2px solid var(--warna-primer);
outline-offset: 2px;
}Markup header diletakkan sebelum main. Perhatikan urutan tiga elemen tengah: checkbox, label, lalu menu — urutan inilah yang membuat kombinator sibling bekerja:
<header class="navigasi">
<div class="wadah navigasi-isi">
<a class="logo" href="#beranda">Kopi Senja</a>
<input class="menu-toggle" type="checkbox" id="menu-toggle" aria-label="Buka menu navigasi">
<label class="tombol-menu" for="menu-toggle">Menu</label>
<nav>
<ul class="navigasi-menu">
<li><a class="navigasi-tautan" href="#beranda">Beranda</a></li>
<li><a class="navigasi-tautan" href="#menu">Menu</a></li>
<li><a class="navigasi-tautan" href="#cerita">Cerita</a></li>
<li><a class="navigasi-tautan" href="#kontak">Kontak</a></li>
</ul>
</nav>
</div>
</header>Hasil di Browser:
Navigation menempel di atas (sticky, top 0px, z-index 20) dengan
latar rgba(255, 251, 235, 0.9) dan blur 8px. Baris navigasi
setinggi 64px dengan ruas logo dan menu terpisah lebar.
Menu horizontal berjarak antartautan 24px, dan tombol hamburger
bernilai display none di desktop.Hamburger Tanpa JavaScript #
Dua aturan dan satu media query menyelesaikan perilaku mobile. Checkbox disembunyikan secara visual tetapi tetap bisa di-fokus; label bertindak sebagai tombol yang menerima klik:
.menu-toggle {
position: absolute;
width: 1px;
height: 1px;
opacity: 0;
}
.tombol-menu {
display: none;
padding: var(--spasi-2) var(--spasi-4);
border: 1px solid var(--warna-garis);
border-radius: var(--radius-sedang);
background-color: var(--warna-permukaan);
font-size: 14px;
font-weight: 500;
cursor: pointer;
}
.menu-toggle:focus-visible + .tombol-menu {
outline: 2px solid var(--warna-primer);
outline-offset: 2px;
}
@media (max-width: 899px) {
.hero {
flex-direction: column;
align-items: flex-start;
}
.hero-gambar {
width: 100%;
}
.keunggulan {
flex-direction: column;
}
.grid-menu {
grid-template-columns: 1fr;
}
.tombol-menu {
display: inline-flex;
}
.navigasi-menu {
display: none;
position: absolute;
top: 64px;
left: 0;
right: 0;
flex-direction: column;
gap: var(--spasi-1);
padding: var(--spasi-4) var(--spasi-6);
background-color: var(--warna-permukaan);
border-bottom: 1px solid var(--warna-garis);
}
.menu-toggle:checked ~ .navigasi-menu {
display: flex;
}
}Bedah Aturan Kunci #
.navigasi(sticky):position: stickydengantop: 0menempelkan header di tepi atas viewport saat digulir; header tetap menempati alur dokumen.z-index: 20menjaganya berada di atas panel menu mobile yang diposisikan absolute.- Latar semi transparan + blur:
rgb(255 251 235 / 90%)dihitung browser menjadirgba(255, 251, 235, 0.9);backdrop-filter: blur(8px)mengaburkan konten yang terlihat menembusnya. .menu-toggle: pola visually hidden — ukuran 1px danopacity: 0membuat checkbox tidak terlihat, tetapi elemen tetap menerima fokus keyboard dan terbaca screen reader. Berbeda dengandisplay: noneyang mengeluarkannya dari aksesibilitas..menu-toggle:checked ~ .navigasi-menu: kombinator general sibling (~) memilih menu yang berada setelah checkbox saat checkbox bertanda checked. Satu ketukan pada label mengubah properti checked, dan browser menampilkan panel — tanpa JavaScript..menu-toggle:focus-visible + .tombol-menu: karena checkbox tak terlihat, cincin fokusnya dipindahkan ke label hamburger lewat kombinator adjacent sibling (+) agar pengguna keyboard tetap melihat posisi fokus.- Satu media query untuk semua: seluruh perubahan breakpoint 899px ditumpuk dalam satu blok
@media— menu, hero, keunggulan, dan grid. Ketika breakpoint berubah, kita hanya menyunting satu tempat.
Uji Bagian Ini #
Halaman uji bagian ini tersedia di /tests/css/proyek/landing-page-responsif/responsive-navigation.html
, dengan spesifikasi lengkap pada tests/responsive-navigation.spec.js. Asersi yang diverifikasi:
| Elemen | Properti | Diharapkan |
|---|---|---|
.navigasi | position | sticky |
.navigasi | top | 0px |
.navigasi | z-index | 20 |
.navigasi | backdrop-filter | blur(8px) |
.navigasi | background-color | rgba(255, 251, 235, 0.9) |
.navigasi-isi | height | 64px |
.navigasi-isi | justify-content | space-between |
.navigasi-menu | gap | 24px |
.menu-toggle | opacity | 0 |
.tombol-menu | display | none |
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
styles/landing.css
Unduh berkas/* =========================================================
Proyek: Landing Page Responsif — styles/landing.css
File utuh proyek yang berkembang mengikuti empat bagian:
Bagian 1 (Visual Foundation), Bagian 2 (Flexbox dan Grid),
Bagian 3 (Responsive Navigation), Bagian 4 (Animations dan
Polish). Komentar "Bagian N" menandai kelompok aturan yang
dibahas pada setiap bagian.
========================================================= */
/* Bagian 1: Visual Foundation ----------------------------- */
:root {
/* Warna semantik — brand kedai Kopi Senja */
--warna-primer: #c2410c;
--warna-primer-tua: #9a3412;
--warna-latar: #fffbeb;
--warna-permukaan: #ffffff;
--warna-teks: #292524;
--warna-teks-lembut: #57534e;
--warna-teks-balik: #ffffff;
--warna-garis: #e7e5e4;
/* Skala spasi */
--spasi-1: 4px;
--spasi-2: 8px;
--spasi-3: 12px;
--spasi-4: 16px;
--spasi-6: 24px;
--spasi-8: 32px;
--spasi-12: 48px;
--spasi-16: 64px;
/* Bentuk */
--radius-sedang: 12px;
--radius-besar: 16px;
--radius-penuh: 999px;
/* Tipografi */
--font-utama: system-ui, sans-serif;
--teks-dasar: 16px;
--teks-lg: 20px;
}
* {
margin: 0;
box-sizing: border-box;
}
body {
font-family: var(--font-utama);
font-size: var(--teks-dasar);
line-height: 1.6;
color: var(--warna-teks);
background-color: var(--warna-latar);
}
.wadah {
max-width: 1120px;
margin: 0 auto;
padding: 0 var(--spasi-6);
}
.tombol {
display: inline-block;
padding: var(--spasi-3) var(--spasi-4);
border-radius: var(--radius-sedang);
font-size: var(--teks-dasar);
font-weight: 500;
text-decoration: none;
/* Bagian 4: menambah baris transition di bawah ini */
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.tombol-primer {
background-color: var(--warna-primer);
color: var(--warna-teks-balik);
}
.tombol-kedua {
background-color: var(--warna-permukaan);
color: var(--warna-primer);
border: 1px solid var(--warna-primer);
}
.badge {
display: inline-block;
padding: var(--spasi-1) var(--spasi-3);
border-radius: var(--radius-penuh);
background-color: rgb(194 65 12 / 10%);
color: var(--warna-primer-tua);
font-size: 14px;
font-weight: 600;
/* Bagian 4: menambah baris animation di bawah ini */
animation: denyut 2s ease-in-out infinite;
}
.judul-bagian {
font-size: 28px;
font-weight: 700;
}
.deskripsi-bagian {
margin-top: var(--spasi-2);
max-width: 560px;
color: var(--warna-teks-lembut);
}
/* Bagian 2: Flexbox dan Grid ------------------------------ */
.hero {
display: flex;
align-items: center;
gap: var(--spasi-12);
padding: var(--spasi-16) 0;
}
.hero-teks {
flex: 1 1 55%;
}
.hero-gambar {
flex: 1 1 45%;
display: flex;
}
.gambar-hero {
width: 100%;
aspect-ratio: 4 / 3;
border-radius: var(--radius-besar);
object-fit: cover;
}
.judul-hero {
font-size: clamp(32px, 16px + 3vw, 52px);
line-height: 1.15;
}
.teks-aksen {
color: var(--warna-primer);
}
.deskripsi-hero {
margin-top: var(--spasi-4);
font-size: 18px;
color: var(--warna-teks-lembut);
}
.hero-aksi {
display: flex;
gap: var(--spasi-4);
margin-top: var(--spasi-6);
}
.keunggulan {
display: flex;
gap: var(--spasi-6);
}
.keunggulan-item {
flex: 1;
padding: var(--spasi-6);
background-color: var(--warna-permukaan);
border: 1px solid var(--warna-garis);
border-radius: var(--radius-sedang);
}
.keunggulan-judul {
font-size: 18px;
font-weight: 600;
}
.keunggulan-isi {
margin-top: var(--spasi-2);
font-size: 14px;
color: var(--warna-teks-lembut);
}
.grid-menu {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--spasi-6);
margin-top: var(--spasi-8);
}
.kartu-menu {
display: flex;
flex-direction: column;
background-color: var(--warna-permukaan);
border: 1px solid var(--warna-garis);
border-radius: var(--radius-sedang);
overflow: hidden;
/* Bagian 4: menambah baris transition di bawah ini */
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.gambar-menu {
width: 100%;
aspect-ratio: 3 / 2;
object-fit: cover;
}
.kartu-menu-isi {
display: grid;
gap: var(--spasi-2);
padding: var(--spasi-6);
}
.kartu-menu-nama {
font-size: var(--teks-lg);
font-weight: 600;
}
.kartu-menu-harga {
color: var(--warna-primer);
font-weight: 600;
}
.kartu-menu-deskripsi {
font-size: 14px;
color: var(--warna-teks-lembut);
}
/* Bagian 3: Responsive Navigation ------------------------- */
.navigasi {
position: sticky;
top: 0;
z-index: 20;
background-color: rgb(255 251 235 / 90%);
backdrop-filter: blur(8px);
border-bottom: 1px solid var(--warna-garis);
}
.navigasi-isi {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--spasi-6);
height: 64px;
}
.logo {
font-size: var(--teks-lg);
font-weight: 700;
color: var(--warna-teks);
text-decoration: none;
}
.navigasi-menu {
display: flex;
gap: var(--spasi-6);
list-style: none;
}
.navigasi-tautan {
color: var(--warna-teks-lembut);
font-weight: 500;
text-decoration: none;
}
.navigasi-tautan:hover {
color: var(--warna-primer);
}
.navigasi-tautan:focus-visible {
outline: 2px solid var(--warna-primer);
outline-offset: 2px;
}
/* Checkbox hamburger disembunyikan secara visual, tetap
bisa di-fokus dan dibaca screen reader */
.menu-toggle {
position: absolute;
width: 1px;
height: 1px;
opacity: 0;
}
.tombol-menu {
display: none;
padding: var(--spasi-2) var(--spasi-4);
border: 1px solid var(--warna-garis);
border-radius: var(--radius-sedang);
background-color: var(--warna-permukaan);
font-size: 14px;
font-weight: 500;
cursor: pointer;
}
/* Fokus keyboard dari checkbox yang tersembunyi ditunjukkan
pada label hamburger di sebelahnya */
.menu-toggle:focus-visible + .tombol-menu {
outline: 2px solid var(--warna-primer);
outline-offset: 2px;
}
@media (max-width: 899px) {
.hero {
flex-direction: column;
align-items: flex-start;
}
.hero-gambar {
width: 100%;
}
.keunggulan {
flex-direction: column;
}
.grid-menu {
grid-template-columns: 1fr;
}
.tombol-menu {
display: inline-flex;
}
.navigasi-menu {
display: none;
position: absolute;
top: 64px;
left: 0;
right: 0;
flex-direction: column;
gap: var(--spasi-1);
padding: var(--spasi-4) var(--spasi-6);
background-color: var(--warna-permukaan);
border-bottom: 1px solid var(--warna-garis);
}
/* Panel menu terbuka tanpa JavaScript memakai :checked */
.menu-toggle:checked ~ .navigasi-menu {
display: flex;
}
}
/* Bagian 4: Animations dan Polish ------------------------- */
@keyframes denyut {
0%, 100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.06);
opacity: 0.85;
}
}
.tombol-primer:hover {
transform: translateY(-2px);
box-shadow: 0 8px 16px rgb(154 52 18 / 25%);
}
.tombol-kedua:hover {
transform: translateY(-2px);
background-color: rgb(194 65 12 / 8%);
}
.kartu-menu:hover {
transform: translateY(-4px);
box-shadow: 0 12px 24px rgb(41 37 36 / 12%);
}
.pita-cta {
margin-top: var(--spasi-16);
padding: var(--spasi-12) var(--spasi-8);
background-color: var(--warna-primer);
color: var(--warna-teks-balik);
text-align: center;
border-radius: var(--radius-besar);
box-shadow: 0 12px 24px rgb(154 52 18 / 25%);
}
.pita-cta-judul {
font-size: 24px;
font-weight: 700;
}
.pita-cta-isi {
margin-top: var(--spasi-2);
}
.kaki {
display: flex;
justify-content: space-between;
gap: var(--spasi-4);
margin-top: var(--spasi-16);
padding: var(--spasi-8) 0;
border-top: 1px solid var(--warna-garis);
font-size: 14px;
color: var(--warna-teks-lembut);
}
html {
scroll-behavior: smooth;
}
/* Pengguna yang mengaktifkan reduce motion menerima halaman
tanpa animasi: keyframes dan transition dimatikan */
@media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
}
.badge {
animation: none;
}
.tombol,
.kartu-menu {
transition: none;
}
}
tests/animations-dan-polish.spec.js
Unduh berkas// ============================================================
// Spesifikasi uji — Proyek: Landing Page Responsif
// Bagian 4: Animations dan Polish
// ============================================================
// Berkas ini merangkum asersi yang diverifikasi oleh harness
// pada halaman uji (viewport 1280x720):
// /tests/css/proyek/landing-page-responsif/animations-dan-polish.html
// Setiap entri memasangkan elemen probe dengan properti CSS
// dan nilai computed yang diharapkan.
const asersi = [
// Guliran antarbagian bergerak halus lewat scroll-behavior.
{ elemen: "html", properti: "scroll-behavior", diharapkan: "smooth" },
// Tombol bertransisi pada properti transform dan box-shadow.
{ elemen: ".tombol-primer", properti: "transition-property", diharapkan: "transform, box-shadow" },
{ elemen: ".tombol-primer", properti: "transition-duration", diharapkan: "0.2s, 0.2s" },
// Kartu menu bertransisi dengan nilai yang sama seperti tombol.
{ elemen: ".kartu-menu", properti: "transition-property", diharapkan: "transform, box-shadow" },
{ elemen: ".kartu-menu", properti: "transition-duration", diharapkan: "0.2s, 0.2s" },
// Badge berdenyut: keyframes denyut, 2 detik, tanpa henti.
{ elemen: ".badge", properti: "animation-name", diharapkan: "denyut" },
{ elemen: ".badge", properti: "animation-duration", diharapkan: "2s" },
{ elemen: ".badge", properti: "animation-timing-function", diharapkan: "ease-in-out" },
{ elemen: ".badge", properti: "animation-iteration-count", diharapkan: "infinite" },
// Pita CTA berlatar primer dengan bayangan kehangatan primer-tua.
{ elemen: ".pita-cta", properti: "background-color", diharapkan: "rgb(194, 65, 12)" },
{ elemen: ".pita-cta", properti: "color", diharapkan: "rgb(255, 255, 255)" },
{ elemen: ".pita-cta", properti: "border-radius", diharapkan: "16px" },
{ elemen: ".pita-cta", properti: "text-align", diharapkan: "center" },
{ elemen: ".pita-cta", properti: "box-shadow", diharapkan: "rgba(154, 52, 18, 0.25) 0px 12px 24px 0px" },
// Judul pita CTA 24px dengan bobot 700.
{ elemen: ".pita-cta-judul", properti: "font-size", diharapkan: "24px" },
{ elemen: ".pita-cta-judul", properti: "font-weight", diharapkan: "700" },
// Footer dua sisi: flex dengan ruas terpisah dan garis atas.
{ elemen: ".kaki", properti: "display", diharapkan: "flex" },
{ elemen: ".kaki", properti: "justify-content", diharapkan: "space-between" },
{ elemen: ".kaki", properti: "border-top-width", diharapkan: "1px" },
];
tests/flexbox-dan-grid.spec.js
Unduh berkas// ============================================================
// Spesifikasi uji — Proyek: Landing Page Responsif
// Bagian 2: Flexbox dan Grid
// ============================================================
// Berkas ini merangkum asersi yang diverifikasi oleh harness
// pada halaman uji (viewport 1280x720):
// /tests/css/proyek/landing-page-responsif/flexbox-dan-grid.html
// Setiap entri memasangkan elemen probe dengan properti CSS
// dan nilai computed yang diharapkan.
const asersi = [
// Hero adalah flex container dengan item terpusat vertikal.
{ elemen: ".hero", properti: "display", diharapkan: "flex" },
{ elemen: ".hero", properti: "align-items", diharapkan: "center" },
{ elemen: ".hero", properti: "gap", diharapkan: "48px" },
// Teks hero: basis 55% yang menyusut menjadi 563.2px akibat gap.
{ elemen: ".hero-teks", properti: "flex-grow", diharapkan: "1" },
{ elemen: ".hero-teks", properti: "flex-shrink", diharapkan: "1" },
{ elemen: ".hero-teks", properti: "flex-basis", diharapkan: "55%" },
{ elemen: ".hero-teks", properti: "width", diharapkan: "563.2px" },
// Gambar hero: basis 45%, lebar akhir 460.8px.
{ elemen: ".hero-gambar", properti: "flex-basis", diharapkan: "45%" },
{ elemen: ".hero-gambar", properti: "width", diharapkan: "460.8px" },
// Kotak gambar menjaga rasio 4:3 sehingga tingginya 345.6px.
{ elemen: ".gambar-hero", properti: "aspect-ratio", diharapkan: "4 / 3" },
{ elemen: ".gambar-hero", properti: "height", diharapkan: "345.6px" },
{ elemen: ".gambar-hero", properti: "border-radius", diharapkan: "16px" },
// Judul hero fluid mencapai batas atas clamp 52px pada 1280px.
{ elemen: ".judul-hero", properti: "font-size", diharapkan: "52px" },
{ elemen: ".judul-hero", properti: "line-height", diharapkan: "59.8px" },
// Baris tombol aksi adalah flex dengan gap 16px.
{ elemen: ".hero-aksi", properti: "display", diharapkan: "flex" },
{ elemen: ".hero-aksi", properti: "gap", diharapkan: "16px" },
// Item keunggulan memakai flex: 1 = grow 1, shrink 1, basis 0%.
{ elemen: ".keunggulan-item", properti: "flex-grow", diharapkan: "1" },
{ elemen: ".keunggulan-item", properti: "flex-shrink", diharapkan: "1" },
{ elemen: ".keunggulan-item", properti: "flex-basis", diharapkan: "0%" },
// Grid menu tiga kolom sama lebar dengan gap 24px.
{ elemen: ".grid-menu", properti: "display", diharapkan: "grid" },
{ elemen: ".grid-menu", properti: "gap", diharapkan: "24px" },
{ elemen: ".grid-menu", properti: "grid-template-columns", diharapkan: "341.328px 341.328px 341.344px" },
// Kartu menu berlatar permukaan putih dengan radius 12px.
{ elemen: ".kartu-menu", properti: "background-color", diharapkan: "rgb(255, 255, 255)" },
{ elemen: ".kartu-menu", properti: "border-radius", diharapkan: "12px" },
{ elemen: ".kartu-menu", properti: "display", diharapkan: "flex" },
];
tests/responsive-navigation.spec.js
Unduh berkas// ============================================================
// Spesifikasi uji — Proyek: Landing Page Responsif
// Bagian 3: Responsive Navigation
// ============================================================
// Berkas ini merangkum asersi yang diverifikasi oleh harness
// pada halaman uji (viewport 1280x720):
// /tests/css/proyek/landing-page-responsif/responsive-navigation.html
// Setiap entri memasangkan elemen probe dengan properti CSS
// dan nilai computed yang diharapkan.
const asersi = [
// Navigation menempel di atas: sticky dengan jarak 0 dari tepi.
{ elemen: ".navigasi", properti: "position", diharapkan: "sticky" },
{ elemen: ".navigasi", properti: "top", diharapkan: "0px" },
{ elemen: ".navigasi", properti: "z-index", diharapkan: "20" },
// Latar krem semi transparan 90% dengan efek blur di belakangnya.
{ elemen: ".navigasi", properti: "background-color", diharapkan: "rgba(255, 251, 235, 0.9)" },
{ elemen: ".navigasi", properti: "backdrop-filter", diharapkan: "blur(8px)" },
// Baris navigasi setinggi 64px dengan ruas logo dan menu terpisah.
{ elemen: ".navigasi-isi", properti: "height", diharapkan: "64px" },
{ elemen: ".navigasi-isi", properti: "justify-content", diharapkan: "space-between" },
{ elemen: ".navigasi-isi", properti: "gap", diharapkan: "24px" },
{ elemen: ".navigasi-isi", properti: "display", diharapkan: "flex" },
// Logo memakai ukuran 20px dengan bobot 700.
{ elemen: ".logo", properti: "font-size", diharapkan: "20px" },
{ elemen: ".logo", properti: "font-weight", diharapkan: "700" },
// Menu tersusun horizontal dengan jarak antartautan 24px.
{ elemen: ".navigasi-menu", properti: "display", diharapkan: "flex" },
{ elemen: ".navigasi-menu", properti: "gap", diharapkan: "24px" },
// Tautan memakai warna teks lembut tanpa garis bawah.
{ elemen: ".navigasi-tautan", properti: "color", diharapkan: "rgb(87, 83, 78)" },
{ elemen: ".navigasi-tautan", properti: "font-weight", diharapkan: "500" },
{ elemen: ".navigasi-tautan", properti: "text-decoration-line", diharapkan: "none" },
// Checkbox hamburger disembunyikan secara visual.
{ elemen: ".menu-toggle", properti: "position", diharapkan: "absolute" },
{ elemen: ".menu-toggle", properti: "opacity", diharapkan: "0" },
{ elemen: ".menu-toggle", properti: "width", diharapkan: "1px" },
// Tombol hamburger hanya tampil pada breakpoint 899px ke bawah.
{ elemen: ".tombol-menu", properti: "display", diharapkan: "none" },
];
tests/visual-foundation.spec.js
Unduh berkas// ============================================================
// Spesifikasi uji — Proyek: Landing Page Responsif
// Bagian 1: Visual Foundation
// ============================================================
// Berkas ini merangkum asersi yang diverifikasi oleh harness
// pada halaman uji (viewport 1280x720):
// /tests/css/proyek/landing-page-responsif/visual-foundation.html
// Setiap entri memasangkan elemen probe dengan properti CSS
// dan nilai computed yang diharapkan.
const asersi = [
// body mengonsumsi token: latar krem hangat dan teks stone-800.
{ elemen: "body", properti: "font-size", diharapkan: "16px" },
{ elemen: "body", properti: "line-height", diharapkan: "25.6px" },
{ elemen: "body", properti: "color", diharapkan: "rgb(41, 37, 36)" },
{ elemen: "body", properti: "background-color", diharapkan: "rgb(255, 251, 235)" },
// Wadah konten dibatasi 1120px dan terpusat di viewport 1280px.
{ elemen: ".wadah", properti: "max-width", diharapkan: "1120px" },
{ elemen: ".wadah", properti: "margin-left", diharapkan: "80px" },
// Judul bagian memakai ukuran 28px dengan bobot 700.
{ elemen: ".judul-bagian", properti: "font-size", diharapkan: "28px" },
{ elemen: ".judul-bagian", properti: "font-weight", diharapkan: "700" },
// Deskripsi bagian memakai warna teks lembut dan lebar terbatas.
{ elemen: ".deskripsi-bagian", properti: "color", diharapkan: "rgb(87, 83, 78)" },
{ elemen: ".deskripsi-bagian", properti: "max-width", diharapkan: "560px" },
// Tombol primer: latar oranye terbakar, teks putih, padding dari token.
{ elemen: ".tombol-primer", properti: "background-color", diharapkan: "rgb(194, 65, 12)" },
{ elemen: ".tombol-primer", properti: "color", diharapkan: "rgb(255, 255, 255)" },
{ elemen: ".tombol-primer", properti: "padding-top", diharapkan: "12px" },
{ elemen: ".tombol-primer", properti: "padding-left", diharapkan: "16px" },
{ elemen: ".tombol-primer", properti: "border-radius", diharapkan: "12px" },
// Tombol kedua: permukaan putih dengan teks dan border primer.
{ elemen: ".tombol-kedua", properti: "background-color", diharapkan: "rgb(255, 255, 255)" },
{ elemen: ".tombol-kedua", properti: "color", diharapkan: "rgb(194, 65, 12)" },
{ elemen: ".tombol-kedua", properti: "border-top-color", diharapkan: "rgb(194, 65, 12)" },
// Badge memakai warna primer dengan alpha 10% dan radius penuh.
{ elemen: ".badge", properti: "background-color", diharapkan: "rgba(194, 65, 12, 0.1)" },
{ elemen: ".badge", properti: "color", diharapkan: "rgb(154, 52, 18)" },
{ elemen: ".badge", properti: "border-radius", diharapkan: "999px" },
{ elemen: ".badge", properti: "font-size", diharapkan: "14px" },
];