Teknik fluid dan teknik adaptif saling melengkapi bila masing-masing dipakai pada lapisan yang tepat. Topik ini merakit fungsi clamp() untuk tipografi dan spasi, kisi auto-fit untuk kolom yang menyesuaikan, serta container query untuk penyesuaian komponen menjadi satu sistem layout fluid. Pembahasan ditutup dengan contoh halaman sederhana yang memakai ketiganya sekaligus. Setelah membacanya, keputusan kapan media query masih diperlukan juga dapat diambil dengan dasar yang jelas.
Tiga lapis penyesuaian#
Sistem layout fluid menempatkan setiap teknik pada lapisan yang berbeda. Lapisan viewport menangani ukuran yang bergerak mulus mengikuti jendela, dan dikerjakan dengan satuan vw beserta fungsi clamp(). Lapisan kisi menangani jumlah kolom yang berubah mengikuti lebar kontainer halaman, dan dikerjakan dengan grid auto-fit. Lapisan komponen menangani respons kartu terhadap wadahnya, dan dikerjakan dengan container query.
Pembagian ini menjaga setiap perubahan dihitung oleh pihak yang paling tahu ukurannya. Ukuran huruf tidak perlu tahu apa pun tentang breakpoint karena clamp() yang mengurungnya, jumlah kolom tidak perlu tahu tentang kartu karena grid yang menghitungnya, dan kartu tidak perlu tahu tentang halaman karena kontainernya yang diuji. Diagram berikut memperlihatkan ketiga lapis itu dari luar ke dalam.
Media query tetap hadir dalam sistem ini, tetapi perannya menyempit ke perubahan struktur halaman yang tidak dapat dinyatakan secara fluid. Semakin banyak keputusan yang dialihkan ke tiga lapis di atas, semakin sedikit breakpoint yang harus dipelihara. Bagian berikut membahas setiap lapis beserta deklarasinya.
Tipografi dan spasi fluid dengan clamp()#
Lapisan pertama mengubah ukuran yang semula melompat antar breakpoint menjadi bergerak terus-menerus. Fungsi clamp(minimum, nilai ideal, maksimum) mengurung nilai ideal berbasis vw di antara dua batas, sehingga ukuran tumbuh mengikuti jendela tanpa melewati batas keterbacaan. Lebar atau sempitnya pergerakan diatur langsung dari selisih kedua batasnya, sehingga setiap properti dapat diberi tingkat kepekaan yang berbeda. Pola yang sama diterapkan pada padding halaman dan jarak antar kartu agar ritme spasi ikut menyesuaikan.
:root {
--ukuran-judul: clamp(1.5rem, calc(1.1rem + 2vw), 2.25rem);
--ukuran-isi: clamp(1rem, calc(0.95rem + 0.25vw), 1.125rem);
--spasi: clamp(0.75rem, calc(0.5rem + 1vw), 1.5rem);
}Ketiga nilai di atas dinyatakan sebagai custom property, yaitu variabel CSS yang dideklarasikan pada pemilih dan dipakai di tempat lain melalui var(), misalnya font-size: var(--ukuran-isi). Nilai idealnya memuat komponen rem, sehingga pertumbuhannya tetap menghormati ukuran font dasar yang dipilih pengguna. Dengan lapisan ini, judul, teks isi, dan jarak antar elemen sudah responsif sebelum satu pun media query ditulis.
Kisi tanpa breakpoint dengan auto-fit#
Lapisan kedua menyerahkan jumlah kolom kepada grid. Deklarasi repeat(auto-fit, minmax(220px, 1fr)) membentuk kolom sebanyak mungkin selama lebar minimumnya masih muat, lalu membagi sisa ruang secara merata. Jumlah kolom naik dan turun mengikuti lebar kontainer tanpa satu pun media query, dan kartu yang ada selalu mengisi ruang yang tersedia.
.papan {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: var(--spasi);
}Nilai minimum pada minmax() menentukan kapan kolom berkurang, sehingga nilainya disetel dari lebar kartu paling sempit yang masih nyaman dibaca. Karena perhitungan ini terjadi pada kontainer halaman, pola tersebut menjadi jembatan menuju lapisan ketiga, yaitu ketika kartu yang sudah selesai dibentuk perlu menyesuaikan diri terhadap lebar slotnya masing-masing.
Perilaku ini berbeda dari kisi tetap yang jumlah kolomnya dinyatakan langsung. Kisi tetap mempertahankan jumlah kolomnya sampai media query mengubahnya, sedangkan kisi auto-fit menghitung ulang jumlah kolom pada setiap lebar. Akibatnya, kisi tetap lebih pas untuk susunan yang memang dirancang per tingkat, misalnya tiga wilayah utama halaman, sedangkan auto-fit lebih pas untuk daftar kartu yang panjangnya tidak pasti.
Penyesuaian komponen dengan container query#
Lapisan ketiga membuat kartu responsif terhadap lebar slotnya, bukan lebar jendela. Elemen kartu ditetapkan sebagai kontainer melalui container-type: inline-size, lalu isi kartunya diatur melalui @container. Satuan cqi dipakai untuk ukuran yang mengikuti lebar kartu, sehingga dua kartu dengan lebar berbeda menghasilkan ukuran teks yang berbeda pula.
.kartu {
container-type: inline-size;
position: relative;
background: #ffffff;
border: 1px solid #cbd5e1;
border-radius: 8px;
padding: var(--spasi);
}
@container (min-width: 340px) {
.kartu h2 {
font-size: calc(1rem + 1.5cqi);
}
}Perlu dicatat bahwa blok @container hanya boleh menata elemen di dalam kontainernya, sehingga deklarasi pada .kartu sendiri tetap berada di luar blok tersebut. Pada contoh ini, judul kartu membesar mengikuti lebar slotnya ketika kartu memperoleh ruang lebih dari 340 piksel. Kartu yang sama dapat dipindahkan ke sidebar maupun ke kolom utama tanpa perubahan gaya apa pun, karena penyesuaiannya melekat pada kartu itu sendiri.
Perhatikan pula bahwa kondisi min-width di sini menguji lebar kartu dan bukan lebar jendela, sehingga ambang 340 piksel dapat tercapai pada lebar jendela yang berbeda-beda tergantung jumlah kolom yang terbentuk. Kartu pada kisi satu kolom memenuhi kondisi itu lebih awal, sedangkan kartu pada kisi tiga kolom menyentuhnya belakangan atau tidak sama sekali. Perubahan pada kisi induk dengan sendirinya merambat ke keputusan komponen tanpa ada aturan tambahan yang menghubungkan keduanya.
Contoh halaman sederhana#
Contoh berikut merakit ketiga lapis pada satu halaman papan pengumuman kelas. Tipografi dan spasinya fluid melalui custom property, kolom kisi menyesuaikan lebar halaman melalui auto-fit, dan setiap kartu mengatur isinya melalui container query. Berkas HTML dan CSS utuhnya ditampilkan berikut.
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Papan pengumuman kelas</title>
<link rel="stylesheet" href="gaya.css">
</head>
<body>
<header class="kepala">
<h1>Papan pengumuman kelas</h1>
<p>Ringkasan informasi minggu ini</p>
</header>
<main class="papan">
<article class="kartu">
<h2>Jadwal piket</h2>
<p>Piket kelas dimulai Senin dengan Ali, Budi, dan Citra.</p>
<span class="tanggal">Senin</span>
</article>
<article class="kartu">
<h2>Ulangan matematika</h2>
<p>Ulangan bab bilangan dilaksanakan pada sesi terakhir Kamis.</p>
<span class="tanggal">Kamis</span>
</article>
<article class="kartu">
<h2>Olahraga</h2>
<p>Latihan basket berpindah ke lapangan dalam selama musim hujan.</p>
<span class="tanggal">Jumat</span>
</article>
<article class="kartu">
<h2>Perpustakaan</h2>
<p>Pengembalian buku paket diterima di meja perpustakaan.</p>
<span class="tanggal">Sabtu</span>
</article>
</main>
</body>
</html>/* Contoh halaman: sistem layout fluid */
* {
box-sizing: border-box;
}
:root {
--ukuran-judul: clamp(1.5rem, calc(1.1rem + 2vw), 2.25rem);
--ukuran-isi: clamp(1rem, calc(0.95rem + 0.25vw), 1.125rem);
--spasi: clamp(0.75rem, calc(0.5rem + 1vw), 1.5rem);
}
body {
margin: 0;
padding: var(--spasi);
font-family: sans-serif;
background: #f1f5f9;
color: #1e293b;
font-size: var(--ukuran-isi);
}
.kepala h1 {
margin: 0 0 0.25rem;
font-size: var(--ukuran-judul);
}
.kepala p {
margin: 0 0 var(--spasi);
color: #475569;
}
.papan {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: var(--spasi);
}
.kartu {
container-type: inline-size;
position: relative;
background: #ffffff;
border: 1px solid #cbd5e1;
border-radius: 8px;
padding: var(--spasi);
}
.kartu h2 {
margin: 0 0 0.5rem;
font-size: var(--ukuran-isi);
}
.kartu p {
margin: 0 0 0.75rem;
}
.tanggal {
display: inline-block;
font-size: 0.8rem;
font-weight: bold;
color: #1d4ed8;
background: #dbeafe;
border-radius: 999px;
padding: 2px 10px;
}
@container (min-width: 340px) {
.kartu h2 {
font-size: calc(1rem + 1.5cqi);
}
.tanggal {
position: absolute;
top: 0.75rem;
right: 0.75rem;
}
}Pada berkas beranda.html, setiap kartu memuat judul, teks pengumuman, dan pil tanggal. Pada berkas gaya.css, lapisan viewport mengatur padding halaman dan skala huruf melalui clamp(), lapisan kisi membentuk kolom melalui auto-fit, dan lapisan komponen memindahkan pil tanggal ke sudut kartu ketika kartunya cukup lebar. Persempit jendela browser secara perlahan, dan ketiga lapis itu bereaksi pada kecepatan yang berbeda sesuai acuannya masing-masing.
Halaman ini dijalankan dengan membuka beranda.html pada browser, karena kedua berkasnya saling terhubung melalui elemen <link>. Pada lebar penuh, kisi membentuk empat kolom, dan setiap kartu cukup lebar untuk memindahkan pil tanggalnya ke sudut. Ketika jendela dipersempit, jumlah kolom menyusut satu per satu, sedangkan kartu yang tersisa justru melebar dan sebagian di antaranya kembali memenuhi kondisi kontainernya. Perubahan pada lapisan yang satu memicu reaksi pada lapisan yang lain, dan inilah gambaran kerja sistem layout fluid secara keseluruhan.
Kapan media query tetap diperlukan#
Sistem fluid tidak menghapus media query, tetapi mempersempit tugasnya ke perubahan struktur yang tidak dapat dinyatakan secara fluid. Perubahan navigasi adalah contoh utamanya, yaitu tautan yang menumpuk pada layar sempit dan berjejer mendatar pada layar lebar. Pergantian susunan semacam itu bersifat diskrit, sehingga media query menjadi alat yang tepat untuknya.
Contoh kedua adalah pergantian urutan area halaman. Konten utama yang berada di sisi navigasi pada layar lebar sering dipindah ke atas navigasi pada layar sempit, dan pengaturannya dilakukan melalui media query yang mengubah templat grid halaman. Kasus lain yang senada mencakup menyembunyikan panel samping pada layar sempit serta pengaturan kolom footer per tingkat lebar.
Kaidah pembedanya sederhana. Apabila perubahannya berupa nilai yang bergerak, seperti ukuran huruf, spasi, dan lebar kolom, teknik fluid pada tiga lapis di atas yang bekerja. Apabila perubahannya berupa struktur yang bentuknya berbeda antar lebar layar, media query yang menanganinya. Dengan pembagian tugas ini, jumlah media query pada proyek menyusut secara alami tanpa mengorbankan kejelasan.
Ringkasan#
clamp()mengurus skala kontinu untuk tipografi dan spasi, sebaiknya dinyatakan sebagai custom property agar konsisten dipakai.repeat(auto-fit, minmax())membentuk kisi yang jumlah kolomnya menyesuaikan kontainer tanpa breakpoint.- Container query menata isi kartu terhadap lebar slotnya melalui
@containerdan satuancqi. - Media query tetap dipakai untuk perubahan struktur halaman, seperti pergantian navigasi dan urutan area.
Referensi#
- clamp() — MDN Web Docs — Dokumentasi fungsi penjepit nilai antara batas minimum dan maksimum.
- CSS container queries — MDN Web Docs — Panduan container query sebagai lapis penyesuaian komponen.
- Learn Responsive Design — web.dev — Kursus desain responsif yang memadukan media query, desain fluid, dan komponen adaptif.
- CSS: Cascading Style Sheets — MDN Web Docs — Indeks dokumentasi CSS sebagai rujukan properti yang dipakai pada topik ini.