Kenapa ini penting
Dua website dengan struktur HTML identik bisa terasa seperti dua merek yang sangat berbeda hanya karena warna, huruf, dan detail kecil seperti efek saat kursor diarahkan. Modul ini tentang "kepribadian" visual: memilih warna dengan format yang tepat, memasang font dari Google Fonts tanpa memperlambat halaman, mengatur latar dan border, serta memberi umpan balik interaksi lewat pseudo-class dan pseudo-element. Detail inilah yang membuat pengguna merasa sebuah antarmuka "hidup" dan bisa dipercaya.
Konsep inti
Warna
| Format | Contoh | Catatan |
|---|---|---|
| Nama | tomato |
Praktis untuk eksperimen, terbatas |
| Hex | #2563eb, #2563eb80 (dengan alpha) |
Paling umum di file desain |
rgb() |
rgb(37 99 235 / 0.5) |
Sintaks modern dipisah spasi, alpha setelah / |
hsl() |
hsl(221 83% 53%) |
Hue (0 sampai 360 derajat), saturation, lightness; mudah membuat variasi terang-gelap |
oklch() |
oklch(0.55 0.2 260) |
Ruang warna modern yang kecerahannya lebih konsisten di mata manusia |
Tips praktis: dengan hsl, kamu cukup mengubah angka lightness untuk mendapatkan versi lebih terang atau gelap dari warna yang sama. Kata kunci currentColor mengambil nilai color elemen itu, berguna untuk ikon SVG dan border yang mengikuti warna teks.
Soal aksesibilitas, kontras teks dan latar perlu cukup tinggi. Pedoman WCAG level AA meminta rasio minimal 4.5:1 untuk teks normal. DevTools Chrome menampilkan rasio kontras saat kamu mengklik kotak warna di panel Styles.
Font dan Google Fonts
font-family menerima daftar cadangan (font stack). Browser memakai font pertama yang tersedia:
body { font-family: "Plus Jakarta Sans", system-ui, sans-serif; }
Memasang Google Fonts: buka fonts.google.com, pilih font dan ketebalan yang benar-benar kamu pakai, lalu salin tag <link>. Polanya:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;600;800&display=swap" rel="stylesheet">
preconnectmembuka koneksi lebih awal ke server font.display=swapmembuat teks langsung tampil memakai font cadangan, lalu berganti ke font asli setelah selesai diunduh. Ini mencegah teks tak terlihat selama loading.- Pilih ketebalan seperlunya; setiap ketebalan tambahan menambah ukuran unduhan.
Properti tipografi lain: font-size, font-weight (100 sampai 900), line-height (tulis tanpa satuan, misalnya 1.6, supaya proporsional dengan ukuran font anak), letter-spacing, text-transform, text-align, dan text-decoration.
Background
background-color,background-image: url(...).background-size: cover(penuhi area, boleh terpotong) ataucontain(tampil utuh, boleh ada sisa).background-position: center,background-repeat: no-repeat.- Shorthand:
background: url(hero.jpg) center / cover no-repeat;. - Beberapa lapisan dipisah koma; yang ditulis pertama berada paling atas. Ini trik umum untuk memberi lapisan gelap di atas foto agar teks terbaca.
Border dan sudut
border: 2px solid #e5e7eb; adalah shorthand untuk lebar, gaya (solid, dashed, dotted), dan warna. border-radius membulatkan sudut: 8px untuk kartu, 9999px untuk tombol berbentuk kapsul, 50% untuk lingkaran pada elemen persegi. outline mirip border tetapi tidak memakan ruang di box model, dan dipakai browser untuk indikator fokus.
Pseudo-class
Pseudo-class memilih elemen berdasarkan keadaan atau posisi:
- Interaksi:
:hover(kursor di atas),:active(sedang ditekan),:focus(sedang fokus),:focus-visible(fokus yang perlu ditampilkan, biasanya dari keyboard). - Form:
:checked,:disabled,:required,:valid,:invalid,:placeholder-shown,:user-invalid(baru dianggap invalid setelah pengguna berinteraksi). - Posisi:
:first-child,:last-child,:nth-child(2n)(genap),:nth-child(odd),:not(.aktif). - Relasi:
:has()memilih induk berdasarkan isinya, misalnya.kartu:has(img)memilih kartu yang punya gambar.
Urutan aman untuk link adalah :link, :visited, :hover, :active (singkatan LoVe HAte), karena specificity-nya sama dan yang terakhir menang.
Penting: jangan pernah menghapus outline fokus tanpa pengganti. Pengguna keyboard butuh tahu elemen mana yang sedang aktif. Pakai :focus-visible agar cincin fokus muncul untuk keyboard tetapi tidak mengganggu klik mouse.
Pseudo-element
Pseudo-element membuat "elemen bayangan" yang bisa di-styling tanpa menambah HTML:
::beforedan::aftermenyisipkan konten sebelum atau sesudah isi elemen. Wajib punya properticontent(boleh string kosong"").::placeholderuntuk teks placeholder input.::selectionuntuk teks yang diblok pengguna.::first-letterdan::first-lineuntuk efek tipografi majalah.::markeruntuk bullet atau nomor list.
::before dan ::after tidak berlaku di void element seperti <img> dan <input>, karena elemen itu tidak punya isi.
Contoh kode
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Kartu Promo</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;700&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; }
body {
margin: 0;
font-family: "Plus Jakarta Sans", system-ui, sans-serif;
color: hsl(222 47% 11%);
background: hsl(210 40% 98%);
}
.hero {
min-height: 60vh;
display: grid;
place-items: center;
color: white;
/* Lapisan 1 (atas): gradasi gelap transparan, lapisan 2: foto */
background:
linear-gradient(rgb(0 0 0 / 0.55), rgb(0 0 0 / 0.55)),
url("https://images.unsplash.com/photo-1495474472287-4d71bcdd2085?w=1600") center / cover no-repeat;
}
.kartu {
position: relative; /* jadi patokan untuk ::before */
max-width: 22rem;
margin: -4rem auto 2rem;
padding: 1.5rem;
background: white;
border: 1px solid hsl(214 32% 91%);
border-radius: 12px;
}
/* Label "BARU" tanpa menambah HTML */
.kartu::before {
content: "BARU";
position: absolute;
top: -0.75rem;
right: 1rem;
padding: 0.15rem 0.6rem;
font-size: 0.75rem;
font-weight: 700;
letter-spacing: 0.05em;
color: white;
background: hsl(350 80% 55%);
border-radius: 9999px;
}
.tombol {
display: inline-block;
padding: 0.75em 1.5em;
font: inherit;
font-weight: 700;
color: white;
background: hsl(221 83% 53%);
border: none;
border-radius: 9999px;
text-decoration: none;
cursor: pointer;
}
.tombol:hover { background: hsl(221 83% 45%); } /* sedikit lebih gelap */
.tombol:active { background: hsl(221 83% 38%); }
.tombol:focus-visible {
outline: 3px solid hsl(45 100% 50%);
outline-offset: 3px;
}
li:nth-child(odd) { background: hsl(210 40% 96%); }
::selection { background: hsl(45 100% 70%); }
</style>
</head>
<body>
<section class="hero"><h1>Kopi Senja</h1></section>
<article class="kartu">
<h2>Es Kopi Pandan</h2>
<ul>
<li>Gula aren asli</li>
<li>Santan segar</li>
<li>Daun pandan wangi</li>
</ul>
<a class="tombol" href="#pesan">Pesan sekarang</a>
</article>
</body>
</html>
<!-- → Hero foto dengan lapisan gelap, kartu putih bertumpuk di bawahnya dengan label "BARU" merah.
Arahkan kursor ke tombol → warnanya menggelap. Tekan Tab → muncul cincin fokus kuning. -->
Kesalahan umum
outline: nonetanpa pengganti. Pengguna keyboard kehilangan jejak. Cara benar: ganti dengan gaya:focus-visibleyang jelas.- Lupa
contentpada::beforeatau::after. Pseudo-element tidak akan muncul sama sekali. Cara benar: selalu tuliscontent: ""minimal. - Memuat terlalu banyak ketebalan font (100 sampai 900 semuanya). Cara benar: pilih 2 sampai 3 ketebalan yang benar-benar dipakai, sertakan
display=swap. - Teks di atas foto tidak terbaca. Cara benar: tambahkan lapisan gradasi gelap atau terang di atas foto, lalu cek kontras.
- Menulis
line-height: 24pxdibody. Heading besar jadi berimpitan karena mewarisi angka tetap. Cara benar: pakai angka tanpa satuan seperti1.5.
Latihan
- Mudah, Pasang font "Poppins" (400 dan 600) dari Google Fonts, terapkan ke
body, dan beri warna tekshsl(220 20% 20%). - Sedang, Buat tombol dengan tiga keadaan berbeda (
:hover,:active,:focus-visible) dan versi:disabledyang tampak pudar serta kursornyanot-allowed. - Menantang, Tanpa menambah HTML, buat judul
h2.garisyang punya garis aksen 60px di bawahnya memakai::after, dan buat link eksternal (a[href^="http"]) otomatis diberi tanda panah "↗" setelah teksnya.
Lihat solusi
<!-- Soal 1 -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">
<style>
body { font-family: "Poppins", system-ui, sans-serif; color: hsl(220 20% 20%); }
</style>
/* Soal 2 */
.btn {
padding: 0.7em 1.4em;
font: inherit;
color: white;
background: hsl(160 70% 35%);
border: none;
border-radius: 8px;
cursor: pointer;
}
.btn:hover { background: hsl(160 70% 30%); }
.btn:active { background: hsl(160 70% 25%); }
.btn:focus-visible { outline: 3px solid hsl(200 100% 50%); outline-offset: 2px; }
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* :disabled ditulis terakhir supaya menang atas :hover saat seri specificity */
/* Soal 3 */
h2.garis { position: relative; padding-bottom: 0.5rem; }
h2.garis::after {
content: "";
position: absolute;
left: 0;
bottom: 0;
width: 60px;
height: 4px;
background: hsl(350 80% 55%);
border-radius: 2px;
}
a[href^="http"]::after {
content: " ↗";
font-size: 0.85em;
}
/* → <a href="https://google.com">Google</a> tampil sebagai "Google ↗" */
Ringkasan
- Gunakan
hsl()atauoklch()untuk palet yang mudah divariasikan; pastikan kontras teks cukup. - Google Fonts:
preconnect, ketebalan seperlunya, dandisplay=swap. - Background bisa berlapis; gradasi di atas foto membuat teks tetap terbaca.
- Pseudo-class menargetkan keadaan (
:hover,:focus-visible,:checked,:has()); jangan hapus indikator fokus. ::beforedan::afterbutuhcontentdan cocok untuk dekorasi tanpa menambah HTML.