Pengenalan CSS
Kenali CSS sebagai lapisan desain di atas HTML.
Pengenalan CSS
- 01Pahami konsepnya · 3
- 02Coba contoh kode · 1
- 03Latihan singkat
Kenali CSS sebagai lapisan desain di atas HTML.
CSS (Cascading Style Sheets) adalah bahasa lembar gaya untuk mendandani halaman web. Jika HTML membangun rangka, CSS mengecatnya: warna, huruf, jarak, tata letak, hingga animasi — semuanya wilayah CSS. Satu berkas CSS bisa mendandani ratusan halaman sekaligus, sehingga mengganti nuansa situs seluruhnya cukup mengubah satu tempat.
CSS bekerja dengan memilih lalu mengatur: sebuah aturan terdiri dari selector (elemen apa yang dituju) dan deklarasi (properti: nilai apa yang dipasang). Target pemilihannya adalah elemen HTML itu sendiri, atau penanda yang kita pasang — class dan id yang dipelajari di kursus HTML menjadi jembatan utamanya.
Kemampuannya nyaris tak berbatas: mengganti font dan ukurannya, memberi warna serta gambar latar, mengatur jarak dalam-luar elemen, mempercantik tautan dan tabel, sampai menyesuaikan tampilan terhadap ukuran layar (responsive). Kursus ini menulusuri semuanya selangkah demi selangkah.
Satu aturan utuh: selector h1 menunjuk semua heading level satu, lalu dua deklarasi memasang warna teal dan perataan tengah. Sintaksnya selalu ini — selector, kurung kurawal, properti: nilai; — diulang sepanjang karier CSS-mu.
Tulis aturan CSS yang mewarnai semua paragraf abu-abu dan menengahkan semua heading h2.
h1 {
color: teal;
text-align: center;
}Inline, internal, dan external — beserta alasan memilihnya.
CSS bisa masuk ke halaman lewat tiga pintu. Pertama, inline style: deklarasi diselipkan langsung pada atribut style elemen — cepat untuk uji sekali pakai, tapi menyulitkan saat aturan menumpuk karena tersebar di mana-mana.
Kedua, internal style: seluruh aturan dikumpulkan dalam tag <style> di bagian head halaman. Rapi untuk satu halaman tunggal — latihan kecil, email, prototipe — tetapi tidak terbagi ke halaman lain. Ketiga, external style: aturan hidup di berkas sendiri bernama .css lalu dihubungkan lewat <link rel="stylesheet" href="style.css"> di head.
Cara ketiganyalah standar proyek nyata: berkas CSS terpisah bisa dipakai ratusan halaman, di-cache browser agar loading lebih cepat, dan dikerjakan terpisah dari isi HTML. Lokasi berkasnya mengikuti aturan yang sama seperti gambar dan tautan: sefolder langsung nama berkas, dalam subfolder folder/nama.css, atau naik satu tingkat ../nama.css.
Ketiganya sah dan dipakai di saat berbeda: inline untuk eksperimen sepintas, internal untuk halaman tunggal, external untuk proyek. Saat ketiganya menimpa properti yang sama, yang paling dekat dengan elemen (inline) menang — itu makna "cascading" yang dibahas pelajaran selektor.
Uji koneksi kedua berkas dengan aturan mencolok seperti latar biru di atas — begitu terlihat, seluruh aturan berikutnya cukup ditulis di style.css. Pola dua-berkas ini dipakai semua pelajaran CSS selanjutnya.
Bangun pasangan index.html + style.css, hubungkan dengan link, lalu buktikan koneksi itu dengan mengubah warna latar body.
<!-- 1) inline: pada elemen -->
<h1 style="color: blue;">Judul biru</h1>
<!-- 2) internal: di head -->
<style>
h1 { color: green; }
</style>
<!-- 3) external: berkas terpisah -->
<link rel="stylesheet" href="style.css">Pilih px, %, em, rem, atau vw sesuai kebutuhan.
Setiap nilai ukuran di CSS punya satuan, dan satuan yang tepat mengubah perilakunya. Piksel (px) bersifat tetap: 16px selalu 16 piksel layar — mudah ditebak untuk border dan detail kecil. Persen (%) bersifat relatif terhadap induknya: width: 50% berarti separuh lebar wadah, sehingga tata letak ikut menyesuaikan.
Lalu ada keluarga relatif-ke-font. em mengacu pada ukuran font elemen itu sendiri — padding: 2em berarti dua kali font elemen; masalahnya em bersarang menggandakan terus (1.2em di dalam 1.2em = 1.44em). rem (root em) menyelesaikannya: ia selalu mengacu pada font akar dokumen, jadi 1.2rem sama di mana pun berada. Praktik modern: rem untuk font dan jarak, px untuk garis dan bayangan.
Terakhir satuan viewport yang mengikuti jendela browser: vw dan vh masing-masing satu persen lebar dan tinggi layar. height: 100vh membuat section setinggi layar penuh — resep hero section di mana-mana. Ada juga ch (lebar karakter "0") yang pas untuk membatasi jumlah kolom teks, misalnya max-width: 70ch untuk baris yang nyaman dibaca.
Perhatikan pembagian tugasnya: vh/vw untuk panggung besar, rem untuk isi yang harus konsisten, ch untuk lebar bacaan, dan px untuk detail yang memang harus presisi. Mengganti font-size akar (html { font-size: 18px }) otomatis menskalakan semua rem — satu tuas mengatur seluruh tipografi.
Daftar bersarang dengan em membuat tiap level mewarisi lalu menggandakan — butir level tiga bisa dua kali lebih besar dari level satu. Mengalihkan ke rem memutus perberatan karena semuanya menghitung dari akar yang sama.
Bangun hero 100vh dengan judul 2.5rem dan artikel max-width 70ch, lalu ubah font akar ke 18px dan rasakan semuanya ikut menskalakan.
.hero {
height: 100vh; /* setinggi layar */
padding: 5vh 5vw; /* jarak ikut ukuran layar */
}
.artikel {
font-size: 1.1rem; /* konsisten di mana pun */
max-width: 70ch; /* ±70 karakter per baris */
}
.avatar {
width: 64px; /* tetap, tak terpengaruh font */
border: 2px solid #333;
}Hex, rgb, hsl, transparansi, dan currentColor.
CSS mengenal warna lewat beberapa format, dan semuanya saling terjemah. Format hex #ff6b35 menulis campuran merah-hijau-biru dalam heksadesimal — ringkas dan paling umum. Format fungsional rgb(255, 107, 53) menulis nilai yang sama secara lebih terbaca, dan rgba menambahkan alpha keempat untuk transparansi: rgba(255, 107, 53, 0.5) setengah tembus.
Format hsl berpikir seperti pelukis: hue (derajat pada roda warna 0-360), saturation (kejenuhan %), lightness (terang %). hsl(14, 100%, 60%) mudah divariasikan — naikkan lightness untuk versi muda, turunkan untuk bayangan; membuat palet warna konsisten jadi aritmetika sederhana, bukan tebak-tebakan hex.
Dua pemain lain: opacity pada elemen membuat seluruh isinya ikut transparan (teks ikut memudar), sedangkan alpha pada warna hanya memudarkan warnanya itu — inilah alasan overlay rgba lebih aman daripada div ber-opacity. Dan currentColor adalah variabel otomatis: ia menyalin warna teks elemen saat itu, sehingga border: 2px solid currentColor selalu serasi dengan tulisannya.
Pasangan hsl --utama dan --utama-tua memperlihatkan kekuatan format ini: satu roda warna, dua tingkat terang — basis palet tombol. Overlay rgba menggelapkan latar tanpa menyentuh opasitas anak-anaknya; bandingkan dengan opacity: 0.45 pada elemen yang juga memudarkan tulisannya. currentColor membuat ikon berbingkai senada otomatis.
Buat palet tiga tingkat dari satu hue hsl (muda, normal, tua) lalu terapkan pada tombol dengan status hover, plus overlay rgba di atas gambar hero.
:root {
--utama: hsl(14, 100%, 60%);
--utama-tua: hsl(14, 100%, 45%);
}
.tombol {
background: var(--utama);
color: #fff;
}
.tombol:hover { background: var(--utama-tua); }
.overlay {
background: rgba(0, 0, 0, 0.45); /* gelap tanpa memudarkan teks anak */
}
.ikon {
color: teal;
border: 2px solid currentColor; /* selalu senada teks */
}Pilih elemen yang tepat dan pahami aturan yang menang.
Selektor menentukan elemen yang menerima gaya. Kelas dapat dipakai ulang. Bila dua aturan mengatur properti yang sama, kekhususan selektor dan urutan aturan menentukan hasilnya.
Selektor dasar ada tiga: berdasarkan tag (p menimpa semua paragraf), berdasarkan class (.kartu menimpa semua elemen berkelas kartu), dan berdasarkan id (#judul menimpa satu elemen unik). Selektor bisa menggabung dan menumpuk: .kartu p hanya menimpa paragraf di dalam elemen berkelas kartu — makin spesifik, makin kuat.
Cascade menjawab pertanyaan "kalau dua aturan bertabrakan?": yang lebih spesifik menang; bila sama spesifiknya, yang ditulis belakangan menang. Urutan kekuatannya kasar begini — tag < class < id, dan inline style di atribut lebih kuat lagi. Memahami tangga ini menjelaskan hampir semua kejanggalan "kenapa gayaku tidak jalan".
Teks pada .kartu mengikuti warna kartu. Elemen strong di dalamnya memakai warna aksen karena aturan yang lebih khusus.
Buat kelas .note dengan warna latar lembut, lalu terapkan pada satu paragraf.
p { color: #596970; }
.kartu { color: #263744; }
.kartu strong { color: #c7603e; }Kombinator, pseudo-class struktural, dan selektor atribut.
Kombinator menghubungkan dua selektor menjadi hubungan. Spasi (descendant) menimpa semua keturunan: .menu a menyentuh semua tautan di kedalaman berapa pun. Tanda > (child) membatasi pada anak langsung: .menu > li hanya butir tingkat pertama — anak dari sub-daftar lolos. Tanda + (adjacent sibling) menimpa saudara tepat setelahnya: h2 + p mengatur paragraf pertama seusai heading. Tanda ~ (general sibling) menjangkau semua saudara setelahnya.
Pseudo-class struktural memilih berdasarkan posisi: :first-child dan :last-child, :nth-child(2) untuk urutan pasti, :nth-child(odd)/even untuk baris ganjil-genap (sahabat tabel zebra), dan :nth-child(3n) untuk tiap ketiga. Yang seru :not() yang memfilter kebalikannya: li:not(.aktif) menimpa semua butir kecuali yang aktif. Ada juga :focus untuk kondisi fokus input, :checked untuk checkbox terpilih, dan :focus-within yang menyala bila anak-anaknya sedang difokuskan.
Selektor atribut menyeleksi lewat atribut HTML: [type="email"] menimpa semua input email, [href^="https"] semua tautan yang diawali https, dan [data-harga] semua elemen yang punya atribut itu berapa pun nilainya — pintu menuju HTML yang kaya metadata tanpa class tambahan.
Enam baris, enam rasa ketepatan: > menjaga sub-menu tidak ikut tebal, + memberi perlakuan khusus paragraf pembuka, nth-child(even) menulis zebra tanpa class manual, :not() meredupkan menu tak aktif, dan selektor atribut menandai tautan eksternal tanpa menyentuh HTML-nya — halaman terasa "tahu kondisinya sendiri".
Dengan CSS: .detail { display: none; } lalu #saklar:checked ~ .detail { display: block; }. Kombinasi :checked dan ~ (saudara umum) membuat toggle bekerja murni di CSS — bukti bahwa selektor tepat bisa menggantikan skrip kecil.
Buat daftar tugas yang mencoret li yang memuat checkbox :checked (pakai ~ atau struktur label), lalu tandai semua tautan eksternal dengan selektor atribut.
/* kombinator */
.menu > li { font-weight: bold; }
h2 + p { text-indent: 0; }
/* struktural */
tr:nth-child(even) { background: #f2f7f9; }
li:not(.aktif) { opacity: 0.55; }
/* atribut */
input[type="email"] { border-color: teal; }
a[href^="https"]::after { content: " ↗"; }Sisipkan konten dekoratif tanpa menambah HTML.
Pseudo-element membuat "elemen hantu" yang tidak ada di HTML: ::before dan ::after masing-masing menyisipkan kotak anonim di awal dan akhir isi elemen. Keduanya nyaris tak berguna tanpa properti content — itulah nyawa mereka: content: "★" menulis bintang, content: "" menghasilkan kotak kosong yang bisa diberi lebar-tinggi untuk dekorasi murni.
Pemakaian sehari-hari: hiasan tipografis (content: "→" pada tautan "selengkapnya"), pembatas section (hr bergaya ulang lewat ::after), badge angka, hingga efek kutipan besar di blockquote. Karena ::before adalah anak pertama elemen, ia mewarisi gaya induknya dan bisa diposisikan absolute bila induknya relative.
Keluarga lain yang berguna: ::first-line dan ::first-letter mengatur baris pertama dan huruf awal paragraf (drop cap koran), ::placeholder menata teks isian form, ::selection mewarnai blok teks yang di-highlight pengunjung. Catatan gaya penulisan: dua tanda titik dua (::) membedakan pseudo-element dari pseudo-class satu titik dua — keduanya sering tertukar padahal berbeda keluarga.
Empat dekorasi tanpa satu pun HTML baru: panah otomatis menempel di tiap tautan "selengkapnya", kutipan besar menghiasi blockquote, placeholder form berabu lembut, dan blok yang di-highlight pengunjung menyala kuning. Konten dengan escape \201C adalah tanda kutip tipografis " — karakter Unicode bisa ditulis lewat kode heksadesimalnya.
content: "" menghasilkan kotak kosong yang lalu dibentuk: absolute + inset menempelkannya 6px di dalam kartu sebagai bingkai putus-putus. pointer-events: none memastikan dekorasi ini tak menghalangi klik tombol di bawahnya — kebiasaan penting untuk semua hiasan ::before/::after.
Hiasi heading-mu dengan garis aksen ::after selebar 48px, lalu buat drop-cap koran dengan ::first-letter pada paragraf pembuka.
.tautan-selengkapnya::after {
content: " →";
color: #c7603e;
}
blockquote::before {
content: "\201C"; /* tanda kutip besar */
font-size: 3em;
color: #bbb;
float: left;
margin-right: 6px;
}
input::placeholder { color: #9aa5ab; }
p::selection { background: #ffe9a8; }Warnai latar halaman atau jadikan gambar sebagai latar.
Properti background mengatur latar elemen, dan latar yang tepat mengubah kesan halaman seketika. Bentuk paling sederhana: warna. background: teal atau background: #35A9DB mewarnai seluruh bidang elemen — pada body, seluruh halaman; pada sebuah div, hanya kotak itu.
Bentuk kedua: gambar. background: url('pemandangan.jpg') menempelkan berkas gambar sebagai latar. Perilaku bawaannya digandakan (repeat) memenuhi bidang bila gambarnya lebih kecil — kendalikan dengan background-repeat: no-repeat untuk sekali tampil atau repeat-x/repeat-y untuk satu arah. Ukurannya juga bisa dipaksa: background-size: cover memenuhi bidang dengan memotong kelebihan, background-position: center menempatkannya di tengah.
Kombinasi favorit praktik: warna latar diletakkan di bawah gambar sebagai cadangan saat gambar gagal dimuat, dan teks di atasnya diberi warna kontras agar tetap terbaca. Semua properti background bisa juga diringkas satu baris — itu pelajaran setelah ini berkembang.
body mendapat latar biru dengan teks putih kontras. .hero memakai gambar yang diposisikan tengah, disesuaikan cover, tanpa penggandaan — tiga nilai itu dirangkum dalam satu deklarasi background beserta pemisah garis miring untuk ukuran. Selalu siapkan warna cadangan agar halaman tetap layak saat gambarnya tak kunjung tiba.
linear-gradient membuat peralihan warna langsung dari CSS tanpa berkas gambar — arahnya diatur to right/top/bottom, warnanya boleh lebih dari dua. Gradien adalah "gambar" menurut CSS, jadi ia hidup di properti background yang sama.
Beri halamanmu latar warna lembut, lalu buat satu section hero dengan gambar latar mode cover dan teks yang tetap terbaca.
body {
background: #35A9DB;
color: #fff;
}
.hero {
background: url('pemandangan.jpg') center / cover no-repeat;
height: 300px;
}Perataan, kapitalisasi, dekorasi, hingga jarak antar huruf.
Properti teks mengatur perilaku tulisan di luar font-nya sendiri. Perataan: text-align dengan left, right, center, atau justify (rata kedua sisi seperti kolom koran). Kapitalisasi: text-transform memaksa uppercase, lowercase, atau capitalize (huruf awal tiap kata besar) tanpa mengubah teks aslinya.
Dekorasi garis diurus text-decoration: underline, overline, line-through (mencoret), atau none — nilai terakhir ini paling sering dipakai untuk melepas garis bawaan tautan. Jarak-jarak juga properti teks: letter-spacing merenggangkan antar huruf, word-spacing antar kata, line-height mengatur tinggi baris (nilai tanpa satuan seperti 1.7 berarti 1,7 kali ukuran font), dan text-indent menjorokkan baris pertama paragraf.
Satu lagi yang memukau: text-shadow menambah bayangan teks dengan tiga nilai — geser horizontal, geser vertikal, lalu warna (text-shadow: 2px 3px gray). Perhatikan detail penting: warna teks diatur properti color — bukan font-color seperti kadang tertukar — karena color berlaku untuk semua teks.
Tiga kelas tiga suasana: judul mewah dengan kapital dan bayangan, artikel koran dengan justify-indent-baris lapang, dan harga lama tercoret abu-abu. Kombinasi kecil-kecil beginilah yang membedakan halaman datar dan halaman yang tertata.
Tata ulang satu artikel: judul uppercase berbayangan, isi justify dengan line-height 1.8 dan indentasi, lalu coret satu kalimat promosi lamanya.
.judul {
text-align: center;
text-transform: uppercase;
letter-spacing: 3px;
text-shadow: 2px 2px #ccc;
}
.artikel {
text-align: justify;
text-indent: 30px;
line-height: 1.8;
}
.harga-lama {
text-decoration: line-through;
color: gray;
}Jenis, ukuran, ketebalan, gaya, sampai font unduhan sendiri.
Keluarga properti font mengurus wajah tulisan. font-family memilih jenisnya — nilai aman yang tersedia hampir di semua komputer antara lain sans-serif, serif, monospace (courier), dan cursive; nilainya boleh berantai fallback: font-family: "Roboto", sans-serif berarti coba Roboto dulu, jatuh ke sans-serif bila tak ada. font-size mengatur ukuran (16px, 1.2em, 120%), font-weight ketebalannya (normal, bold, atau angka 100-900), dan font-style kemiringan (italic).
Bosan font bawaan? Dua jalan. Pertama: layanan font daring seperti Google Fonts — pilih fontnya, salin satu baris <link> ke head, dan font itu tersedia untuk CSS-mu. Kedua: berkas font unduhan (ttf/woff) didaftarkan lewat @font-face: beri nama pada font-family, tunjuk berkasnya dengan src: url(...), lalu pakai nama itu seperti font biasa.
Rumus tampilan yang enak dibaca biasanya sederhana: ukuran tubuh 16-18px, line-height longgar, dan maksimal dua jenis font per halaman — satu untuk judul, satu untuk isi. Lebih dari itu, halaman berisiko terlihat seperti papan maket.
body memakai rantai fallback: Segoe UI bila ada, tanpa syarat sans-serif sebagai jaring cadangan. Blok @font-face mendaftarkan berkas unduhan dengan nama TulisanKeren sehingga .judul-unik bisa memakainya — nama cipratan tetap berada di posisi fallback. Inilah cara font khas situs-situs besar sampai ke browser pengunjung.
Pasang satu font Google Fonts pilihanmu, terapkan pada judul, dan biarkan isi memakai rantai sans-serif — maksimal dua jenis font dalam satu halaman.
body {
font-family: "Segoe UI", sans-serif;
font-size: 17px;
}
h1 { font-weight: 800; }
blockquote { font-style: italic; }
@font-face {
font-family: "TulisanKeren";
src: url("font/wolf.ttf");
}
.judul-unik {
font-family: "TulisanKeren", cursive;
font-size: 44px;
}Empat status tautan dan mengubahnya menjadi tombol.
Tautan punya empat keadaan yang masing-masing bisa didandani terpisah: a:link keadaan biasa belum dikunjungi, a:visited setelah pernah dikunjungi, a:hover saat kursor melayang di atasnya, dan a:active pada saat sedang diklik. Menata keempatnya membuat tautan terasa hidup — pengunjung mendapat umpan balik tanpa perlu JavaScript.
Perubahan paling umum: pada hover, ganti warna atau beri garis bawah; pada visited, redupkan agar pengunjung tahu sudah pernah ke sana. Urutan penulisannya disarankan link-visited-hover-active agar aturan saling menimpa dengan benar.
Trik favorit semua orang: mengubah tautan menjadi tombol. Resepnya bukan tag baru melainkan CSS pada <a> — background berwarna, padding untuk ruang gerak, text-decoration: none melepas garis bawah, dan hover yang mengganti warna. Ditambah border-radius, hasilnya tombol pill yang halus; dipasang di navbar, jadilah menu yang rapi.
Tiga keadaan diam (link, visited, dan dasar) berbagi gaya dasar tombol; hover dan active masing-masing menggelapkan warna selangkah — urutan terang-sedang-gelap memberi rasa "ditekan". display: inline-block membuat padding tampil penuh pada elemen sebaris seperti a.
Buat tiga tautan bertema beda (netral, peringatan, sukses) sebagai tombol dengan status hover dan active yang jelas.
a.tombol,
a.tombol:link,
a.tombol:visited {
display: inline-block;
padding: 10px 22px;
background: #1ABC9C;
color: #fff;
text-decoration: none;
border-radius: 6px;
}
a.tombol:hover {
background: #148f77;
}
a.tombol:active {
background: #0e6251;
}Bedakan margin di luar dan padding di dalam elemen.
Setiap elemen HTML adalah kotak, dan box model membedahnya menjadi empat lapisan: isi (content), padding di dalam border, border itu sendiri, dan margin di luar border. Padding memberi ruang bernapas antara isi dan tepi elemen; margin mendorong elemen menjauh dari tetangganya — mengatur keduanya adalah 80% pekerjaan tata letak harian.
Keduanya sadar arah. Bentuk panjangnya menyebut sisi satu per satu: margin-top, margin-right, margin-bottom, margin-left — padding pun demikian. Bentuk ringkasnya satu nilai untuk semua sisi (padding: 20px), dua nilai untuk vertikal-horizontal (margin: 10px 24px), atau empat nilai searah jarum jam atas-kanan-bawah-kiri (padding: 8px 20px 6px 12px).
Satu jebakan klasik: menetapkan width lalu menambah padding dan border membuat kotak menjulur melebihi lebar yang ditulis. box-sizing: border-box menyembuhkannya — lebar yang dinyatakan sudah termasuk padding dan border, sehingga ukuran kotak dapat dipercaya. Praktik modern memasang border-box global untuk semua elemen lewat selektor *.
Lebar kartu tetap 280px karena border-box menghitung padding dan border ke dalamnya; margin 16px berada di luar ukuran itu sebagai jarak ke tetangga. Uji pemahaman: ganti padding menjadi 32px dan amati lebar luar kotak tidak berubah.
Margin boleh negatif — elemen menyusup ke wilayah tetangganya, berguna untuk efek tumpang tindih. Trik margin: 0 auto pada elemen berlebar tetap adalah cara klasik menengahkannya di halaman.
Buat dua kartu bersebelahan dengan padding dalam berbeda dan margin luar 24px, buktikan border-box menjaga lebarnya.
* { box-sizing: border-box; }
.kartu {
width: 280px;
padding: 20px;
border: 2px solid #56636a;
margin: 16px;
}Delapan gaya garis, tebal, warna, dan bentuk ringkasnya.
Border menggambar garis tepi elemen dan punya tiga dimensi yang saling bebas: gaya, tebal, dan warna. Gaya ditentukan border-style dan tersedia delapan pilihan — solid (garis penuh), dashed (putus-putus), dotted (titik-titik), double (garis ganda), serta groove, ridge, inset, outset yang memberi kesan timbul-tenggelam tiga dimensi. Tanpa border-style, border tidak muncul sama sekali.
Dimensi lainnya: border-width mengatur ketebalan dalam piksel dan border-color mewarnainya (nama, #hex, atau rgb). Ketiganya bisa dirangkum satu deklarasi: border: 2px dashed tomato — urutannya bebas asal lengkap.
Setiap sisi bisa diatur sendiri: border-top, border-right, border-bottom, border-left — masing-masing dengan varian -width/-style/-color bila perlu mengubah satu hal saja. Pola favorit tampilan modern: hanya border-bottom pada kartu (garis aksen di bawah judul), atau border-radius — tetangga border — yang membulatkan sudut sampai menjadi pil penuh saat nilainya setengah tinggi elemen.
Empat kelas pertama memamerkan gaya inti dengan tebal berbeda — perhatikan dotted dan dashed makin terlihat polanya pada tebal besar. .kartu-aksen memakai pola sehari-hari: garis bawah tebal sebagai aksen plus sudut membulat, tanpa bingkai penuh.
Buat lima kartu dengan lima gaya border berbeda, lalu satu kartu bergaya modern: tanpa bingkai penuh, hanya aksen bawah dan sudut membulat.
.garis-satu { border: 1px solid blue; }
.garis-dua { border: 10px dotted green; }
.garis-tiga { border: 3px dashed #ff6b35; }
.garis-empat { border: 6px double purple; }
.kartu-aksen {
border-bottom: 4px solid teal;
border-radius: 8px;
}Beri kedalaman pada kartu, tombol, dan fokus input.
box-shadow menggambar bayangan di luar (atau di dalam) kotak elemen dengan empat nilai inti: geser-x, geser-y, blur, dan warna — box-shadow: 0 4px 12px rgba(0,0,0,0.15). Geser nol dengan blur besar menghasilkan "mengambang" lembut ala kartu modern; geser tajam tanpa blur memberi kesan retro flat dengan tepi tegas (2px 2px 0 #000).
Kata kunci inset membalik bayangan ke dalam membentuk cekungan — cocok untuk input yang tertekan dan track scrollbar. Bayangan juga bisa ditumpuk koma: kombinasi satu bayangan tipis dekat plus satu lebar jauh menghasilkan kedalaman realistis yang sulit dicapai satu lapis.
Kebiasaan praktis: pakai warna rgba alih-alih hitam pekat (bayangan di dunia nyata jarang benar-benar hitam), satukan arah cahaya untuk semua elemen — konsistensi lebih penting daripada keindahan satu kartu — dan pasangkan transisi pada hover (box-shadow termasuk properti yang paling enak dianimasikan untuk efek "mengangkat").
Dua lapis bayangan kartu bekerja seperti cahaya sungguhan: satu garis kontak tipis di dasar plus kabut lebar di belakangnya. Saat hover, keduanya diperbesar sedikit — kartu seolah terangkat. Versi inset memberi kesan tertekan pada input. Perhatikan rgba ber-alpha rendah: bayangan halus, bukan blok hitam.
Buat kartu dengan bayangan dua lapis yang "terangkat" saat hover (tambahkan transition), lalu input berbayangan inset.
.kartu {
box-shadow:
0 1px 2px rgba(0, 0, 0, 0.08), /* lapis dekat tajam */
0 8px 24px rgba(0, 0, 0, 0.12); /* lapis jauh lembut */
}
.kartu:hover {
box-shadow:
0 2px 4px rgba(0, 0, 0, 0.08),
0 14px 32px rgba(0, 0, 0, 0.16);
}
.input-cekung {
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
}Static, relative, fixed, dan absolute beserta kegunaannya.
Properti position menentukan bagaimana elemen ditempatkan, dan empat nilainya membentuk tangga kendali. static adalah bawaan: elemen mengalir normal mengikuti dokumen. relative memindahkan elemen relatif terhadap posisi normalnya — offset top/right/bottom/left menggesernya tanpa mengusik unsur lain, yang tetap menghormati tempat asalnya.
fixed melepaskan elemen dari gulungan halaman: diposisikan terhadap jendela browser dan tetap di tempatnya selama halaman digulir — navbar atas yang selalu terlihat dan tombol "kembali ke atas" adalah penghuni tetap pola ini. absolute menempatkan elemen pada titik tepat di dalam leluhur terdekat yang ber-position (biasanya relative) — elemen lain tidak lagi menyisakan ruang baginya, sehingga ia bisa menumpuk di atas apa pun; inilah dasar dropdown, tooltip, dan badge notifikasi.
Kuncinya satu kalimat: offset top/right/bottom/left hanya bekerja setelah position diatur pada elemen itu. Tanpa position, keempat properti itu diam seribu bahasa.
Trio kegunaan nyata: navbar fixed menempel di atas layar berapa pun halaman digulir; .kartu diberi relative semata agar menjadi "pasangan" koordinat; .badge absolute menempel di pojok kartu itu (negatif -8px menjorok keluar sedikit) — resep notifikasi merah yang familar.
Buat kartu relative dengan badge absolute di pojoknya, lalu navbar fixed yang tetap terlihat saat halaman digulir.
.navbar {
position: fixed;
top: 0; left: 0; right: 0;
background: #1c2833;
padding: 12px 20px;
}
.kartu { position: relative; }
.badge {
position: absolute;
top: -8px; right: -8px;
background: #e74c3c;
color: #fff;
border-radius: 50%;
padding: 4px 8px;
font-size: 12px;
}Atur elemen mana tampil di atas ketika bertumpuk.
Saat elemen bertumpang tindih (karena position absolute/fixed atau margin negatif), z-index memutuskan siapa di atas: nilainya bilangan bulat bebas — elemen bernilai lebih tinggi menang, dan elemen tanpa z-index berdiri di urutan kode (yang belakangan menimpa). Pasangannya wajib: z-index hanya berlaku pada elemen ber-position selain static (atau elemen flex/grid anak).
Kenyataan pahitnya: z-index bukan satu tangga global. Elemen dengan position sekaligus z-index menciptakan "stacking context" — dunia lapisan tersendiri yang anak-anaknya hanya bertarung di dalamnya. Navbar z-index 999 bisa kalah oleh modal z-index 1 jika modal hidup di dalam induk ber-z-index lebih tinggi. Gejala "kenapa z-index 9999-ku kalah" hampir selalu berakar pada konteks bersarang ini.
Kebiasaan sehat: gunakan nilai bertingkat konsisten (10 dropdown, 100 navbar, 1000 modal, 2000 toast) dan kendalikan sedikit induk mungkin. Semakin sedikit elemen yang membuat stacking context, semakin bisa diprediksi lapisanmu — dan semakin jarang kamu berdialog dengan z-index: 99999.
Tangga bertingkat (10-100-1000-2000) memberi ruang untuk sisipan di masa depan — dropdown baru cukup ambil 120, tak perlu perang angka. Perhatikan semua peserta ber-position: z-index tanpa position pada elemen static hanyalah angka kesepian yang tak didengar siapa pun.
Bangun tiga lapis (kartu, dropdown di dalam kartu, modal global) dengan tangga z-index yang rapi, lalu uji menempatkan modal di dalam induk ber-z-index rendah untuk melihat gejala konteks bersarang.
.navbar {
position: fixed;
z-index: 100; /* tingkat: navigasi */
}
.dropdown {
position: absolute;
z-index: 110; /* sedikit di atas navbar */
}
.modal {
position: fixed;
z-index: 1000; /* tingkat: jendela modal */
}
.toast {
position: fixed;
z-index: 2000; /* tingkat: notifikasi teratas */
}Bungkus teks di sekitar gambar dan elemen lain.
Float melepaskan elemen dari aluran normal dan mendorongnya ke satu sisi — kiri atau kanan — lalu isi di sekitarnya (terutama teks) mengalir memenuhi ruang yang tersisa. Empat nilainya: left, right, none (mematikan), dan inherit (mewarisi induk). Efek paling dikenalnya adalah tata letak majalah: gambar di kiri, paragraf menyorok manis di sisiannya.
Sebelum era flexbox dan grid, float dimanfaatkan untuk membangun layout kolom — kini tugas itu sudah diambil alih teknik yang lebih kuat. Tapi untuk tujuan aslinya float tetap juara: membalut gambar dengan teks, quotation yang menjorok, atau elemen kecil yang ingin dikelilingi isi.
Efek samping yang wajib dikenali: elemen induk dari sesuatu yang mengapung bisa "runtuh" karena anaknya tidak lagi menopang tingginya. Solusinya properti clear pada elemen setelahnya (clear: both memaksa turun ke bawah pengapungan), atau teknik modern clearfix. Kenali gejala ini — halaman yang tiba-tiba bertabrakan biasanya sedang menderita float yang belum dibersihkan.
Gambar mengapung kiri dengan margin kanan-bawah sebagai jeda napas teks — itulah seluruh sihir float. Elemen berkelas .bawah memakai clear: both agar memulai baris baru di bawah pengapungan, mencegah induk runtuh. Coba ganti left menjadi right dan rasakan bedanya.
Buat artikel dengan gambar mengapung kiri yang dikelilingi dua paragraf, lalu footer yang clear di bawahnya.
.gambar-postingan {
float: left;
width: 240px;
margin: 0 18px 8px 0; /* kanan-bawah agar teks tidak menempel */
}
.bawah { clear: both; }Kelola isi yang tak muat: gulir, sembunyikan, atau elipsis.
Apa yang terjadi saat isi lebih besar dari kotaknya? Properti overflow menjawab dengan empat pilihan. visible (bawaan) membiarkan isi meluber keluar kotak — kadang artistik, sering kacau. hidden memotong rapat apa pun yang melebihi batas. scroll selalu menyediakan bilah gulir; auto lebih sopan — bilah baru muncul saat benar-benar diperlukan. Aturan vertikal-horizontal bisa berbeda: overflow-x: hidden; overflow-y: auto memotong menyamping tapi menggulir ke bawah.
Resep paling dipakai sepanjang karier: teks satu baris yang terpotong elipsis. Tiga sahabat wajib bersama: white-space: nowrap mencegah turun baris, overflow: hidden memotong, dan text-overflow: ellipsis menambah "…" di titik potong. Tanpa ketiganya lengkap, elipsis tidak muncul.
Blok kode dan kutipan panjang adalah penghuni tetap overflow: pre berpasangan dengan overflow-x: auto agar kode panjang digulir alih-alih merusak tata letak. Kotak dengan tinggi tetap (max-height) plus overflow-y: auto juga adalah resep bawaan dropdown dan panel chat yang isinya bertumbuh.
Trio pertama menghasilkan "Judul yang sangat panjang…" yang rapi di satu baris — hapus satu saja dan elipsisnya lenyap. pre menggulir menyamping menjaga halaman tetap utuh, dan panel chat dengan max-height membentuk jendela bergulir alami. Kombinasi kecil ini muncul di hampir semua antarmuka nyata.
Buat daftar judul artikel dengan elipsis satu baris, panel chat bergulir max-height 300px, dan blok kode yang menggulir menyamping.
.judul-satu-baris {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
pre.kode {
overflow-x: auto; /* kode panjang digulir */
}
.panel-chat {
max-height: 320px;
overflow-y: auto; /* isi bertambah, kotak menggulir */
}Paksa media mengisi kotak tanpa rusak proporsinya.
Masalah klasik: gambar 4:3 dimasukkan ke kotak 16:9 — defaultnya digelek atau dimanjangkan. object-fit mengatur bagaimana elemen media (img, video, iframe berukuran) mengisi kotaknya. cover memenuhi seluruh kotak sambil menjaga proporsi asli, memotong kelebihan tepi — pilihan utama untuk thumbnail dan hero. contain memuat seluruh gambar utuh di dalam kotak, membiarkan ruang kosong di sisi yang tak terpakai — pas untuk logo dan diagram.
Nilai lain: fill memaksa pas penuh tanpa peduli proporsi (gelembung wajah dijamin), none menampilkan ukuran asli apa adanya, dan scale-down berperilaku seperti none atau contain mana yang lebih kecil. Pendampingnya object-position mengatur titik fokus pemotongan — object-position: top menjaga wajah di bagian atas saat cover memotong.
Bandingkan dengan background-image: properti background punya perilaku serupa lewat background-size: cover, tapi hanya untuk elemen dekoratif. Untuk gambar konten yang butuh alt dan makna semantik, img dengan object-fit adalah jalur yang benar — aksesibel sekaligus rapi.
cover membuat seluruh grid thumbnail seragam rapi walau foto aslinya bermacam proporsi; object-position menyelamatkan wajah dari pemotongan. contain menjaga logo tetap utuh di slot persegi panjang — dua kata kunci, dua filosofi berlawanan yang sama-sama berguna.
Buat grid foto profil seragam 200×200 dengan cover + posisi atas, lalu baris logo mitra dengan contain.
.thumbnail {
width: 240px;
height: 140px;
object-fit: cover; /* isi penuh, potong sisa */
object-position: center top; /* fokus di bagian atas */
}
.logo {
width: 120px;
height: 60px;
object-fit: contain; /* utuh, tak terpotong */
}Ganti penanda list: kotak, lingkaran, romawi, atau hilang.
Penanda daftar HTML — bullet dan angka — sepenuhnya bisa diubah CSS lewat properti list-style-type. Untuk daftar tak berurut (ul): disc (titik bawaan), circle (lingkaran berongga), square (kotak), dan none yang menghapus penanda. Untuk daftar berurut (ol): decimal (1, 2, 3), lower/upper-alpha (a/b/c atau A/B/C), lower/upper-roman (i, ii, iii atau I, II, III).
Nilai none adalah pintu menuju hal lain: tanpa bullet, sebuah ul siap diubah menjadi menu navigasi horizontal atau daftar tag pil — penanda lama diganti dekorasi buatan seperti warna latar dan jarak. Hampir semua menu website dibangun dari "ul tanpa bullet" ini.
Dua properti pendamping menyempurnakan kontrol: list-style-position menentukan apakah penanda berada di dalam (inside) atau di luar (outside) kotak isi, dan list-style-image mengganti penanda dengan gambar custom. Keduanya jarang dibutuhkan — 90% kebutuhan selesai di list-style-type saja.
Empat kelas pertama mengganti penanda bawaan dengan sekali deklarasi. Blok ul.menu menunjukkan pola paling produktif: none memoles daftar, padding: 0 meluruhkan indentasi bawaan, lalu li dibuat sebaris — hasilnya kerangka menu navigasi yang tinggal diberi warna.
Ubah satu daftar menjadi romawi besar, satu lagi lingkaran, lalu bangun menu horizontal dari ul tanpa penanda.
ul.makanan { list-style-type: square; }
ul.minuman { list-style-type: circle; }
ol.bab { list-style-type: upper-roman; }
ol.huruf { list-style-type: lower-alpha; }
ul.menu {
list-style-type: none; /* polos: siap jadi navigasi */
padding: 0;
}
ul.menu li { display: inline-block; margin-right: 12px; }Susun baris-kolom lentur dengan display: flex.
Flexbox adalah sistem tata letak satu-dimensi: ia hebat menyusun anak-anak dalam SATU arah — baris atau kolom. Cukup display: flex pada wadah, dan anak-anaknya langsung berbaris rapi dengan tinggi seragam, siap diatur. Sebelum flexbox, hal serupa butuh trik float dan clear yang rapuh; kini satu properti menuntaskan semuanya.
Properti sang wadah mengatur arah dan distribusi: flex-direction memilih row (baris) atau column (kolom); justify-content mengatur sepanjang sumbu utama (flex-start, center, space-between, space-around); align-items mengatur sumbu silangnya (stretch bawaan, center, flex-start); gap memberi jarak antar anak tanpa margin; dan flex-wrap: wrap membolehkan anak pindah baris bila tak muat.
Properti sang anak mengatur porsi: flex: 1 membuat anak memenuhi sisa ruang secara adil; flex: 2 menuntut porsi dua kali; flex: 0 0 200px mengunci lebar. Kombinasi klasik: sidebar tetap 240px plus konten flex: 1 — layout dua kolom yang tak bisa hancur. Navbar, kartu, form label-input, hampir semua antarmuka modern adalah flexbox menyamar.
Navbar memakai tiga pengatur wadah sekaligus: anak-anak sejajar tengah secara vertikal, logo kiri dan menu kanan teregang space-between, gap menjaga jarak. Layout badan menunjukkan duo porsi: sidebar terkunci 240px sementara isi mengembang flex: 1 — ubah lebar jendela dan perhatikan hanya isi yang melebar.
Angka ajaib ada di flex: 1 1 260px — dasar 260px per kartu, boleh tumbuh mengisi ruang dan menyusut saat sempit; flex-wrap memindahkan yang tak muat ke baris berikut. Hasilnya grid kartu responsif tanpa satu pun media query.
Bangun navbar flex (logo kiri, menu kanan, tengah vertikal) dan layout dua kolom sidebar-konten, lalu uji di lebar layar berbeda.
.navbar {
display: flex;
align-items: center; /* tegak: tengah */
justify-content: space-between; /* mendatar: meregang */
gap: 16px;
padding: 12px 20px;
}
.badan {
display: flex;
gap: 24px;
}
.sisi { flex: 0 0 240px; } /* kaku 240px */
.isi { flex: 1; } /* menyerap sisanya */Tata letak dua dimensi dengan baris dan kolom bernama.
Kalau flexbox menurus satu arah, Grid mengurus dua arah sekaligus: baris DAN kolom dalam satu wadah — sistem tata letak paling kuat yang pernah dimiliki CSS. Wadah diberi display: grid, lalu grid-template-columns mendefinisikan lebarnya: grid-template-columns: 240px 1fr 1fr membangun satu kolom tetap dan dua kolom lentur (fr = fraction, pecahan ruang sisa).
Senjata andalannya repeat() dan minmax(): repeat(3, 1fr) menulis tiga kolom sama lebar dalam sekejap, sedangkan repeat(auto-fit, minmax(220px, 1fr)) adalah mantra responsif — "buat kolom 220px sebanyak yang muat, bagi rata sisanya" — grid yang menyusun sendiri jumlah kolomnya mengikuti lebar layar, tanpa media query. gap mengatur jarak baris-kolom sekaligus.
Elemen anak bisa ditempatkan presisi: grid-column: 1 / 3 membuat kartu membentang dua kolom, grid-area dengan nama (header, sidebar, konten, footer) menggambar cetakan halaman penuh seperti peta. Grid untuk kerangka besar halaman, flexbox untuk isian di dalamnya — duo inilah standar tata letak web masa kini.
Mantra auto-fit + minmax membuat galeri menata diri: layar lebar memuat banyak kolom, layar ponsel menyisakan satu-dua — semuanya otomatis. Kartu berkelas unggulan membentang dua kolom dengan grid-column: span 2. Perkecil jendela browser dan saksikan grid menyusun ulang dirinya tanpa muatan ulang.
grid-template-areas menggambar cetakan halaman seperti peta ASCII: kepala dan kaki membentang penuh, sisi dan isi berbagi baris tengah. Tiap anak tinggal diberi grid-area sesuai namanya — memindah sidebar ke kanan berarti memindah satu kata di peta, bukan menata ulang margin.
Bangun galeri auto-fit dengan satu kartu span 2, lalu cetakan halaman lengkap (header/sidebar/isi/footer) dengan template-areas.
.galeri {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 20px;
}
.galeri .unggulan {
grid-column: span 2; /* kartu unggulan dua kolom */
}Tiga cara menengah: teks, blok, dan segalanya.
Menengahkan legendaris sulit di CSS lama — lelucon berpuluh tahun — tapi tiga alat modern menuntaskannya. Kasus pertama: teks di dalam elemen. text-align: center untuk mendatar dan line-height setinggi kotaknya (atau padding simetris) untuk tegak — cukup untuk tombol dan badge satu baris.
Kasus kedua: blok berlebar tetap di tengah induk. margin: 0 auto — kiri-kanan auto membagi sisa ruang sama rata. Ini solusi klasik yang tetap sehat sampai kini untuk konten bertumpuk vertikal. Untuk menengahkan tegak blok di induk bertinggi tetap, pasangkan induk dengan display: flex dan align-items: center.
Kasus ketiga — senjata serba-bisa: induk flexbox tiga baris (display: flex; justify-content: center; align-items: center) menengahkan anak ke arah mana pun, ukuran apa pun, tanpa perhitungan. Alternatif sejawat untuk elemen ber-position absolute: left: 50%; top: 50%; transform: translate(-50%, -50%) — persen pada translate mengacu ukuran elemen sendiri, jadi pas tengah presisi. Pilih satu sesuai senjata favorit; semua sah.
Tiga tingkat kesulitan tiga obat: teks cukup text-align + line-height; blok bertumpuk cukup margin auto; dan panggung flex tiga baris menengahkan apa pun di tengah layar — pola hero "coming soon" yang sering kamu lihat. Uji ketiganya di satu halaman yang sama.
left/top 50% menempatkan titik kiri-atas anak di tengah induk — belum pas tengah; translate(-50%, -50%) lalu menggeser anak kembali separuh ukurannya sendiri. Trik persen-vs-persen ini tetap menjadi resep modal dan tooltip yang menempel presisi.
Buat halaman "segera hadir" dengan logo sempurna di tengah layar (flex), modal ber-transform tengah, dan konten 640px margin auto.
/* 1) teks */
.tombol {
text-align: center;
line-height: 44px; /* = tinggi tombol */
}
/* 2) blok tetap */
.konten { width: 640px; margin: 0 auto; }
/* 3) serba-bisa */
.panggung {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}Simpan nilai yang bisa dipakai ulang di seluruh lembar gaya.
Custom properties — variabel CSS — dideklarasikan dengan dua garis di awal nama: --utama: teal. Tempat deklarasinya menentukan jangkauannya: pada :root ia global untuk seluruh dokumen; pada sebuah selektor ia lokal untuk elemen itu dan keturunannya. Pemakaiannya lewat fungsi var(): color: var(--utama), dengan cadangan opsional var(--utama, black) yang aktif bila variabelnya tak terdefinisi.
Kekuatan sejatinya baru terasa saat dipakai: ganti satu nilai di :root dan seluruh tombol, tautan, serta aksen di situs ikut berganti — palet, spacing, dan radius menjadi tuas-tuas yang bisa diputar tanpa menyentuh puluhan baris. Berbeda dari pra-prosesor lama (Sass/Less), variabel ini hidup di browser: bisa dibaca dan diubah dari JavaScript (element.style.setProperty), dan bisa berbeda per elemen.
Satu trik yang mengubah segalanya: mendeklarasikan ulang variabel di dalam media query atau kelas tertentu. :root { --bg: white } lalu .gelap { --bg: #1c2833 } — satu kelas toggle mengganti seluruh tema karena semua elemen membaca dari sumber yang sama. Begitulah mode gelap modern dibangun tanpa menulis ulang lembar gaya.
Seluruh sistem warna dan bentuk situs ini hidup di lima variabel :root. body.gelap cukup menimpa dua variabel — latar dan teks — dan semua elemen yang membaca var() ikut berubah seketika, termasuk kartu yang warnanya tetap. Tambahkan tombol penerang JavaScript satu baris (classList.toggle) dan mode gelapmu selesai.
Rancang setidaknya enam variabel tema (warna, jarak, radius) untuk halamanmu, lalu buat kelas .gelap yang menimpanya dan tombol toggle mode gelap.
:root {
--utama: hsl(190, 60%, 40%);
--bg: #f7f9fa;
--teks: #243b46;
--radius: 10px;
--jarak: 16px;
}
body {
background: var(--bg);
color: var(--teks);
}
.kartu {
border-radius: var(--radius);
padding: var(--jarak);
background: var(--utama);
}
body.gelap {
--bg: #16222b;
--teks: #e8eef1;
}Hitung ukuran langsung di dalam CSS.
calc() adalah kalkulator di tengah deklarasi: width: calc(100% - 240px) mengurangi piksel dari persen — dua satuan yang biasanya tak bisa dicampur. Aturannya longgar tapi tegas: operator + - * / dipisah spasi (calc(100%-240px) gagal karena minus melekat), dan hasil campuran satuan diselesaikan browser saat runtime. Kegunaan klasiknya: sidebar tetap + konten selebar "semua minus sidebar" tanpa float.
Tiga sepupu modern menyelesaikan kasus umum lebih ringkas. min(a, b) memilih terkecil: width: min(600px, 100%) aman di layar sempit. max(a, b) memilih terbesar: font-size: max(1rem, 14px) tak pernah jatuh di bawah 1rem. Dan clamp(min, ideal, max) menjepit nilai ideal di antara dua batas — clamp(1rem, 2.5vw, 1.5rem) berarti font mengikuti lebar layar tapi tak pernah lebih kecil 1rem atau lebih besar 1.5rem.
clamp() untuk ukuran adalah bentuk paling sederhana dari tipografi fluid — judul yang membesar mulus di layar lebar dan mengecil tertib di ponsel, tanpa satu pun media query. Fungsi attr() menutup daftar: ia membaca atribut HTML sebagai nilai, misalnya menampilkan angka data-harga lewat content: attr(data-harga) pada pseudo-element.
Tiga fungsi, tiga masalah usang tuntas: calc mencampur persen dan piksel untuk layout sidebar; clamp membuat judul berskala mulus antara 1.6rem dan 3rem mengikuti layar; min menjaga kolom bacaan tetap 680px di layar besar dan 90% di layar kecil. Resize jendela dan rasakan semuanya menyesuaikan tanpa titik henti.
Terapkan tipografi fluid clamp pada h1-h3, lebar konten min(680px, 92%), dan layout sidebar dengan calc — tanpa media query sama sekali.
.isi {
width: calc(100% - 260px); /* semua dikurangi sidebar */
margin-left: 260px;
}
h1 {
font-size: clamp(1.6rem, 4vw, 3rem); /* fluid dengan jepit */
}
.konten {
width: min(680px, 90%); /* tak pernah lebih lebar dari keduanya */
}Ubah gaya berpindah lembut, bukan mendadak.
Tanpa transisi, perubahan gaya terjadi seketika: tombol hover melompat warna dalam satu frame. transition membuatnya meluncur: cukup deklarasikan pada keadaan diam, dan browser mengisi perjalanan antar dua nilai otomatis. Bentuk ringkasnya empat bagian: transition: properti durasi timing delay — misal transition: background 0.3s ease.
Properti yang boleh ditransisikan hampir semuanya yang bernilai antara (warna, ukuran, opacity, transform, box-shadow); display dan font-family tidak bisa karena tak punya "antaranya". all sebagai nama properti praktis tapi boros — sebutkan properti spesifik agar browser tidak menyiapkan animasi untuk segalanya. Durusi 150-350ms adalah zona nyaman antarmuka: lebih cepat tak terasa, lebih lambat terasa lamban.
Timing function mengubah karakter gerak: ease (bawaan, pelan-pelan-cepat-pelan), linear datar, ease-in mulai berat, ease-out mulai ringan (favorit untuk hover), dan cubic-bezier() untuk kurva buatan sendiri. Aturan emas penempatan: transisi ditulis pada keadaan DASAR elemen, bukan di :hover — di hover hanya nilainya yang berubah, agar perjalanan pulang juga halus.
Transisi dideklarasikan sekali di keadaan dasar dengan dua properti berbeda durasi sama; :hover hanya mengganti nilai tujuan. Hasilnya: warna berpindah lembut dan tombol terangkat 2px dengan ease-out — dan saat kursor pergi, ia kembali turun sama halusnya karena aturannya tetap ada di keadaan dasar.
Buat kartu yang terangkat dengan bayangan tumbuh saat hover (kombinasi transform + box-shadow), lalu link yang garis bawahnya tumbuh dari tengah memakai transisi.
.tombol {
background: #1ABC9C;
color: #fff;
padding: 10px 22px;
border-radius: 6px;
/* transisi di keadaan dasar */
transition: background 0.25s ease-out, transform 0.25s ease-out;
}
.tombol:hover {
background: #148f77;
transform: translateY(-2px); /* terangkat halus */
}Geser, putar, skala, dan miringkan tanpa mengganggu layout.
Transform memanipulasi kotak elemen di bidang tanpa menyentuh aliran dokumen — tetangga-tetangganya tidak bergeser sedikit pun. Empat jurus dasarnya: translateX/Y (atau translate(x, y)) menggeser; rotate(45deg) memutar mengelilingi titik pusat; scale(1.2) memperbesar-seragam (atau scale(x, y) berbeda arah); dan skew(x, y) memiringkan seperti kartu dilihat serong.
Beberapa transform dirangkai koma dalam satu deklarasi: transform: translate(-50%, -50%) rotate(-2deg) — urutan pengerjaannya kiri-ke-kanan, dan urutan mempengaruhi hasil (memutar lalu menggeser berbeda dengan menggeser lalu memutar). Titik porosnya diatur transform-origin: center bawaan bisa dipindah ke top left atau persen apa pun — rotate berputar mengelilingi titik itu.
Tiga alasan transform menjadi fondasi animasi CSS: ia super ringan (dipercepat GPU, tak memicu layout ulang), ia bisa ditransisikan mulus, dan ia bekerja pada pseudo-element. Praktik umum sehari-hari: hover membesar kartu scale(1.03), ikon berputar rotate saat loading, dan modal muncul translate naik + fade. Nilai 3D-nya (rotateX/Y, perspective, translateZ) adalah kelanjutan alami bila kamu ingin lanjut ke efek kedalaman.
Kartu hover menggabungkan dua jurus — naik 6px dan membesar 2% — dalam satu deklarasi berurutan. Ikon memutar 180° mengelilingi titik pusatnya (transform-origin), dan stempel memakai rotate+skew untuk kesan cap kertas miring. Perhatikan tetangga-tetangga elemen tak pernah ikut bergeser.
Buat galeri foto polaroid: tiap kartu miring acak rotate, membesar dan lurus saat hover, dengan transform-origin yang kamu atur sendiri.
.kartu {
transition: transform 0.3s ease-out;
}
.kartu:hover {
transform: translateY(-6px) scale(1.02);
}
.ikon-muat {
animation: none;
transform-origin: center;
}
.ikon-muat.putar { transform: rotate(180deg); }
.stempel {
transform: rotate(-6deg) skew(-4deg);
}Gerak berurutan multi-langkah dengan keyframes.
Transisi hanya menghubungkan dua titik — animasi keyframes menulis peta jalan banyak titik. Blok @keyframes nama mendefinisikan jalurnya lewat kata from/to untuk kasus dua langkah, atau persen (0%, 50%, 100%) untuk koreografi penuh; lalu elemen menjalankannya lewat properti animation dengan nama durasi dan pengulangannya.
Properti animation punya barisan lengkap: nama, durasi, timing-function, delay, iteration-count (angka atau infinite), direction (alternate bolak-balik — trik klasik agar animasi berjalan mundur mulus tanpa lompat), fill-mode (forwards membekukan keadaan akhir), dan play-state (paused untuk jeda). Bentuk ringkasnya: animation: berdenyut 2s ease-in-out infinite alternate.
Kombinasi favorit praktik: denyut (pulse) untuk titik notifikasi live, goyang (shake) untuk form tak valid, masuk-panggung (fade + translate) untuk kartu saat halaman dibuka, dan spinner rotate infinite untuk indikator muat. Pasangan sepupu yang sering ditampilkan: bila kebutuhannya cuma dua keadaan, transisi lebih sederhana; begita butuh tiga titik atau berulang, keyframes pulanglah.
Titik merah live membesar-mengecil tanpa henti lewat tiga titik koreografi; kartu berkelas kartu-masuk hadir sekali — naik 16px sambil muncul — lalu fill-mode backwards menjaga ia tersembunyi selama delay (jika ada) sebelum tampil. from/to adalah tulisan ringkas 0%/100%.
Buat tiga animasi: titik live berdenyut, kartu masuk-panggang berurutan (perbedaan animation-delay), dan ikon pemuat berputar infinite.
@keyframes berdenyut {
0% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.25); opacity: 0.7; }
100% { transform: scale(1); opacity: 1; }
}
.titik-live {
width: 10px; height: 10px;
border-radius: 50%;
background: #e74c3c;
animation: berdenyut 1.6s ease-in-out infinite;
}
@keyframes masuk {
from { opacity: 0; transform: translateY(16px); }
to { opacity: 1; transform: translateY(0); }
}
.kartu-masuk {
animation: masuk 0.5s ease-out backwards;
}Gunakan grid dan media query untuk layar berbeda.
Grid membantu menyusun kartu dalam kolom. Media query mengubah aturan ketika lebar layar melewati batas tertentu, sehingga konten tetap nyaman dibaca di ponsel.
Grid bekerja lewat properti display: grid pada wadah: grid-template-columns: repeat(3, 1fr) membelah tiga kolom selebar sama, dan gap memberi jarak antar sel tanpa perlu margin. Anak-anak wadah otomatis menempati sel-sel itu berurutan — tanpa float, tanpa trik.
Media query menyaring kapan aturan berlaku: @media (max-width: 700px) { ... } hanya aktif saat lebar layar 700px ke bawah. Di dalamnya kita menimpa tata letak desktop — misalnya mengubah tiga kolom menjadi satu — sehingga halaman yang sama nyaman dilihat di layar mana pun. Pasangan grid + media query ini adalah fondasi web modern yang responsif.
Di layar lebar ada tiga kolom. Pada lebar 700px atau kurang, kartu menjadi satu kolom.
Tambahkan aturan untuk dua kolom pada layar tablet.
.cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
@media (max-width: 700px) {
.cards { grid-template-columns: 1fr; }
}Ubah tabel polos menjadi tabel modern berbaris zebra.
Tabel bawaan HTML tampak datar — tanpa garis, tanpa warna, tanpa jarak. Proyek ini mengerjakannya menjadi tabel modern selangkah demi selangkah, mengumpulkan hampir semua yang sudah dipelajari: selektor, border, padding, background, dan pseudo-class.
Langkah pertama: border-collapse: collapse pada table — sel-sel yang tadinya punya garis sendiri-sendiri melebur menjadi garis tunggal yang bersih. Berikutnya border tipis pada th dan td (1px solid dengan warna lembut) plus padding 8-12px agar isi tidak menempel kaca. Kepala tabel (th) diberi background gelap dengan teks terang sehingga kolom langsung terbaca sebagai judul.
Dua sentuhan akhir yang mengangkat kelas: tr:hover mewarnai baris yang sedang disorot kursor — umpan balik halus yang memudahkan melacak baris panjang; dan tr:nth-child(even) mewarnai baris genap dengan nada lebih terang, menciptakan pola zebra yang membuat mata berpindah baris tanpa tersesat. Selesai — tabel data yang terlihat seperti komponen aplikasi sungguhan.
Lima blok kecil, lima tugas berbeda: collapse menyatukan garis, th diwarnai, sel diberi bingkai dan ruang, nth-child(even) membuat zebra, hover menyorot baris aktif. Pasangkan dengan tabel HTML ber-th dari pelajaran tabel kursus HTML — hasilnya persis komponen tabel aplikasi modern.
Desain tabel daftar temanmu sendiri: kepala berwarna, zebra, hover, lalu tambahkan border-radius dan bayangan halus pada table-nya.
table.siswa {
border-collapse: collapse;
width: 100%;
font-family: sans-serif;
}
table.siswa th {
background: #35A9DB;
color: #fff;
}
table.siswa th,
table.siswa td {
border: 1px solid #d5dbdf;
padding: 10px 16px;
text-align: center;
}
table.siswa tr:nth-child(even) {
background: #f2f7f9;
}
table.siswa tr:hover {
background: #dceef5;
}