Buat Slider Halaman Penuh Kustom dengan CSS dan JavaScript

Diterbitkan: 2022-03-11

Saya sering bekerja dengan tata letak layar penuh khusus, hampir setiap hari. Biasanya, tata letak ini menyiratkan sejumlah besar interaksi dan animasi. Baik itu timeline transisi kompleks yang dipicu oleh waktu atau rangkaian peristiwa berbasis scroll berbasis pengguna, dalam banyak kasus, UI membutuhkan lebih dari sekadar menggunakan solusi plugin yang siap pakai dengan beberapa penyesuaian dan perubahan . Di sisi lain, saya melihat banyak pengembang JavaScript cenderung menggunakan plugin JS favorit mereka untuk mempermudah pekerjaan mereka, meskipun tugas tersebut mungkin tidak memerlukan semua fitur yang disediakan oleh plugin tertentu.

Penafian: Menggunakan salah satu dari banyak plugin yang tersedia di luar sana memiliki keuntungan, tentu saja. Anda akan mendapatkan berbagai opsi yang dapat Anda gunakan untuk menyesuaikan kebutuhan Anda tanpa harus melakukan banyak pengkodean. Selain itu, sebagian besar pembuat plugin mengoptimalkan kode mereka, membuatnya kompatibel lintas-browser dan lintas-platform, dan seterusnya. Tapi tetap saja, Anda mendapatkan pustaka ukuran penuh yang disertakan dalam proyek Anda mungkin hanya untuk satu atau dua hal berbeda yang disediakannya. Saya tidak mengatakan menggunakan plugin pihak ketiga dalam bentuk apa pun secara alami adalah hal yang buruk, saya melakukannya setiap hari dalam proyek saya, hanya saja umumnya merupakan ide yang baik untuk mempertimbangkan pro dan kontra dari setiap pendekatan sebagaimana adanya praktik yang baik dalam pengkodean. Ketika datang untuk melakukan hal Anda sendiri dengan cara ini, diperlukan sedikit lebih banyak pengetahuan dan pengalaman pengkodean untuk mengetahui apa yang Anda cari, tetapi pada akhirnya, Anda harus mendapatkan sepotong kode yang melakukan satu hal dan hanya satu cara Anda menginginkannya.

Artikel ini bertujuan untuk menunjukkan pendekatan CSS/JS murni dalam mengembangkan tata letak slider yang dipicu gulir layar penuh dengan animasi konten khusus. Dalam pendekatan yang diperkecil ini, saya akan membahas struktur HTML dasar yang Anda harapkan akan disampaikan dari back-end CMS, teknik tata letak CSS (SCSS) modern, dan pengkodean vanilla JavaScript untuk interaktivitas penuh. Menjadi sederhana, konsep ini dapat dengan mudah diperluas ke plugin skala besar dan/atau digunakan dalam berbagai aplikasi yang tidak memiliki ketergantungan pada intinya.

Desain yang akan kami buat adalah etalase portofolio arsitek minimalis dengan gambar dan judul unggulan dari setiap proyek. Slider lengkap dengan animasi akan terlihat seperti ini:

Contoh slider dari portofolio arsitek.

Anda dapat melihat demo di sini, dan Anda dapat mengakses repo Github saya untuk detail lebih lanjut.

Ikhtisar HTML

Jadi inilah HTML dasar yang akan kita kerjakan:

 <div> <div class="mask"> <!-- Textual logo will go here --> </div> <div> <div class="slides"> <!-- Featured image slides will go here --> </div> <div class="slides mask"> <!-- Slide titles will go here --> </div> </div> <div> <!-- Static info on the right --> </div> <nav> <!-- Current slide indicator --> </nav> </div>

Div dengan id hero-slider adalah pemegang utama kami. Di dalam, tata letak dibagi menjadi beberapa bagian:

  • Logo (bagian statis)
  • Slideshow yang sebagian besar akan kami kerjakan
  • Info (bagian statis)
  • Navigasi penggeser yang akan menunjukkan slide yang sedang aktif serta jumlah total slide

Mari kita fokus pada bagian slideshow karena itulah yang menjadi perhatian kita dalam artikel ini. Di sini kita memiliki dua bagian— main dan aux . Main adalah div yang berisi gambar unggulan sementara aux memegang judul gambar. Struktur setiap slide di dalam dua dudukan ini cukup mendasar. Di sini kita memiliki slide gambar di dalam dudukan utama:

 <div class="slide" data-index="0"> <div class="abs-mask"> <div class="slide-image"> </div> </div> </div>

Atribut data indeks adalah apa yang akan kita gunakan untuk melacak di mana kita berada dalam tayangan slide. Div abs-mask yang akan kita gunakan untuk membuat efek transisi yang menarik dan div gambar slide berisi gambar unggulan tertentu. Gambar dirender sebaris seolah-olah berasal langsung dari CMS dan disetel oleh pengguna akhir.

Demikian pula, judul meluncur di dalam pemegang aux:

 <h2 class="slide-title slide" data-index="0"><a href="#">#64 Paradigm</a></h2>

Setiap judul slide adalah tag H2 dengan atribut data yang sesuai dan tautan untuk dapat mengarah ke satu halaman proyek itu.

Sisa HTML kami juga cukup mudah. Kami memiliki logo di bagian atas, info statis yang memberi tahu pengguna di halaman mana mereka berada, beberapa deskripsi, dan indikator slider saat ini/total.

Ikhtisar CSS

Kode CSS sumber ditulis dalam SCSS, pra-prosesor CSS yang kemudian dikompilasi menjadi CSS biasa yang dapat ditafsirkan oleh browser. SCSS memberi Anda keuntungan menggunakan variabel, pemilihan bersarang, mixin, dan hal-hal keren lainnya, tetapi SCSS perlu dikompilasi ke dalam CSS agar browser membaca kode sebagaimana mestinya. Untuk tujuan tutorial ini, saya telah menggunakan Scout-App untuk menangani kompilasi karena saya ingin memiliki perkakas minimal.

Saya menggunakan flexbox untuk menangani tata letak dasar berdampingan. Idenya adalah memiliki slideshow di satu sisi dan bagian info di sisi lain.

 #hero-slider { position: relative; height: 100vh; display: flex; background: $dark-color; } #slideshow { position: relative; flex: 1 1 $main-width; display: flex; align-items: flex-end; padding: $offset; } #info { position: relative; flex: 1 1 $side-width; padding: $offset; background-color: #fff; }

Mari selami pemosisian dan sekali lagi, fokus pada bagian tayangan slide:

 #slideshow { position: relative; flex: 1 1 $main-width; display: flex; align-items: flex-end; padding: $offset; } #slides-main { @extend %abs; &:after { content: ''; @extend %abs; background-color: rgba(0, 0, 0, .25); z-index: 100; } .slide-image { @extend %abs; background-position: center; background-size: cover; z-index: -1; } } #slides-aux { position: relative; top: 1.25rem; width: 100%; .slide-title { position: absolute; z-index: 300; font-size: 4vw; font-weight: 700; line-height: 1.3; @include outlined(#fff); } }

Saya telah mengatur slider utama untuk benar-benar diposisikan dan membuat gambar latar belakang meregangkan seluruh area dengan menggunakan properti background-size: cover . Untuk memberikan lebih banyak kontras terhadap judul slide, saya telah menetapkan elemen pseudo absolut yang bertindak sebagai overlay. Slider aux yang berisi judul slide diposisikan di bagian bawah layar dan di atas gambar.

Karena hanya satu slide yang akan terlihat pada satu waktu, saya mengatur setiap judul menjadi absolut juga, dan memiliki ukuran pemegang dihitung melalui JS untuk memastikan tidak ada cut-off, tetapi lebih lanjut tentang itu di salah satu bagian kami yang akan datang. Di sini Anda dapat melihat penggunaan fitur SCSS yang disebut memperluas:

 %abs { position: absolute; top: 0; left: 0; height: 100%; width: 100%; }

Karena saya sering menggunakan pemosisian absolut, saya menarik CSS ini menjadi dapat diperpanjang agar mudah tersedia di berbagai pemilih. Juga, saya membuat mixin yang disebut "diuraikan" untuk memberikan pendekatan KERING saat menata judul dan judul penggeser utama.

 @mixin outlined($color: $dark-color, $size: 1px) { color: transparent; -webkit-text-stroke: $size $color; }

Adapun bagian statis dari tata letak ini, tidak ada yang rumit tentangnya tetapi di sini Anda dapat melihat metode yang menarik ketika memposisikan teks yang harus berada di sumbu Y alih-alih aliran normalnya:

 .slider-title-wrapper { position: absolute; top: $offset; left: calc(100% - #{$offset}); transform-origin: 0% 0%; transform: rotate(90deg); @include outlined; }

Saya ingin menarik perhatian Anda pada properti transform-origin karena menurut saya properti ini kurang dimanfaatkan untuk jenis tata letak ini. Cara elemen ini diposisikan adalah bahwa jangkarnya tetap berada di sudut kiri atas elemen, mengatur titik rotasi dan membuat teks terus mengalir dari titik itu ke bawah tanpa masalah ketika menyangkut ukuran layar yang berbeda.

Mari kita lihat bagian CSS yang lebih menarik - animasi pemuatan awal:

Muat animasi untuk penggeser.

Biasanya, perilaku animasi yang disinkronkan semacam ini dicapai dengan menggunakan perpustakaan - GSAP, misalnya, adalah salah satu yang terbaik di luar sana, memberikan kemampuan rendering yang sangat baik, mudah digunakan, dan memiliki fungsionalitas garis waktu yang memungkinkan pengembang untuk merantai elemen secara terprogram transisi ke satu sama lain.

Namun, karena ini adalah contoh CSS/JS murni, saya memutuskan untuk benar-benar mendasar di sini. Jadi setiap elemen diatur ke posisi awal secara default-baik disembunyikan oleh transformasi atau opacity dan ditampilkan pada beban slider yang dipicu oleh JS kami. Semua properti transisi di-tweak secara manual untuk memastikan aliran alami dan menarik dengan setiap transisi berlanjut ke transisi lainnya memberikan pengalaman visual yang menyenangkan.

 #logo:after { transform: scaleY(0); transform-origin: 50% 0; transition: transform .35s $easing; } .logo-text { display: block; transform: translate3d(120%, 0, 0); opacity: 0; transition: transform .8s .2s, opacity .5s .2s; } .current, .sep:before { opacity: 0; transition: opacity .4s 1.3s; } #info { transform: translate3d(100%, 0, 0); transition: transform 1s $easing .6s; } .line { transform-origin: 0% 0; transform: scaleX(0); transition: transform .7s $easing 1s; } .slider-title { overflow: hidden; >span { display: block; transform: translate3d(0, -100%, 0); transition: transform .5s 1.5s; } }

Jika ada satu hal yang saya ingin Anda lihat di sini, itu adalah penggunaan properti transform . Saat memindahkan elemen HTML, apakah itu transisi atau animasi, disarankan untuk menggunakan properti transform . Saya melihat banyak orang yang cenderung menggunakan margin atau padding atau bahkan offset–atas, kiri, dll. yang tidak memberikan hasil yang memadai dalam hal rendering.

Untuk mendapatkan pemahaman yang lebih mendalam tentang cara menggunakan CSS saat menambahkan perilaku interaktif, saya tidak bisa merekomendasikan artikel berikut dengan cukup.

Ini oleh Paul Lewis, seorang insinyur Chrome, dan mencakup hampir semua yang harus diketahui tentang rendering piksel di web apakah itu CSS atau JS.

Ikhtisar JavaScript dan Logika Slider

File JavaScript dibagi menjadi dua fungsi yang berbeda.

Fungsi heroSlider yang menangani semua fungsi yang kita butuhkan di sini, dan fungsi utils di mana saya telah menambahkan beberapa fungsi utilitas yang dapat digunakan kembali. Saya telah mengomentari masing-masing fungsi utilitas ini untuk memberikan konteks jika Anda ingin menggunakannya kembali dalam proyek Anda.

Fungsi utama dikodekan sedemikian rupa sehingga memiliki dua cabang: init dan resize . Cabang-cabang ini tersedia melalui pengembalian fungsi utama dan dipanggil bila perlu. init adalah inisialisasi fungsi utama dan dipicu pada acara pemuatan jendela. Demikian pula, cabang pengubahan ukuran dipicu pada pengubahan ukuran jendela. Satu-satunya tujuan dari fungsi pengubahan ukuran adalah untuk menghitung ulang ukuran penggeser judul pada pengubahan ukuran jendela, karena ukuran font judul dapat bervariasi.

Dalam fungsi heroSlider , saya telah menyediakan objek slider yang berisi semua data dan pemilih yang kita perlukan:

 const slider = { hero: document.querySelector('#hero-slider'), main: document.querySelector('#slides-main'), aux: document.querySelector('#slides-aux'), current: document.querySelector('#slider-nav .current'), handle: null, idle: true, activeIndex: -1, interval: 3500 };

Sebagai catatan tambahan, pendekatan ini dapat dengan mudah diadaptasi jika Anda misalnya menggunakan React, karena Anda dapat menyimpan data dalam status atau menggunakan kait yang baru ditambahkan. Untuk tetap pada intinya, mari kita lihat apa yang diwakili oleh masing-masing pasangan nilai kunci di sini:

  • Empat properti pertama adalah referensi HTML ke elemen DOM yang akan kita manipulasi.
  • Properti handle akan digunakan untuk memulai dan menghentikan fungsionalitas putar otomatis.
  • Properti idle adalah flag yang akan mencegah pengguna untuk memaksa menggulir saat slide dalam transisi.
  • activeIndex akan memungkinkan kita untuk melacak slide yang sedang aktif
  • interval menunjukkan interval putar otomatis slider

Setelah inisialisasi slider, kami memanggil dua fungsi:

 setHeight(slider.aux, slider.aux.querySelectorAll('.slide-title')); loadingAnimation();

Fungsi setHeight menjangkau fungsi utilitas untuk mengatur ketinggian aux slider kami berdasarkan ukuran judul maksimum. Dengan cara ini kami memastikan bahwa ukuran yang memadai disediakan dan tidak ada judul slide yang akan terpotong bahkan ketika isinya turun menjadi dua baris.

fungsi loadingAnimation menambahkan kelas CSS ke elemen yang menyediakan transisi CSS intro:

 const loadingAnimation = function () { slider.hero.classList.add('ready'); slider.current.addEventListener('transitionend', start, { once: true }); }

Karena indikator penggeser kami adalah elemen terakhir dalam garis waktu transisi CSS, kami menunggu transisinya berakhir dan menjalankan fungsi mulai. Dengan memberikan parameter tambahan sebagai objek, kami memastikan bahwa ini dipicu hanya sekali.

Mari kita lihat fungsi start:

 const start = function () { autoplay(true); wheelControl(); window.innerWidth <= 1024 && touchControl(); slider.aux.addEventListener('transitionend', loaded, { once: true }); }

Jadi ketika tata letak selesai, transisi awalnya dipicu oleh fungsi loadingAnimation dan fungsi start mengambil alih. Ini kemudian memicu fungsionalitas putar otomatis, mengaktifkan kontrol roda, menentukan apakah kita menggunakan perangkat sentuh atau desktop, dan menunggu transisi judul slide pertama untuk menambahkan kelas CSS yang sesuai.

Putar otomatis

Salah satu fitur inti dalam tata letak ini adalah fitur putar otomatis. Mari kita membahas fungsi yang sesuai:

 const autoplay = function (initial) { slider.autoplay = true; slider.items = slider.hero.querySelectorAll('[data-index]'); slider.total = slider.items.length / 2; const loop = () => changeSlide('next'); initial && requestAnimationFrame(loop); slider.handle = utils().requestInterval(loop, slider.interval); }

Pertama, kami menyetel tanda putar otomatis ke true, yang menunjukkan bahwa penggeser dalam mode putar otomatis. Tanda ini berguna saat menentukan apakah akan memicu kembali putar otomatis setelah pengguna berinteraksi dengan penggeser. Kami kemudian mereferensikan semua item penggeser (slide), karena kami akan mengubah kelas aktifnya dan menghitung total iterasi yang akan dimiliki penggeser dengan menambahkan semua item dan membaginya dengan dua karena kami memiliki dua tata letak penggeser yang disinkronkan (utama dan aux) tetapi hanya satu "penggeser" yang mengubah keduanya secara bersamaan.

Bagian yang paling menarik dari kode di sini adalah fungsi loop. Ini memanggil slideChange , memberikan arah slide yang akan kita bahas dalam satu menit, namun, fungsi loop dipanggil beberapa kali. Mari kita lihat mengapa.

Jika argumen awal dievaluasi sebagai benar, kita akan memanggil fungsi loop sebagai callback requestAnimationFrame . Ini hanya terjadi pada pemuatan slider pertama yang memicu perubahan slide langsung. Dengan menggunakan requestAnimationFrame , kami menjalankan panggilan balik yang disediakan tepat sebelum pengecatan ulang bingkai berikutnya.

Diagram langkah-langkah yang digunakan untuk membuat slider.

Namun, karena kami ingin terus menelusuri slide dalam mode putar otomatis, kami akan menggunakan panggilan berulang dari fungsi yang sama ini. Ini biasanya dicapai dengan setInterval. Namun dalam kasus ini, kita akan menggunakan salah satu fungsi utilitas– requestInterval . Sementara setInterval akan bekerja dengan baik, requestInterval adalah konsep lanjutan yang bergantung pada requestAnimationFrame dan menyediakan pendekatan yang lebih berkinerja. Ini memastikan bahwa fungsi dipicu kembali hanya jika tab browser aktif.

Lebih lanjut tentang konsep ini dalam artikel yang luar biasa ini dapat ditemukan di trik CSS. Harap dicatat bahwa kami menetapkan nilai pengembalian dari fungsi ini ke properti slider.handle kami. ID unik yang dikembalikan fungsi ini tersedia bagi kami dan kami akan menggunakannya untuk membatalkan putar otomatis nanti menggunakan cancelAnimationFrame .

Perubahan Geser

Fungsi slideChange adalah fungsi utama dalam keseluruhan konsep. Itu mengubah slide apakah itu dengan putar otomatis atau oleh pemicu pengguna. Ini menyadari arah penggeser, menyediakan perulangan sehingga ketika Anda sampai pada slide terakhir Anda akan dapat melanjutkan ke slide pertama. Inilah cara saya mengkodekannya:

 const changeSlide = function (direction) { slider.idle = false; slider.hero.classList.remove('prev', 'next'); if (direction == 'next') { slider.activeIndex = (slider.activeIndex + 1) % slider.total; slider.hero.classList.add('next'); } else { slider.activeIndex = (slider.activeIndex - 1 + slider.total) % slider.total; slider.hero.classList.add('prev'); } //reset classes utils().removeClasses(slider.items, ['prev', 'active']); //set prev const prevItems = [...slider.items] .filter(item => { let prevIndex; if (slider.hero.classList.contains('prev')) { prevIndex = slider.activeIndex == slider.total - 1 ? 0 : slider.activeIndex + 1; } else { prevIndex = slider.activeIndex == 0 ? slider.total - 1 : slider.activeIndex - 1; } return item.dataset.index == prevIndex; }); //set active const activeItems = [...slider.items] .filter(item => { return item.dataset.index == slider.activeIndex; }); utils().addClasses(prevItems, ['prev']); utils().addClasses(activeItems, ['active']); setCurrent(); const activeImageItem = slider.main.querySelector('.active'); activeImageItem.addEventListener('transitionend', waitForIdle, { once: true }); }

Idenya adalah untuk menentukan slide aktif berdasarkan indeks data yang kami dapatkan dari HTML. Mari kita bahas setiap langkah:

  1. Setel bendera idle penggeser ke false. Ini menunjukkan bahwa perubahan slide sedang berlangsung dan gerakan roda dan sentuh dinonaktifkan.
  2. Kelas CSS arah slider sebelumnya akan diatur ulang dan kami memeriksa yang baru. Parameter arah disediakan baik secara default sebagai 'berikutnya' jika kita berasal dari fungsi putar otomatis atau oleh fungsi yang dipanggil pengguna– wheelControl atau touchControl .
  3. Berdasarkan arah, kami menghitung indeks slide aktif dan memberikan arah kelas CSS saat ini ke slider. Class CSS ini digunakan untuk menentukan efek transisi yang akan digunakan (misalnya kanan ke kiri atau kiri ke kanan)
  4. Slide mendapatkan reset kelas CSS "status" (sebelumnya, aktif) menggunakan fungsi utilitas lain yang menghapus kelas CSS tetapi dapat dipanggil pada NodeList, bukan hanya elemen DOM tunggal. Setelah itu, hanya slide sebelumnya dan saat ini yang aktif yang menambahkan kelas CSS tersebut ke dalamnya. Hal ini memungkinkan CSS untuk menargetkan hanya slide tersebut dan menyediakan transisi yang memadai.
  5. setCurrent adalah panggilan balik yang memperbarui indikator slider berdasarkan indeks aktif.
  6. Terakhir, kami menunggu transisi dari slide gambar aktif berakhir untuk memicu panggilan balik waitForIdle yang memulai ulang putar otomatis jika sebelumnya terganggu oleh pengguna.

Kontrol Pengguna

Berdasarkan ukuran layar, saya telah menambahkan dua jenis kontrol pengguna–roda dan sentuh. Kontrol roda:

 const wheelControl = function () { slider.hero.addEventListener('wheel', e => { if (slider.idle) { const direction = e.deltaY > 0 ? 'next' : 'prev'; stopAutoplay(); changeSlide(direction); } }); }

Di sini, kami mendengarkan roda genap dan jika penggeser saat ini dalam mode siaga (saat ini tidak menganimasikan perubahan slide), kami menentukan arah roda, memanggil stopAutoplay untuk menghentikan fungsi putar otomatis jika sedang berlangsung, dan mengubah slide berdasarkan arah. Fungsi stopAutoplay tidak lain adalah fungsi sederhana yang menyetel tanda putar otomatis kita ke nilai salah dan membatalkan interval kita dengan menjalankan fungsi utilitas cancelRequestInterval dengan meneruskannya ke pegangan yang sesuai:

 const stopAutoplay = function () { slider.autoplay = false; utils().clearRequestInterval(slider.handle); }

Mirip dengan wheelControl , kami memiliki touchControl yang menangani gerakan sentuh:

 const touchControl = function () { const touchStart = function (e) { slider.ts = parseInt(e.changedTouches[0].clientX); window.scrollTop = 0; } const touchMove = function (e) { slider.tm = parseInt(e.changedTouches[0].clientX); const delta = slider.tm - slider.ts; window.scrollTop = 0; if (slider.idle) { const direction = delta < 0 ? 'next' : 'prev'; stopAutoplay(); changeSlide(direction); } } slider.hero.addEventListener('touchstart', touchStart); slider.hero.addEventListener('touchmove', touchMove); }

Kami mendengarkan dua acara: touchstart dan touchmove . Kemudian kita hitung selisihnya. Jika mengembalikan nilai negatif, kami mengubah ke slide berikutnya saat pengguna telah menggeser dari kanan ke kiri. Di sisi lain, jika nilainya positif, artinya pengguna telah menggeser dari kiri ke kanan, kami memicu slideChange dengan arah yang diteruskan sebagai "sebelumnya." Dalam kedua kasus, fungsi putar otomatis dihentikan.

Ini adalah implementasi gerakan pengguna yang cukup sederhana. Untuk membangun ini, kita bisa menambahkan tombol sebelumnya/berikutnya untuk memicu slideChange saat klik atau menambahkan daftar berpoin untuk langsung menuju slide berdasarkan indeksnya.

Penutup dan Pemikiran Terakhir tentang CSS

Jadi begitulah, cara CSS/JS murni untuk mengkodekan tata letak slider non-standar dengan efek transisi modern.

Saya harap Anda menemukan pendekatan ini berguna sebagai cara berpikir dan dapat menggunakan sesuatu yang serupa di proyek front-end Anda saat membuat kode untuk proyek yang belum tentu dirancang secara konvensional.

Bagi Anda yang tertarik dengan efek transisi gambar, saya akan membahas ini dalam beberapa baris berikutnya.

Jika kita meninjau kembali struktur HTML slide yang saya berikan di bagian intro, kita akan melihat bahwa setiap slide gambar memiliki div di sekitarnya dengan kelas CSS abs-mask . Apa yang dilakukan div ini adalah menyembunyikan sebagian gambar yang terlihat dengan jumlah tertentu dengan menggunakan overflow:hidden dan mengimbanginya ke arah yang berbeda dari gambar. Misalnya, jika kita melihat cara pengkodean slide sebelumnya:

 &.prev { z-index: 5; transform: translate3d(-100%, 0, 0); transition: 1s $easing; .abs-mask { transform: translateX(80%); transition: 1s $easing; } }

Slide sebelumnya memiliki offset -100% pada sumbu X-nya, memindahkannya ke kiri slide saat ini, namun, div abs-mask bagian dalam diterjemahkan 80% ke kanan, memberikan viewport yang lebih sempit. Ini, dalam kombinasi dengan memiliki indeks-z yang lebih besar untuk hasil slide aktif dalam semacam efek sampul—gambar aktif menutupi gambar sebelumnya sementara pada saat yang sama memperluas area yang terlihat dengan menggerakkan topeng yang memberikan tampilan penuh.