Saya selalu terpesona dengan banyaknya pencapaian luar biasa yang dapat kami capai hanya dengan menggunakan HTML dan CSS. Fitur interaktif baru di Popover API adalah contoh lain seberapa banyak yang dapat kami capai hanya dengan menggunakan dua bahasa ini.
Anda mungkin pernah melihat tutorial lain yang menunjukkan apa yang dapat dilakukan Popover API, tetapi artikel ini membahas tentang cara menundukkannya tanpa ampun. Kami akan menambahkan lebih banyak <>Pop> musik Untuk campurannya, seperti halnya balon… beberapa “letupan” literal jika Anda mau.
-Advertisement-.
Saya telah membuat game – tentu saja hanya menggunakan HTML dan CSS – berdasarkan API Popover. Misi Anda adalah meletuskan balon sebanyak mungkin dalam waktu kurang dari satu menit. Tapi hati-hati! Beberapa balon (seperti yang dikatakan Gollum) “rumit” dan menyebabkan lebih banyak balon meledak.
Saya menyebutnya pintar Meledakkan balon Kami akan melakukannya bersama-sama, langkah demi langkah. Dan ketika kita selesai melakukannya, akan terlihat seperti ini (yah, <>tepat> Seperti dia:
menghadapi popover
menjelaskan
Elemen apa pun bisa menjadi popup selama kita mendesainnya popover
Menjelaskan:
<div popover>...</div>
Kami bahkan tidak perlu menyediakannya popover
Dengan nilai. Secara default, popover
Nilai awalnya adalah auto
Mereka menggunakan apa yang disebut dalam spesifikasi “penutupan cepat”. Ini berarti jendela pop-up dapat ditutup dengan mengklik di mana saja di luarnya. Saat jendela pop-up terbuka, kecuali jika disarangkan, jendela pop-up lain di halaman tersebut akan ditutup. Popup otomatis saling berhubungan seperti ini.
Pilihan lainnya adalah penyetelan popover
ke manual
nilai:
<div popover=“manual”>...</div>
…yang berarti item tersebut dibuka dan ditutup secara manual — kita sebenarnya harus mengklik tombol tertentu untuk membuka dan menutupnya. Dengan kata lain, manual
Ini menciptakan popup yang mengganggu yang hanya menutup ketika tombol yang benar ditekan dan benar-benar independen dari popup lain di halaman.
Menggunakan <details>
Item sebagai permulaan
Salah satu tantangan dalam membuat game menggunakan Popover API adalah Anda tidak dapat memuat halaman dengan popover yang sudah terbuka… dan tidak ada solusi lain dengan JavaScript jika tujuan kami adalah membuat game hanya menggunakan HTML dan CSS .
Memasuki <details>
Barang. Berbeda dengan jendela pop-up, <details>
Item dapat dibuka secara default:
<details open>
<!-- rest of the game -->
</details>
Jika kita mengikuti jalur ini, kita akan dapat memunculkan sekumpulan tombol (balon) dan “membukanya” hingga balon terakhir dengan menutupnya. <details>
Dengan kata lain, kita bisa menempatkan balon awal di ruang terbuka. <details>
Item ditampilkan di halaman saat dimuat.
Ini adalah struktur dasar yang saya bicarakan:
<details open>
<summary>🎈</summary>
<button>🎈</button>
<button>🎈</button>
<button>🎈</button>
</details>
Dengan cara ini, kita bisa mengklik balon yang terletak di dalamnya <summary>
Untuk menutup <details>
dan “meletuskan” semua balon kancing, meninggalkan kita dengan satu balon ( <summary>
Terakhir (kami akan menyelesaikan cara menghapusnya nanti).
Mungkin Anda berpikir begitu <dialog>
Ini akan menjadi arah yang lebih indikatif untuk permainan kami, dan Anda benar. Tapi ada dua kelemahannya <dialog>
Ini tidak memungkinkan kami menggunakannya di sini:
- Satu-satunya cara untuk menutup
<dialog>
Yang terbuka saat halaman dimuat adalah JavaScript. Sejauh yang saya tahu, tidak ada penutupan<button>
Kita bisa terjerumus ke dalam permainan yang akan ditutup<dialog>
Ini tidak terkunci setelah diunduh. <dialog>
Ini bersifat modular dan mencegah mengklik hal lain saat terbuka. Kita harus membiarkan pemain meniup balonnya<dialog>
Untuk mengatasi sementara.
Oleh karena itu kami akan menggunakan <details
open>
Item sebagai wadah tingkat atas game dan gunakan bentuk normal <div>
Adapun popup itu sendiri <div popover>
.
Yang perlu kita lakukan sekarang adalah memastikan semua popup dan tombol ini terhubung bersama sehingga mengklik tombol tersebut akan membuka popup. Anda mungkin telah mempelajari hal ini dari tutorial lain, namun kita perlu memberi tahu elemen popup bahwa ada tombol yang perlu ditanggapi, lalu memberi tahu tombol tersebut bahwa ada popup yang perlu dibuka. Untuk melakukan ini, kami memberikan elemen popup sebuah pengidentifikasi unik (sebagaimana seharusnya semua pengidentifikasi) dan kemudian mengarahkannya ke <button>
dengan popovertarget
Menjelaskan:
<!-- Level 0 is open by default -->
<details open>
<summary>🎈</summary>
<button popovertarget="lvl1">🎈</button>
</details>
<!-- Level 1 -->
<div id="lvl1" popover="manual">
<h2>Level 1 Popup</h2>
</div>
Inilah gagasan ketika semuanya terikat menjadi satu:
Buka dan tutup jendela pop-up
Ada sedikit pekerjaan yang harus dilakukan pada versi beta terbaru. Salah satu kelemahan dari permainan ini sejauh ini adalah kliknya <button>
Dari a popup
Membuka lebih banyak pop-up; Klik pada jendela yang sama <button>
lagi dan mereka menghilang. Ini membuat permainan menjadi sangat mudah.
Kita dapat memisahkan perilaku membuka dan menutup dengan melakukan penyesuaian popovertargetaction
atribut (tidak, penulis spesifikasi HTML tidak peduli dengan singkatnya) aktif <button>
Jika kita menetapkan nilai atribut ke salah satu dari show
atau hide
itu <button>
Tindakan ini hanya akan dilakukan untuk popup tertentu.
<!-- Level 0 is open by default -->
<details open>
<summary>🎈</summary>
<!-- Show Level 1 Popup -->
<button popovertarget="lvl1" popovertargetaction="show">🎈</button>
<!-- Hide Level 1 Popup -->
<button popovertarget="lvl1" popovertargetaction="hide">🎈</button>
</details>
<!-- Level 1 -->
<div id="lvl1" popover="manual">
<h2>Level 1 Popup</h2>
<!-- Open/Close Level 2 Poppup -->
<button popovertarget="lvl2">🎈</button>
</div>
<!-- etc. -->
Perhatikan saya menambahkan yang baru <button>
di dalam <div>
Yang diatur untuk menargetkan yang lain <div>
Membuka atau menutup dengan sengaja <>TIDAK> menyesuaikan popovertargetaction
Lihatlah betapa sulitnya “mengeluarkan” barang (dengan cara yang baik):
Penataan balon
Sekarang kita perlu mendesain <summary>
Dan <button>
Item-itemnya sangat mirip sehingga pemain tidak dapat membedakannya. Perhatikan kataku <summary>
Dan <>TIDAK> <details>
hal ini dikarenakan <summary>
Ini adalah elemen sebenarnya yang kita klik untuk membuka dan menutup <details>
wadah.
Sebagian besar pekerjaan ini merupakan pekerjaan CSS standar: menyesuaikan latar belakang, padding, margin, ukuran, batas, dll. Namun ada beberapa hal penting, dan belum tentu jelas, yang perlu disertakan.
- Pertama, ada kontrol
list-style-type
properti untuknone
pada<summary>
Elemen untuk menghilangkan tanda segitiga yang menunjukkan apakah<details>
Terbuka atau tertutup. Bendera ini sangat berguna dan bagus untuk memilikinya di sana secara default, tetapi untuk permainan seperti ini, akan lebih baik untuk menghapus petunjuk ini untuk tantangan yang lebih baik. - Safari tidak menyukai pendekatan yang sama. untuk menghapus
<details>
Tag di sini, kita perlu menyetel elemen dummy khusus dengan awalan vendor,summary::-webkit-details-marker
kedisplay: none
. - Alangkah baiknya jika penunjuk mouse menunjukkan bahwa balon tersebut dapat diklik, sehingga kita dapat menyesuaikannya
cursor: pointer
pada<summary>
Barang juga. - Detail terakhir adalah penyetelan
user-select
properti untuknone
pada<summary>
Untuk mencegah pemilihan balon — yang hanya berupa teks ekspresif — menjadikannya lebih seperti objek di halaman. - Dan ya, ini tahun 2024 dan kami masih membutuhkan awalan itu
-webkit-user-select
Fitur untuk mendukung Safari. Terima kasih apel.
Masukkan semuanya ke dalam kode .balloon
Baris yang akan kita gunakan <button>
Dan <summary>
Elemen:
.balloon {
background-color: transparent;
border: none;
cursor: pointer;
display: block;
font-size: 4em;
height: 1em;
list-style-type: none;
margin: 0;
padding: 0;
text-align: center;
-webkit-user-select: none; /* Safari fallback */
user-select: none;
width: 1em;
}
Satu masalah dengan balon adalah beberapa di antaranya… <>dengan sengaja> Jangan melakukan apa pun. Ini karena pop-up yang Anda tutup tidak terbuka. Pemain mungkin berpikir mereka tidak mengklik/mengetuk balon tertentu atau permainannya rusak, jadi mari tambahkan sedikit gradien saat balon berada di tempatnya. :active
Status klik:
.balloon:active {
scale: 0.7;
transition: 0.5s;
}
Bonusnya: Karena cursor
Itu adalah tangan yang menunjuk dengan jari telunjuknya, mengetuk balon, dan seolah-olah tangan tersebut mendorong balon dengan jarinya. 👉🎈💥
Cara kami mendistribusikan balon di sekitar layar adalah hal penting lainnya yang perlu dipertimbangkan. Kami tidak dapat mengacaknya tanpa JavaScript, jadi itu tidak mungkin. Saya telah mencoba banyak hal, seperti membuat angka “acak” sendiri yang didefinisikan sebagai properti khusus yang dapat digunakan sebagai pengganda, tetapi saya belum bisa mendapatkan hasil keseluruhan agar terlihat sepenuhnya “acak” tanpa tumpang tindih balon atau membuat semacam pola visual.
Saya akhirnya menemukan cara yang menggunakan kelas untuk menempatkan balon ke dalam baris dan kolom yang berbeda — tidak seperti Grid CSS atau Multikolom, tetapi baris dan kolom tiruan berdasarkan masukan fisik. Ini akan terlihat lebih mirip Grid dan menjadi kurang “acak” daripada yang saya inginkan, tapi selama tidak ada balon yang memiliki dua kategori yang sama, mereka tidak akan saling mengganggu.
Saya memutuskan untuk menggunakan kisi 8 x 8 tetapi membiarkan “baris” dan “kolom” pertama kosong sehingga balon terlihat jelas di tepi kiri dan atas browser.
/* Rows */
.r1 { --row: 1; }
.r2 { --row: 2; }
/* all the way up to .r7 */
/* Columns */
.c1 { --col: 1; }
.c2 { --col: 2; }
/* all the way up to .c7 */
.balloon {
/* This is how they're placed using the rows and columns */
top: calc(12.5vh * (var(--row) + 1) - 12.5vh);
left: calc(12.5vw * (var(--col) + 1) - 12.5vw);
}
Memberi selamat kepada pemain (atau tidak memberi selamat kepada pemain)
Kami sudah memiliki sebagian besar potongan permainan, tapi akan menyenangkan jika bisa meraih kemenangan menari Muncul pesan pop-up untuk memberi selamat kepada pemain ketika mereka berhasil meletuskan semua balon dalam waktu yang ditentukan.
Semuanya kembali ke <details
open>
Barang. Setelah item ini menjadi… <>TIDAK> open
Permainan harus diakhiri dengan langkah terakhir yaitu meledakkan balon terakhir. Jadi, jika kita memberi elemen ini sebuah pengenal, misalnya, #root
Kita dapat membuat kondisi untuk menyembunyikannya menggunakan display: none
Kapan itu terjadi :not()
di dalam open
negara:
#root:not([open]) {
display: none;
}
Itu adalah tempat terbaik yang kami miliki :has()
Pembatas semu karena kita dapat menggunakannya untuk menentukan #root
Elemen utama dari elemen tersebut sehingga kapan #root
Jika elemennya tertutup, kita dapat mendefinisikan elemen anak dari elemen induknya — elemen baru dengan ID #congrats
– Untuk menampilkan jendela pop-up palsu yang menampilkan pesan ucapan selamat kepada pemain. (Ya, saya menyadari ironi ini.)
#game:has(#root:not([open])) #congrats {
display: flex;
}
Jika kita memainkan permainan ini pada titik ini, kita dapat menerima pesan kemenangan tanpa harus meledakkan semua balonnya. Sekali lagi, popup tidak akan ditutup secara manual kecuali tombol yang benar diklik — meskipun kita menutup tombol aslinya <details>
komponen.
Apakah ada cara dalam CSS untuk mengetahui apakah popup masih terbuka? Ya, masuk :popover-open
Kelas semu.
itu :popover-open
Kelas semu memilih jendela popup yang terbuka. Kita bisa menggunakannya dengan :has()
Sebelumnya untuk mencegah pesan muncul jika jendela pop-up masih terbuka di halaman. Beginilah cara menghubungkan hal-hal ini bersama-sama and
klausa bersyarat.
/* If #game does *not* have an open #root
* but has an element with an open popover
* (i.e. the game isn't over),
* then select the #congrats element...
*/
#game:has(#root:not([open])):has(:popover-open) #congrats {
/* ...and hide it */
display: none;
}
Sekarang, seorang pemain hanya diberi ucapan selamat ketika dia, lho, melakukan sesuatu. <>menang>.
Sebaliknya, jika pemain tidak dapat meletuskan semua balon sebelum batas waktu habis, maka kita harus memberitahukan pemain tersebut bahwa permainan telah selesai. Karena tidak ada waktu tertentu, if()
Jika tidak ada pernyataan kondisional di CSS (setidaknya belum) kami akan memutar animasi 1 menit hingga pesan ini menghilang untuk mengakhiri permainan.
#fail {
animation: fadein 0.5s forwards 60s;
display: flex;
opacity: 0;
z-index: -1;
}
@keyframes fadein {
0% {
opacity: 0;
z-index: -1;
}
100% {
opacity: 1;
z-index: 10;
}
}
Namun kita tidak ingin pesan kegagalan muncul jika layar kemenangan ditampilkan, sehingga kita dapat menulis pemilih blok #fail
Pesan dari tampilan pada saat yang sama #congrats
pesan.
#game:has(#root:not([open])) #fail {
display: none;
}
Kami membutuhkan pengatur waktu permainan
Pemain harus mengetahui berapa lama waktu yang dimilikinya untuk meletuskan semua balon. Kita dapat membuat pengatur waktu yang cukup “sederhana” menggunakan elemen yang memenuhi seluruh lebar layar (100vw
), skalakan ke arah horizontal, lalu cocokkan dengan animasi di atas yang memungkinkan hal ini #fail
Pesan memudar.
#timer {
width: 100vw;
height: 1em;
}
#bar {
animation: 60s timebar forwards;
background-color: #e60b0b;
width: 100vw;
height: 1em;
transform-origin: right;
}
@keyframes timebar {
0% {
scale: 1 1;
}
100% {
scale: 0 1;
}
}
Memiliki satu titik kegagalan saja mungkin membuat permainan sedikit lebih mudah, jadi mari kita coba menambahkan titik kegagalan kedua <details>
Elemen yang berisi pengidentifikasi “root” kedua, #root2
Sekali lagi, kita bisa menggunakannya :has
Untuk memastikan tidak ada keduanya #root
TIDAK #root2
Unsur-unsurnya adalah open
Sebelum tawaran #congrats
pesan.
#game:has(#root:not([open])):has(#root2:not([open])) #congrats {
display: flex;
}
kesimpulan
Satu-satunya hal yang perlu dilakukan adalah memainkan permainannya!
Menyenangkan, bukan? Saya yakin kami dapat membangun sesuatu yang lebih kuat tanpa batasan yang dibuat sendiri dengan pendekatan bebas JavaScript, dan bukan berarti kami memberikan izin aksesibilitas dengan itikad baik, namun mendorong API hingga batasnya adalah hal yang menyenangkan. <>Dan> Mendidik, bukan?
Saya tertarik: Ide aneh apa lagi yang dapat Anda pikirkan untuk menggunakan popup? Mungkin Anda memikirkan permainan lain, beberapa efek UI yang bagus, atau cara cerdas untuk menggabungkan popup dengan fitur CSS baru lainnya, seperti penempatan jangkar. Apa pun pendapat Anda, silakan bagikan!
Pop(over) the Balloons awalnya diterbitkan di CSS-Tricks, bagian dari keluarga DigitalOcean. Anda harus mendapatkan buletin.