Cara Membuat Galeri Scroll Horizontal, Cap Teks Melingkar, dan Efek Salah Cetak Risograf dengan CSS & JS (plus CMS PHP)
Cara Membuat Galeri Scroll Horizontal, Cap Teks Melingkar, dan Efek Salah Cetak Risograf dengan CSS & JS (plus CMS PHP)
Portofolio ilustrator semestinya terasa seperti karya itu sendiri: penuh tekstur, sedikit berantakan, dan menyenangkan untuk dijelajahi. Template Zine meniru majalah kecil hasil cetak risograf. Di artikel ini kita bongkar lima teknik intinya: efek tinta salah cetak, galeri yang bergeser menyamping saat halaman di-scroll, cap dengan teks melingkar yang berputar, tumpukan catatan testimoni, dan markdown mini yang aman untuk isi dari CMS.
1. Efek "salah cetak" tanpa gradasi dan tanpa glow
Mesin risograf mencetak setiap warna secara terpisah, sehingga lapisan tinta sering bergeser beberapa milimeter. Efek ini bisa ditiru dengan text-shadow yang tidak diberi blur, jadi hasilnya tetap blok warna flat, bukan cahaya berpendar:
.misreg{text-shadow:4px 3px 0 var(--acc),-3px -2px 0 var(--acc2)}
.misreg em{text-shadow:3px 2px 0 var(--yellow)}
Angka ketiga pada text-shadow adalah radius blur. Selama nilainya 0, bayangan berupa salinan huruf yang tajam. Untuk ilustrasi SVG, lapisan warna digabung dengan mix-blend-mode: multiply sehingga bagian yang bertumpuk menjadi lebih gelap, persis seperti dua tinta yang saling menimpa.
Tekstur kertas juga dibuat tanpa gradasi: sebuah SVG 240 x 240 berisi 140 titik kecil semi-transparan, dipasang sebagai latar berulang.
body{background:var(--paper) url(../img/kertas.svg)}
Judul sampul diberi variasi otomatis di PHP. Pemilik cukup menulis satu kalimat di CMS, lalu kata kedua dan terakhir menjadi huruf miring serif, sedangkan kata keempat diberi blok stabilo:
function judul_zine(string $t): string {
$kata = preg_split('/\s+/', trim($t));
$n = count($kata);
foreach ($kata as $i => &$k) {
$k = e($k);
if ($i === 1 || $i === $n - 1) $k = '<em>' . $k . '</em>';
elseif ($i === 3) $k = '<mark>' . $k . '</mark>';
}
return implode(' ', $kata);
}
Perhatikan bahwa setiap kata di-escape dengan e() sebelum dibungkus tag, jadi teks dari CMS tidak bisa menyisipkan HTML.
2. Galeri karya yang bergeser menyamping saat di-scroll
Polanya terdiri dari tiga lapis: section luar yang tinggi, wadah yang position: sticky setinggi layar, dan track horizontal di dalamnya.
.works-sticky{position:sticky;top:90px;height:calc(100vh - 90px);overflow:hidden}
.works-track{display:flex;gap:46px;width:max-content;will-change:transform}
Tinggi section luar dihitung dari panjang lintasan. Kalau track lebih panjang 2.000 piksel dari layar, section dibuat setinggi 2.000 piksel ditambah satu layar. Selama pengunjung menggulir sepanjang itu, wadah tetap menempel dan kita tinggal mengubah progres scroll menjadi geseran horizontal:
const sizeWorks = () => {
const geser = Math.max(0, track.scrollWidth - innerWidth);
works.style.height = (geser + innerHeight) + 'px';
works.dataset.geser = geser;
};
const moveWorks = () => {
const r = works.getBoundingClientRect();
const total = works.offsetHeight - innerHeight + 90;
const p = Math.min(1, Math.max(0, -r.top / Math.max(1, total)));
track.style.transform = `translate3d(${-p * works.dataset.geser}px,0,0)`;
};
sizeWorks() dipanggil ulang saat jendela diubah ukurannya dan saat filter kategori menyembunyikan poster, karena panjang lintasan ikut berubah. Di layar di bawah 980 piksel, efek ini dimatikan dan poster tersusun vertikal biasa. Menggeser ke samping dengan jari di HP sambil menggulir ke bawah justru membingungkan.
3. Cap dengan teks melingkar yang berputar
Teks melingkar memakai textPath SVG. Lingkaran digambar sebagai path dua busur, lalu teks "ditempelkan" di sepanjang path itu:
<svg viewBox="0 0 120 120">
<defs><path id="tp7" d="M60 60m-46 0a46 46 0 1 1 92 0a46 46 0 1 1-92 0"/></defs>
<circle cx="60" cy="60" r="57" fill="none" stroke="currentColor" stroke-dasharray="3 5"/>
<text><textPath href="#tp7">PROCREATE · 95% · PROCREATE ·</textPath></text>
</svg>
Seluruh SVG diputar dengan animasi CSS, sementara logo di tengahnya tetap diam. Setiap cap diberi durasi berbeda (--d: 14s, 17s, 20s, dan seterusnya) agar tidak berputar seragam seperti mesin. Saat kursor menyentuh cap, logo di tengah berbalik rotateY(180deg) seperti koin.
ID path dibuat dari ID teknologi di database (tp<?= $t['id'] ?>) supaya tidak bentrok ketika ada belasan cap dalam satu halaman.
4. Tumpukan catatan testimoni yang bisa dibalik
Semua catatan ditumpuk dengan position: absolute; inset: 0. JavaScript menyimpan urutan tumpukan dalam array, lalu setiap catatan diberi z-index dan sedikit geseran sesuai posisinya:
const layout = () => order.forEach((idx, k) => {
const n = notes[idx];
n.style.zIndex = notes.length - k;
n.style.transform = `translate(${k * 10}px, ${k * 10}px) rotate(${k === 0 ? -1.5 : (k % 2 ? 3 : -3)}deg)`;
});
Saat diklik, catatan teratas diberi kelas gone yang menerbangkannya ke kanan atas dengan sedikit rotateX. Setelah animasi selesai, indeksnya dipindah ke ujung array dan tumpukan disusun ulang. Hasilnya seperti membalik setumpuk kertas di meja.
5. Markdown mini yang aman untuk cerita karya
Pemilik menulis cerita karya di CMS dengan format sederhana: ## Subjudul, - poin, **tebal**, dan [teks](https://link). Kuncinya, teks di-escape dulu baru diubah menjadi HTML:
$inline = e($isList ? substr($b, 2) : ltrim($b, '# '));
$inline = preg_replace('/\*\*(.+?)\*\*/', '<strong>$1</strong>', $inline);
$inline = preg_replace('/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/', '<a href="$2" target="_blank" rel="noopener">$1</a>', $inline);
Karena < sudah menjadi <, tag HTML apa pun yang diketik akan tampil sebagai teks biasa. Pola link hanya menerima http:// atau https://, sehingga [klik](javascript:...) tidak pernah menjadi tautan aktif.
Ringkasan
- Salah cetak risograf =
text-shadowtanpa blur +mix-blend-mode: multiply. - Scroll horizontal = section tinggi + wadah sticky + progres scroll yang diubah menjadi
translateX. - Teks melingkar =
textPathSVG yang diputar CSS, durasi tiap cap dibuat berbeda. - Tumpukan catatan = urutan dalam array,
z-index, lalu pindahkan kartu teratas ke belakang. - Markdown mini aman = escape dulu, format belakangan, link hanya http/https.
Download source code lengkapnya
Template Zine lengkap dengan CMS (profil, karya + galeri, alat gambar, pengalaman, jasa, testimoni, pesan masuk, dashboard), data contoh, dan puluhan ilustrasi poster risograf bisa kamu unduh gratis.
Download Source Code Template Portofolio Zine + CMS di Papicode
Source code lengkapnya gratis
Lihat semua yang dibahas di artikel ini langsung berjalan.
Tutorial lainnya
Cara Membuat Sistem Tiket Travel dengan Pilih Kursi di Google Apps Script: Layout Armada, Anti Kursi Dobel, dan Kursi Kedaluwarsa
20 Oktober 2026
Cara Membuat Website Donasi Transparan dengan Google Apps Script: Kode Unik Transfer dan Laporan Penyaluran
20 Oktober 2026