Topik ini membahas tipografi fluid, yaitu ukuran huruf yang berubah mulus mengikuti lebar viewport dengan fungsi clamp(). Pembahasan mencakup struktur clamp(minimum, nilai ideal, maksimum), cara menghitung nilai ideal berbasis satuan vw, contoh skala untuk h1 dan teks isi, serta perbandingannya dengan media query bertingkat yang menggunakan breakpoint. Setelah membacanya, judul dapat disetel agar membesar seiring lebar layar tanpa menulis banyak aturan per titik pecah.
Struktur fungsi clamp()#
Fungsi clamp() menerima tiga nilai, yaitu batas minimum, nilai ideal, dan batas maksimum. Browser menggunakan nilai ideal selama nilainya berada di antara kedua batas, menggunakan minimum apabila ideal terlalu kecil, dan menggunakan maksimum apabila ideal terlalu besar. Hasilnya setara dengan max(minimum, min(nilai ideal, maksimum)) yang dituliskan secara ringkas. Ketiga nilai dapat berupa ekspresi, sehingga nilai ideal boleh berupa calc() yang menggabungkan beberapa satuan.
Fungsi ini berlaku untuk properti apa pun yang menerima panjang, misalnya width, padding, dan margin. Manfaatnya paling terasa pada font-size karena ukuran huruf memengaruhi seluruh hierarki teks, dari judul hingga catatan kaki. Dengan satu deklarasi, ukuran huruf bergerak mengikuti layar dan tetap terkurung pada dua batas yang ditentukan. Pola yang sama juga dapat digunakan untuk padding kartu catatan, misalnya clamp(1rem, 2vw, 2rem), agar ruangnya menyesuaikan layar tanpa aturan tambahan.
Nilai ideal berbasis vw#
Satuan vw menyatakan satu persen lebar viewport, yaitu area jendela browser yang tersedia untuk halaman. Nilai ideal berbasis vw membuat ukuran huruf tumbuh linier mengikuti lebar layar. Kemiringan garis itu dikendalikan lewat dua pasang nilai, yaitu ukuran minimum pada lebar layar terkecil dan ukuran maksimum pada lebar layar terbesar. Prosedur menghitung nilai ideal berlangsung dalam empat langkah.
- Tetapkan dua pasang nilai, misalnya 24px pada lebar 320px dan 48px pada lebar 1280px.
- Hitung kemiringannya, yaitu (48 - 24) / (1280 - 320) = 0.025, sehingga setara 2.5vw.
- Hitung titik potongnya, yaitu 24 - (320 x 0.025) = 16, sehingga nilai idealnya
calc(16px + 2.5vw). - Susun deklarasinya menjadi
clamp(24px, calc(16px + 2.5vw), 48px).
Pemeriksaan cepatnya sederhana. Pada lebar 320px, nilai ideal dihitung 16 + 8 = 24 dan tepat menyentuh minimum. Pada lebar 1280px, nilai ideal dihitung 16 + 32 = 48 dan tepat menyentuh maksimum. Di antara kedua lebar itu, ukuran huruf bergerak terus tanpa lompatan.
Contoh skala h1 dan body#
Skala tipografi fluid tersusun dari beberapa deklarasi clamp() dengan rentang yang berbeda-beda. Judul utama diberi rentang lebar karena hierarkinya harus terasa, sedangkan teks isi diberi rentang sempit agar keterbacaannya stabil. Contoh berikut menyusun tiga tingkat ukuran sekaligus.
h1 {
font-size: clamp(2rem, calc(1.25rem + 3.5vw), 4rem);
}
h2 {
font-size: clamp(1.5rem, calc(1.1rem + 2vw), 2.5rem);
}
body {
font-size: clamp(1rem, calc(0.95rem + 0.25vw), 1.125rem);
}Pada contoh tersebut, h1 bergerak dari 32px di layar sempit hingga 64px di layar lebar, sedangkan teks isi hanya bergeser dari 16px ke 18px. Perbedaan rentang itulah yang menjaga hierarki: judul membesar jauh lebih cepat daripada teksnya. Nilai ideal pada setiap deklarasi memuat komponen rem, sehingga skala tetap menghormati preferensi ukuran font pengguna.
Diagram berikut memperlihatkan bentuk garis yang dihasilkan clamp() terhadap lebar viewport. Garis datar pada 24px di layar sempit, menanjak di antara 320px dan 1280px, lalu datar kembali pada 48px. Bagian yang menanjak itulah yang dihitung oleh nilai ideal berbasis vw.
Demo penggeser lebar layar#
Demo berikut mensimulasikan perubahan lebar viewport melalui penggeser. Panel simulasi memuat dua judul, yaitu judul fluid yang mengikuti clamp(24px, 5vw, 48px) dan judul pembanding yang menggunakan 8vw tanpa batas. Karena satuan vw menghitung dari viewport nyata, kedua judul dihitung ulang oleh skrip demo terhadap lebar simulasi tersebut. Jalankan demo, geser nilainya dari ujung kiri hingga ujung kanan, lalu amati judul vw murni yang terus membesar melewati 80px sedangkan judul fluid berhenti di 48px.
Kode sumber demo
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Demo simulasi lebar viewport untuk ukuran judul fluid</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<main>
<label for="lebar">Lebar viewport simulasi: <output id="baca-lebar">375</output> px</label>
<input type="range" id="lebar" min="320" max="1024" step="10" value="375">
<div class="simulasi" id="simulasi">
<p class="judul fluid" id="judul-fluid">Judul fluid (clamp)</p>
<p class="judul murni" id="judul-murni">Judul vw murni</p>
</div>
<p class="bacaan">Ukuran judul fluid: <output id="baca-fluid">24.0</output> px. Ukuran judul vw murni: <output id="baca-murni">30.0</output> px.</p>
</main>
<script src="index.js"></script>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 16px;
font-family: "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-size: 14px;
line-height: 1.5;
color: #1e293b;
background-color: #f8fafc;
}
main {
max-width: 100%;
overflow-x: auto;
}
label {
display: block;
font-weight: 600;
margin-bottom: 6px;
}
input[type="range"] {
width: 100%;
margin-bottom: 14px;
}
.simulasi {
width: 375px;
border: 1px dashed #94a3b8;
border-radius: 8px;
background-color: #ffffff;
padding: 12px 16px;
}
.judul {
margin: 0 0 6px;
font-weight: 700;
}
.judul.fluid {
color: #1d4ed8;
}
.judul.murni {
color: #b45309;
}
.bacaan {
margin: 12px 0 0;
color: #475569;
}
</style>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 16px;
font-family: "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-size: 14px;
line-height: 1.5;
color: #1e293b;
background-color: #f8fafc;
}
main {
max-width: 100%;
overflow-x: auto;
}
label {
display: block;
font-weight: 600;
margin-bottom: 6px;
}
input[type="range"] {
width: 100%;
margin-bottom: 14px;
}
.simulasi {
width: 375px;
border: 1px dashed #94a3b8;
border-radius: 8px;
background-color: #ffffff;
padding: 12px 16px;
}
.judul {
margin: 0 0 6px;
font-weight: 700;
}
.judul.fluid {
color: #1d4ed8;
}
.judul.murni {
color: #b45309;
}
.bacaan {
margin: 12px 0 0;
color: #475569;
}
</style>
<script>
const KECIL = 320;
const MIN_FLUID = 24;
const MAKS_FLUID = 48;
function ukuranFluid(lebar) {
// meniru clamp(24px, 5vw, 48px) terhadap lebar simulasi
const ideal = lebar * 0.05;
return Math.min(Math.max(ideal, MIN_FLUID), MAKS_FLUID);
}
function ukuranMurni(lebar) {
// meniru 8vw tanpa batas
return lebar * 0.08;
}
function perbarui() {
const lebar = Number(input.value);
const fluid = ukuranFluid(lebar);
const murni = ukuranMurni(lebar);
simulasi.style.width = lebar + 'px';
judulFluid.style.fontSize = fluid + 'px';
judulMurni.style.fontSize = murni + 'px';
bacaLebar.textContent = lebar;
bacaFluid.textContent = fluid.toFixed(1);
bacaMurni.textContent = murni.toFixed(1);
}
const input = document.getElementById('lebar');
const simulasi = document.getElementById('simulasi');
const judulFluid = document.getElementById('judul-fluid');
const judulMurni = document.getElementById('judul-murni');
const bacaLebar = document.getElementById('baca-lebar');
const bacaFluid = document.getElementById('baca-fluid');
const bacaMurni = document.getElementById('baca-murni');
input.addEventListener('input', perbarui);
perbarui();
</script>
<script>
const KECIL = 320;
const MIN_FLUID = 24;
const MAKS_FLUID = 48;
function ukuranFluid(lebar) {
// meniru clamp(24px, 5vw, 48px) terhadap lebar simulasi
const ideal = lebar * 0.05;
return Math.min(Math.max(ideal, MIN_FLUID), MAKS_FLUID);
}
function ukuranMurni(lebar) {
// meniru 8vw tanpa batas
return lebar * 0.08;
}
function perbarui() {
const lebar = Number(input.value);
const fluid = ukuranFluid(lebar);
const murni = ukuranMurni(lebar);
simulasi.style.width = lebar + 'px';
judulFluid.style.fontSize = fluid + 'px';
judulMurni.style.fontSize = murni + 'px';
bacaLebar.textContent = lebar;
bacaFluid.textContent = fluid.toFixed(1);
bacaMurni.textContent = murni.toFixed(1);
}
const input = document.getElementById('lebar');
const simulasi = document.getElementById('simulasi');
const judulFluid = document.getElementById('judul-fluid');
const judulMurni = document.getElementById('judul-murni');
const bacaLebar = document.getElementById('baca-lebar');
const bacaFluid = document.getElementById('baca-fluid');
const bacaMurni = document.getElementById('baca-murni');
input.addEventListener('input', perbarui);
perbarui();
</script></body>
</html>Perilaku yang tampil pada demo persis perilaku yang dilakukan browser terhadap viewport nyata. Pada ujung kiri, judul fluid menempel di batas minimumnya, dan pada rentang tengah ia mengikuti garis 5vw hingga menyentuh batas maksimumnya. Nilai batas yang dipilih dengan prosedur empat langkah di atas membuat kedua peralihan itu terjadi di lebar layar yang memang dimaksudkan.
Perbandingan dengan media query bertingkat#
Pendekatan lama untuk skala judul adalah media query bertingkat, yaitu menetapkan font-size tetap per breakpoint dan menaikkannya pada titik pecah tertentu. Ukuran huruf pada pendekatan itu melompat dari satu nilai tetap ke nilai tetap berikutnya, sedangkan clamp() membuatnya bergerak terus-menerus. Tabel berikut menyandingkan kedua pendekatan.
| Aspek | Media query bertingkat | clamp() |
|---|---|---|
| jumlah kode | satu blok @media per titik perubahan | satu deklarasi |
| perubahan ukuran | melompat antar nilai tetap | bergerak mulus di antara dua batas |
| titik kendali | eksplisit pada setiap breakpoint | dua batas dan satu kemiringan |
| perubahan tata letak diskrit | sesuai keperluan ini | bukan bidangnya |
Kedua pendekatan saling melengkapi. Media query tetap diperlukan apabila elemen harus berubah secara diskrit, misalnya tata letak dua kolom yang menjadi satu kolom, karena clamp() tidak mengubah struktur. Sebaliknya, skala ukuran yang kontinu seperti huruf dan spasi lebih ringkas ditangani clamp(). Pada proyek nyata, keduanya hadir bersama dengan tugas yang tidak saling menimpa, dan jumlah media query yang tersisa justru menjadi sedikit karena skala ukuran sudah diurus deklarasi tunggal.
Kesalahan umum#
Kesalahan pertama adalah menulis angka desimal dengan koma, misalnya 0,5, di dalam CSS. Browser menolak deklarasi semacam itu, karena CSS selalu menuliskan desimal dengan titik seperti 0.5. Perbaikannya, periksa kembali setiap angka pada deklarasi yang tidak berjalan dan pastikan pemisah desimalnya titik.
Kesalahan kedua adalah menganggap vw dan persen memiliki acuan yang sama. Satuan vw menghitung dari lebar viewport, sedangkan persen pada font-size menghitung dari font-size elemen induk. Campuran acuan yang tidak disadari menghasilkan ukuran yang sulit ditebak, sehingga pahami dulu acuan tiap satuan sebelum menyusun skala.
Kesalahan ketiga adalah memakai nilai ideal tanpa mengeceknya pada kedua ujung lebar layar. Akibatnya minimum tidak pernah tercapai, atau maksimum terlewati sejak layar sedang. Perbaikannya, uji halaman dengan DevTools pada lebar 320px dan 1280px, lalu sesuaikan kemiringan dan titik potongnya sampai kedua batas tersentuh di lebar yang dimaksudkan.
Ringkasan#
clamp(minimum, nilai ideal, maksimum)mengurung nilai ideal pada dua batas dan setara denganmax()atasmin().- Nilai ideal berbasis vw menghasilkan pertumbuhan linier, dan kemiringannya dihitung dari dua pasang nilai ukuran dan lebar layar.
- Judul memakai rentang lebar agar hierarki terasa, sedangkan teks isi memakai rentang sempit agar keterbacaan stabil.
- Media query tetap dipilih untuk perubahan tata letak diskrit, sedangkan
clamp()mengurus skala yang kontinu.
Referensi#
- clamp() — MDN
— Definisi fungsi
clamp()beserta hubungannya denganmin()danmax(). - font-size — MDN
— Properti
font-sizebeserta satuan dan kata kunci yang diterimanya. - Learn CSS — web.dev — Kursus resmi CSS yang mencakup responsivitas dan fungsi penjepit nilai.