transform menggeser, memutar, atau mengubah ukuran gambar sebuah elemen tanpa mengubah tempatnya di layout. Bayangin foto kamar yang ditempel di plastik bening di atas halaman. Menggeser plastiknya gak membuat teks lain pindah. Tapi kalau fotonya dipindah di dalam dokumen, semua teks di bawahnya mengalir ulang. top dan margin memindah foto di dokumen; transform cuma menggeser plastiknya. Karena itu transform dan opacity bisa dianimasikan di langkah composite saja, tanpa layout dan paint ulang.
🧪 Tebakan cepat: Kartu Kamar Teras naik 16 px dalam 300 ms. Kalau digerakkan lewat
top, Chromium menghitung layout berapa kali? Kalau lewattransform? Jawabannya ada di bagian "Diukur: transform lawan top".
Fungsi transform
| Fungsi | Artinya | Di halaman Bu Sri |
|---|---|---|
translate(x, y), translateX(), translateY() |
geser; persen dihitung dari ukuran elemen itu sendiri | kartu naik translateY(16px), galeri translateX(-100%) |
scale(n) |
perbesar atau perkecil | tombol malam ditekan scale(0.96) |
rotate(sudut) |
putar | panah galeri rotate(180deg) |
skew(sudut) |
miringkan | jarang dipakai di UI |
Titik pusatnya diatur transform-origin, default di tengah elemen (50% 50%). scale(0.96) di tombol malam mengecil ke arah tengahnya; bar hitung mundur di toast memakai transform-origin: left supaya menyusut ke kiri.
Urutan fungsi menentukan hasil
transform boleh berisi beberapa fungsi, dan urutannya mengubah hasil. Baca dari kanan ke kiri: fungsi paling kanan dikenakan duluan ke elemen, lalu hasilnya dikenai fungsi di sebelah kirinya. Kami memasang keduanya pada kotak 100 × 40 px di Chromium 147, WebKit 26.4, dan Firefox 146:
transform |
Yang terjadi | Kotak pembatasnya |
|---|---|---|
translateX(50px) rotate(45deg) |
diputar di tempat, lalu digeser lurus 50 px ke kanan | kiri 150,5, atas 70,5 |
rotate(45deg) translateX(50px) |
digeser 50 px dulu, lalu seluruhnya diputar 45° di sekitar titik pusat, jadi geserannya ikut miring: 35,4 px ke kanan dan 35,4 px ke bawah | kiri 135,9, atas 105,9 |
Jadi ya, urutan transform mempengaruhi hasil akhir.
translate, rotate, scale sebagai properti sendiri
Sejak Chrome 104, Firefox 72, dan Safari 14.1, ketiganya juga ada sebagai properti terpisah: translate, rotate, scale. Urutannya tetap: translate, lalu rotate, lalu scale, lalu transform, dibaca dari kiri seperti satu transform panjang. Kami mengukurnya: rotate: 45deg; transform: translateX(50px) sama persis dengan transform: rotate(45deg) translateX(50px). Dan scale: 2; transform: translateX(50px) menggeser kotaknya 100 px, karena geseran di transform ikut diperbesar scale.
Gunanya: tiap gerakan punya properti sendiri, jadi gak saling menimpa.
.room { translate: 0 16px; opacity: 0;
transition: translate 300ms ease-out, opacity 300ms ease-out, scale 150ms ease-out; }
.room.in { translate: none; opacity: 1; } /* masuk */
.room.selected { scale: 1.02; } /* dipilih, gak menghapus geser masuknya */
Kalau keduanya ditulis lewat transform, transform: scale(1.02) milik kartu terpilih menggantikan seluruh transform: translateY(16px) milik animasi masuk.
Diukur: transform lawan top
Kami merekam Performance trace di Chromium 147 saat kartu Kamar Teras naik 16 px dalam 300 ms, dengan Kamar Loteng dan Kamar Kebun di bawahnya. Angkanya dari tiga kali rekam:
| Kartu naik lewat | Layout | Paint |
|---|---|---|
top: 16px jadi 0 |
35 sampai 37 kali | 70 sampai 72 kali |
margin-top: 16px jadi 0 |
37 sampai 39 kali | 74 sampai 76 kali, dua kartu di bawahnya ikut bergeser |
transform: translateY(16px) jadi none |
1 kali | 2 kali, di awal saja |
translate: 0 16px jadi none |
1 kali | 2 kali, di awal saja |
transform + will-change: transform |
0 | 0 |
Itu jawaban tebakannya: lewat top, layout dihitung 35 sampai 37 kali (hampir di setiap frame), lewat transform cuma 1 kali. Satu layout dan dua paint di awal itu terjadi saat browser memindahkan kartu ke layer-nya sendiri.
Properti yang cukup sampai composite
Composite menyusun layer: gambar-gambar yang sudah di-paint. Kalau kartu punya layer sendiri, menggeser, memutar, mengubah ukuran (transform), atau mengubah transparansinya (opacity) cuma berarti menyusun ulang layer itu dengan posisi atau transparansi baru. Gak ada piksel yang perlu di-paint ulang. Pekerjaan itu bisa dilakukan compositor thread tanpa menunggu main thread.
Properti lain gak seberuntung itu. Di trace yang sama, box-shadow yang menebal: 0 layout tapi 74 paint, karena bayangannya harus dilukis ulang tiap frame. filter: blur(4px) jadi blur(0): 0 layout dan 6 paint, tapi style dihitung ulang 37 sampai 39 kali (transform: 7 sampai 9 kali), jadi main thread tetap ikut bekerja di setiap frame. Blur juga mahal untuk GPU: tiap piksel dihitung dari banyak piksel tetangganya.
will-change: layer disiapkan sebelum mulai
will-change: transform memberi tahu browser bahwa transform elemen ini akan berubah. Browser langsung membuatkan layer sendiri, sebelum animasinya mulai. Hasilnya di trace: 0 layout dan 0 paint, dibanding 1 layout dan 2 paint di awal tanpa will-change. Frame pertama gak perlu menunggu layer dibuat.
Harganya memori. Tiap layer adalah gambar bitmap di memori GPU: lebar × tinggi × 4 byte per piksel. Kartu Kamar Teras berukuran 328 × 143 px; di HP dengan layar 3x, layer-nya 984 × 429 piksel × 4 byte = sekitar 1,7 MB. Dari data layer Chromium (LayerTree, yang juga dipakai panel Layers), 3 kartu dengan will-change menambah 3 layer, dan 30 kartu menambah 30 layer, sekitar 51 MB. will-change juga membuat stacking context baru, seperti transform (ingat pelajaran Z-Index).
card.style.willChange = 'transform'; // tepat sebelum animasi
card.classList.add('in');
card.addEventListener('transitionend', () => {
card.style.willChange = ''; // lepas lagi setelah selesai
}, { once: true });
Pasang di elemen yang memang akan bergerak, sebentar sebelum bergerak, dan lepas setelahnya. Jangan di semua elemen.
⚠️ Jebakan yang sering ketemu
- Menganimasikan
top,left,width,height, ataumargin. Layout di hampir setiap frame, dan denganmargin, semua yang di bawahnya ikut bergeser. Pakaitransformatautranslate. * { will-change: transform; }. Tiap elemen jadi layer: puluhan MB memori GPU untuk satu halaman. Pakai seperlunya, lalu lepas.- Dua
transformsaling menimpa.transformdi aturan:activemenggantikantransformdari animasi masuk, bukan menambahnya. Pisahkan dengantranslate,rotate,scale. - Urutan fungsi tertukar.
rotate(45deg) translateX(50px)bergerak miring, bukan lurus. transformdi elemen inline.<span>dengandisplay: inlinegak bisa di-transform. Beridisplay: inline-block.
TL;DR: transform (translate, scale, rotate, skew) mengubah gambar elemen tanpa mengubah layout; persen di translate dihitung dari ukuran elemen sendiri, titik pusatnya transform-origin. Urutan fungsi mempengaruhi hasil: dibaca dari kanan ke kiri, jadi translateX(50px) rotate(45deg) bergeser lurus sedangkan rotate(45deg) translateX(50px) bergeser miring. Properti translate, rotate, scale (Chrome 104, Firefox 72, Safari 14.1) dikenakan dengan urutan translate, rotate, scale, lalu transform, dan gak saling menimpa. Di Chromium 147, kartu naik 16 px dalam 300 ms lewat top = 35 sampai 37 layout dan 70 sampai 72 paint; lewat transform = 1 layout dan 2 paint di awal; dengan will-change: transform = 0 dan 0. transform dan opacity cukup sampai composite; box-shadow di-paint ulang tiap frame, filter tetap menghitung style tiap frame. will-change menyiapkan layer sebelum animasi mulai, tapi tiap layer memakan memori (kartu 328 × 143 px di layar 3x sekitar 1,7 MB): pasang sebentar, lalu lepas.