Ringkasan dasar tentang cara membuat komponen setelan penggeser dan kotak centang.
Dalam postingan ini, saya ingin membagikan pemikiran tentang cara membuat komponen Setelan untuk web yang responsif, mendukung beberapa input perangkat, dan berfungsi di seluruh browser. Coba demo.
Jika Anda lebih suka video, atau menginginkan pratinjau UI/UX dari yang kita buat, berikut panduan singkat di YouTube:
Ringkasan
Saya telah membagi aspek komponen ini ke dalam bagian berikut:
- Tata Letak
- Warna
- Input rentang kustom
- Input kotak centang kustom
- Pertimbangan aksesibilitas
- JavaScript
Tata letak
Ini adalah demo Tantangan GUI pertama yang menjadi semua Petak CSS! Berikut setiap petak yang ditandai dengan Chrome DevTools untuk petak:
Hanya untuk celah
Tata letak yang paling umum:
foo {
display: grid;
gap: var(--something);
}
Saya menyebut tata letak ini "hanya untuk celah" karena hanya menggunakan petak untuk menambahkan celah di antara blok.
Lima tata letak menggunakan strategi ini, berikut adalah semua tata letak yang ditampilkan:
Elemen fieldset
, yang berisi setiap grup input (.fieldset-item
), menggunakan gap: 1px
untuk
membuat batas garis halus antarelemen. Tidak ada solusi batas yang rumit.
.grid { display: grid; gap: 1px; background: var(--bg-surface-1); & > .fieldset-item { background: var(--bg-surface-2); } }
.grid { display: grid; & > .fieldset-item { background: var(--bg-surface-2); &:not(:last-child) { border-bottom: 1px solid var(--bg-surface-1); } } }
Penggabungan petak alami
Tata letak yang paling kompleks akhirnya menjadi tata letak makro, sistem tata letak
logis antara <main>
dan <form>
.
Memusatkan konten penggabungan
Flexbox dan petak memberikan kemampuan ke align-items
atau
align-content
, dan saat menangani elemen penggabungan, perataan
tata letak content
akan mendistribusikan ruang di antara turunan sebagai grup.
main {
display: grid;
gap: var(--space-xl);
place-content: center;
}
Elemen utama menggunakan singkatan
perataan place-content: center
sehingga
turunan dipusatkan secara vertikal dan horizontal dalam tata letak satu dan dua kolom.
Tonton video di atas untuk melihat cara "konten" tetap berada di tengah, meskipun penggabungan telah terjadi.
Mengulangi minmax penyesuaian otomatis
<form>
menggunakan tata letak petak adaptif untuk setiap bagian.
Tata letak ini beralih dari satu menjadi dua kolom berdasarkan ruang yang tersedia.
form {
display: grid;
gap: var(--space-xl) var(--space-xxl);
grid-template-columns: repeat(auto-fit, minmax(min(10ch, 100%), 35ch));
align-items: flex-start;
max-width: 89vw;
}
Petak ini memiliki nilai yang berbeda untuk row-gap
(--space-xl) daripada column-gap
(--space-xxl)
untuk menempatkan sentuhan kustom tersebut pada tata letak responsif. Saat kolom ditumpuk, kita
ingin memiliki celah yang besar, tetapi tidak sebesar jika kita menggunakan layar lebar.
Properti grid-template-columns
menggunakan 3 fungsi CSS: repeat()
, minmax()
, dan
min()
. Una Kravets memiliki postingan blog tentang
tata letak yang bagus tentang hal ini, yang ia sebut
RAM.
Ada 3 tambahan khusus dalam tata letak kami, jika Anda membandingkannya dengan tata letak Una:
- Kita meneruskan fungsi
min()
tambahan. - Kita menentukan
align-items: flex-start
. - Ada gaya
max-width: 89vw
.
Fungsi min()
tambahan dijelaskan dengan baik oleh Evan Minto di blognya dalam
postingan Petak CSS Responsif Secara Intrinsik dengan minmax() dan
min().
Sebaiknya baca postingan tersebut. Koreksi perataan flex-start
adalah
menghapus efek peregangan default, sehingga turunan tata letak ini tidak
perlu memiliki tinggi yang sama, dan dapat memiliki ketinggian intrinsik yang alami. Video
YouTube memiliki perincian singkat tentang penambahan penyelarasan ini.
max-width: 89vw
layak untuk dibahas secara singkat dalam postingan ini.
Mari kita lihat tata letak dengan dan tanpa gaya yang diterapkan:
Apa yang terjadi? Saat ditentukan, max-width
akan memberikan konteks,
pengukuran eksplisit, atau pengukuran
pasti untuk algoritma
tata letak auto-fit
guna mengetahui
jumlah pengulangan yang dapat sesuai dengan ruang. Meskipun tampaknya jelas bahwa
ruang adalah "lebar penuh", sesuai dengan spesifikasi petak CSS, ukuran pasti atau ukuran maksimum harus
disediakan. Saya telah memberikan ukuran maksimum.
Jadi, mengapa 89vw
? Karena "berhasil" untuk tata letak saya.
Saya dan beberapa orang Chrome lainnya sedang menyelidiki mengapa nilai yang lebih wajar,
seperti 100vw
, tidak memadai, dan apakah ini sebenarnya merupakan bug.
Spasi
Sebagian besar harmoni tata letak ini berasal dari palet spasi yang terbatas, tepatnya 7.
:root {
--space-xxs: .25rem;
--space-xs: .5rem;
--space-sm: 1rem;
--space-md: 1.5rem;
--space-lg: 2rem;
--space-xl: 3rem;
--space-xxl: 6rem;
}
Penggunaan alur ini sangat cocok dengan petak, CSS @nest, dan sintaksis level 5 @media. Berikut adalah contoh, kumpulan gaya tata letak <main>
yang lengkap.
main {
display: grid;
gap: var(--space-xl);
place-content: center;
padding: var(--space-sm);
@media (width >= 540px) {
& {
padding: var(--space-lg);
}
}
@media (width >= 800px) {
& {
padding: var(--space-xl);
}
}
}
Petak dengan konten yang berada di tengah, dengan padding yang cukup secara default (seperti di perangkat seluler). Namun, dengan bertambahnya ruang area tampilan, area akan menyebar dengan meningkatkan padding. CSS 2021 terlihat cukup bagus!
Ingat tata letak sebelumnya, "hanya untuk celah"? Berikut adalah versi yang lebih lengkap tentang tampilannya dalam komponen ini:
header {
display: grid;
gap: var(--space-xxs);
}
section {
display: grid;
gap: var(--space-md);
}
Warna
Penggunaan warna yang terkontrol membantu desain ini tampil beda karena ekspresif sekaligus minimal. Saya melakukannya seperti ini:
:root {
--surface1: lch(10 0 0);
--surface2: lch(15 0 0);
--surface3: lch(20 0 0);
--surface4: lch(25 0 0);
--text1: lch(95 0 0);
--text2: lch(75 0 0);
}
Saya memberi nama warna permukaan dan teks dengan angka, bukan nama seperti
surface-dark
dan surface-darker
karena dalam kueri media, saya akan membalik
warna tersebut, dan terang serta gelap tidak akan bermakna.
Saya membaliknya dalam kueri media preferensi seperti ini:
:root {
...
@media (prefers-color-scheme: light) {
& {
--surface1: lch(90 0 0);
--surface2: lch(100 0 0);
--surface3: lch(98 0 0);
--surface4: lch(85 0 0);
--text1: lch(20 0 0);
--text2: lch(40 0 0);
}
}
}
Penting untuk melihat sekilas gambaran dan strategi secara keseluruhan sebelum kita membahas detail sintaksis warna. Namun, karena saya sudah terlalu jauh, mari kita kembali ke awal.
LCH?
Tanpa terlalu mendalami konsep warna, LCH adalah sintaksis berorientasi manusia, yang mengakomodasi cara kita memandang warna, bukan cara mengukur warna dengan matematika (seperti 255). Hal ini memberikan keuntungan tersendiri karena manusia dapat menulisnya dengan lebih mudah dan orang lain akan menyesuaikan dengan penyesuaian ini.
Untuk hari ini, dalam demo ini, mari kita fokus pada sintaksis dan nilai yang saya balikkan untuk membuat terang dan gelap. Mari kita lihat 1 platform dan 1 warna teks:
:root {
--surface1: lch(10 0 0);
--text1: lch(95 0 0);
@media (prefers-color-scheme: light) {
& {
--surface1: lch(90 0 0);
--text1: lch(40 0 0);
}
}
}
--surface1: lch(10 0 0)
diterjemahkan menjadi kecerahan 10%
, kroma 0, dan hue 0:
abu-abu tanpa warna yang sangat gelap. Kemudian, dalam kueri media untuk mode terang, kecerahan
dibalik menjadi 90%
dengan --surface1: lch(90 0 0);
. Dan itulah inti dari strategi ini. Mulailah dengan hanya mengubah kecerahan di antara 2 tema, mempertahankan
rasio kontras yang diminta desain, atau yang dapat mempertahankan aksesibilitas.
Bonus dengan lch()
di sini adalah bahwa kecerahan berorientasi pada manusia, dan kita dapat merasa
puas dengan perubahan %
pada kecerahan, bahwa %
akan berbeda secara persepsi dan konsisten. Misalnya, hsl()
tidak
sebanding.
Ada hal lain
yang perlu
dipelajari tentang
ruang warna dan lch()
jika Anda tertarik. Sebentar lagi!
CSS saat ini tidak dapat mengakses warna ini sama sekali. Saya ulangi: Kita tidak memiliki akses ke sepertiga warna di sebagian besar monitor modern. Dan ini bukan sembarang warna, tetapi warna paling cerah yang dapat ditampilkan layar. Situs kami memudar karena hardware monitor berkembang lebih cepat daripada spesifikasi CSS dan implementasi browser.
Lea Verou
Kontrol formulir adaptif dengan skema warna
Banyak browser mengirimkan kontrol tema gelap, saat ini Safari dan Chromium, tetapi Anda harus menentukan dalam CSS atau HTML bahwa desain Anda menggunakannya.
Gambar di atas menunjukkan efek properti dari panel Gaya di DevTools. Demo ini menggunakan tag HTML, yang menurut saya umumnya merupakan lokasi yang lebih baik:
<meta name="color-scheme" content="dark light">
Pelajari semuanya dalam artikel
color-scheme
ini oleh Thomas
Steiner. Ada banyak hal lain yang dapat diperoleh
dari input kotak centang gelap.
accent-color
CSS
Ada aktivitas
terbaru di sekitar
accent-color
pada elemen formulir, yang merupakan satu gaya CSS yang dapat mengubah
warna tint yang digunakan di elemen input browser. Baca selengkapnya di sini di GitHub. Saya telah memasukkannya ke
dalam gaya saya untuk komponen ini. Karena browser mendukungnya, kotak centang saya akan lebih sesuai dengan tema dengan warna merah muda dan ungu.
input[type="checkbox"] {
accent-color: var(--brand);
}
Pop warna dengan gradien tetap dan fokus dalam
Warna akan terlihat paling menarik jika digunakan secukupnya, dan salah satu cara yang saya sukai untuk melakukannya adalah melalui interaksi UI yang berwarna-warni.
Ada banyak lapisan masukan dan interaksi UI dalam video di atas, yang membantu memberikan kepribadian pada interaksi dengan:
- Menyoroti konteks.
- Memberikan masukan UI tentang "seberapa penuh" nilai yang ada dalam rentang.
- Memberikan masukan UI bahwa kolom menerima input.
Untuk memberikan masukan saat elemen sedang berinteraksi, CSS menggunakan
class semu
:focus-within
untuk mengubah tampilan berbagai elemen. Mari kita uraikan
.fieldset-item
, yang sangat menarik:
.fieldset-item {
...
&:focus-within {
background: var(--surface2);
& svg {
fill: white;
}
& picture {
clip-path: circle(50%);
background: var(--brand-bg-gradient) fixed;
}
}
}
Jika salah satu turunan elemen ini memiliki fokus di dalam:
- Latar belakang
.fieldset-item
diberi warna permukaan kontras yang lebih tinggi. svg
bertingkat diisi dengan warna putih untuk kontras yang lebih tinggi.<picture>
clip-path
bertingkat diperluas menjadi lingkaran penuh dan latar belakang diisi dengan gradien tetap yang terang.
Rentang kustom
Dengan elemen input HTML berikut, saya akan menunjukkan cara menyesuaikan tampilannya:
<input type="range">
Ada 3 bagian pada elemen ini yang perlu kita sesuaikan:
Gaya elemen rentang
input[type="range"] {
/* style setting variables */
--track-height: .5ex;
--track-fill: 0%;
--thumb-size: 3ex;
--thumb-offset: -1.25ex;
--thumb-highlight-size: 0px;
appearance: none; /* clear styles, make way for mine */
display: block;
inline-size: 100%; /* fill container */
margin: 1ex 0; /* ensure thumb isn't colliding with sibling content */
background: transparent; /* bg is in the track */
outline-offset: 5px; /* focus styles have space */
}
Beberapa baris pertama CSS adalah bagian khusus dari gaya, dan saya harap memberi label yang jelas pada gaya tersebut akan membantu. Gaya lainnya sebagian besar adalah gaya reset, untuk memberikan fondasi yang konsisten untuk mem-build bagian komponen yang rumit.
Gaya jalur
input[type="range"]::-webkit-slider-runnable-track {
appearance: none; /* clear styles, make way for mine */
block-size: var(--track-height);
border-radius: 5ex;
background:
/* hard stop gradient:
- half transparent (where colorful fill we be)
- half dark track fill
- 1st background image is on top
*/
linear-gradient(
to right,
transparent var(--track-fill),
var(--surface1) 0%
),
/* colorful fill effect, behind track surface fill */
var(--brand-bg-gradient) fixed;
}
Caranya adalah dengan "memunculkan" warna isian yang cerah. Hal ini dilakukan dengan gradien hard stop di atasnya. Gradien transparan hingga persentase isi, dan setelahnya menggunakan warna permukaan jalur yang tidak terisi. Di belakang permukaan yang tidak terisi, terdapat warna lebar penuh, yang menunggu transparansi untuk menampilkannya.
Gaya isian pelacakan
Desain saya memerlukan JavaScript untuk mempertahankan gaya isian. Ada strategi khusus CSS, tetapi strategi tersebut memerlukan elemen thumb dengan tinggi yang sama dengan trek, dan saya tidak dapat menemukan harmoni dalam batas itu.
/* grab sliders on page */
const sliders = document.querySelectorAll('input[type="range"]')
/* take a slider element, return a percentage string for use in CSS */
const rangeToPercent = slider => {
const max = slider.getAttribute('max') || 10;
const percent = slider.value / max * 100;
return `${parseInt(percent)}%`;
};
/* on page load, set the fill amount */
sliders.forEach(slider => {
slider.style.setProperty('--track-fill', rangeToPercent(slider));
/* when a slider changes, update the fill prop */
slider.addEventListener('input', e => {
e.target.style.setProperty('--track-fill', rangeToPercent(e.target));
})
})
Saya rasa ini akan menjadi upgrade visual yang bagus. Penggeser berfungsi dengan baik tanpa
JavaScript, properti --track-fill
tidak diperlukan, hanya saja tidak akan memiliki
gaya isi jika tidak ada. Jika JavaScript tersedia, isi properti kustom sekaligus amati perubahan pengguna, sinkronkan properti kustom dengan nilai.
Berikut adalah
postingan menarik di
CSS-Tricks oleh Ana
Tudor, yang menunjukkan solusi khusus CSS untuk
isi jalur. Saya juga merasa
elemen range
ini sangat menginspirasi.
Gaya thumb
input[type="range"]::-webkit-slider-thumb {
appearance: none; /* clear styles, make way for mine */
cursor: ew-resize; /* cursor style to support drag direction */
border: 3px solid var(--surface3);
block-size: var(--thumb-size);
inline-size: var(--thumb-size);
margin-top: var(--thumb-offset);
border-radius: 50%;
background: var(--brand-bg-gradient) fixed;
}
Sebagian besar gaya ini digunakan untuk membuat lingkaran yang bagus.
Sekali lagi, Anda melihat gradien latar belakang tetap di sana yang menyatukan
warna dinamis thumbnail, trek, dan elemen SVG terkait.
Saya memisahkan gaya untuk interaksi guna membantu mengisolasi teknik box-shadow
yang digunakan untuk sorotan pengarahan kursor:
@custom-media --motionOK (prefers-reduced-motion: no-preference);
::-webkit-slider-thumb {
…
/* shadow spread is initally 0 */
box-shadow: 0 0 0 var(--thumb-highlight-size) var(--thumb-highlight-color);
/* if motion is OK, transition the box-shadow change */
@media (--motionOK) {
& {
transition: box-shadow .1s ease;
}
}
/* on hover/active state of parent, increase size prop */
@nest input[type="range"]:is(:hover,:active) & {
--thumb-highlight-size: 10px;
}
}
Tujuannya adalah sorotan visual yang mudah dikelola dan dianimasikan untuk masukan pengguna. Dengan menggunakan bayangan kotak, saya dapat menghindari pemicu tata letak dengan efek ini. Saya melakukannya dengan membuat bayangan yang tidak diburamkan dan cocok dengan bentuk melingkar elemen thumbnail. Kemudian, saya mengubah dan mentransisikan ukuran penyebarannya saat diarahkan kursor.
Seandainya efek sorotan di kotak centang begitu mudah…
Pemilih lintas browser
Saya mendapati bahwa saya memerlukan pemilih -webkit-
dan -moz-
ini untuk mencapai konsistensi
lintas browser:
input[type="range"] {
&::-webkit-slider-runnable-track {}
&::-moz-range-track {}
&::-webkit-slider-thumb {}
&::-moz-range-thumb {}
}
Kotak Centang Kustom
Dengan elemen input HTML berikut, saya akan menunjukkan cara menyesuaikan tampilannya:
<input type="checkbox">
Ada 3 bagian pada elemen ini yang perlu kita sesuaikan:
Elemen kotak centang
input[type="checkbox"] {
inline-size: var(--space-sm); /* increase width */
block-size: var(--space-sm); /* increase height */
outline-offset: 5px; /* focus style enhancement */
accent-color: var(--brand); /* tint the input */
position: relative; /* prepare for an absolute pseudo element */
transform-style: preserve-3d; /* create a 3d z-space stacking context */
margin: 0;
cursor: pointer;
}
Gaya transform-style
dan position
menyiapkan pseudo-elemen yang akan kita perkenalkan nanti
untuk menata gaya sorotan. Jika tidak, sebagian besar
adalah hal-hal gaya opini kecil dari saya. Saya suka kursor menjadi pointer, saya suka
offset garis batas, kotak centang default terlalu kecil, dan jika accent-color
didukung, ubah kotak centang ini
ke dalam skema warna merek.
Label kotak centang
Penting untuk memberikan label pada kotak centang karena 2 alasan. Yang pertama adalah merepresentasikan tujuan penggunaan nilai kotak centang, untuk menjawab "aktif atau nonaktif untuk apa?" Kedua, untuk UX, pengguna web telah terbiasa berinteraksi dengan kotak centang melalui label terkait.
<input type="checkbox" id="text-notifications" name="text-notifications" >
<label for="text-notifications"> <h3>Text Messages</h3> <small>Get notified about all text messages sent to your device</small> </label>
Pada label, masukkan atribut for
yang mengarah ke kotak centang berdasarkan ID: <label for="text-notifications">
. Di kotak centang, gandakan nama dan ID untuk
memastikannya ditemukan dengan berbagai alat dan teknologi, seperti mouse atau pembaca layar:
<input type="checkbox" id="text-notifications" name="text-notifications">
.
:hover
, :active
, dan lainnya tersedia gratis dengan koneksi ini, sehingga meningkatkan
cara interaksi dengan formulir Anda.
Sorotan kotak centang
Saya ingin antarmuka saya tetap konsisten, dan elemen penggeser memiliki tanda thumbnail
yang bagus yang ingin saya gunakan dengan kotak centang. Thumbnail ini
dapat menggunakan box-shadow
dan properti spread
untuk menskalakan bayangan ke atas dan
ke bawah. Namun, efek tersebut tidak berfungsi di sini karena kotak centang kita, dan harus
berbentuk, persegi.
Saya dapat memperoleh efek visual yang sama dengan elemen pseudo, dan CSS yang rumit, dalam jumlah yang sangat sedikit:
@custom-media --motionOK (prefers-reduced-motion: no-preference);
input[type="checkbox"]::before {
--thumb-scale: .01; /* initial scale of highlight */
--thumb-highlight-size: var(--space-xl);
content: "";
inline-size: var(--thumb-highlight-size);
block-size: var(--thumb-highlight-size);
clip-path: circle(50%); /* circle shape */
position: absolute; /* this is why position relative on parent */
top: 50%; /* pop and plop technique (https://web.dev/centering-in-css#5-pop-and-plop) */
left: 50%;
background: var(--thumb-highlight-color);
transform-origin: center center; /* goal is a centered scaling circle */
transform: /* order here matters!! */
translateX(-50%) /* counter balances left: 50% */
translateY(-50%) /* counter balances top: 50% */
translateZ(-1px) /* PUTS IT BEHIND THE CHECKBOX */
scale(var(--thumb-scale)) /* value we toggle for animation */
;
will-change: transform;
@media (--motionOK) { /* transition only if motion is OK */
& {
transition: transform .2s ease;
}
}
}
/* on hover, set scale custom property to "in" state */
input[type="checkbox"]:hover::before {
--thumb-scale: 1;
}
Membuat pseudo-elemen lingkaran adalah pekerjaan yang mudah, tetapi meletakkan elemen tersebut di belakang elemen yang dilampirkan lebih sulit. Berikut ini sebelum dan setelah saya memperbaikinya:
Ini jelas merupakan interaksi mikro, tetapi penting bagi saya untuk menjaga konsistensi
visual. Teknik penskalaan animasi sama dengan yang telah kita gunakan di
tempat lain. Kita menetapkan properti kustom ke nilai baru dan membiarkan CSS mentransisikan properti tersebut
berdasarkan preferensi gerakan. Fitur utamanya di sini adalah translateZ(-1px)
. Induk
membuat ruang 3D dan turunan elemen pseudo ini memanfaatkannya dengan
menempatkan dirinya sedikit kembali di ruang z.
Aksesibilitas
Video YouTube ini menunjukkan demonstrasi yang bagus tentang interaksi mouse, keyboard, dan pembaca layar untuk komponen setelan ini. Saya akan menyebutkan beberapa detail di sini.
Pilihan Elemen HTML
<form>
<header>
<fieldset>
<picture>
<label>
<input>
Setiap halaman ini berisi petunjuk dan tips untuk alat penjelajahan pengguna. Beberapa elemen memberikan petunjuk interaksi, beberapa menghubungkan interaktivitas, dan beberapa membantu membentuk hierarki aksesibilitas yang dinavigasi oleh pembaca layar.
Atribut HTML
Kita bisa menyembunyikan elemen yang tidak dibutuhkan oleh pembaca layar, dalam hal ini ikon di sebelah {i>slider<i}:
<picture aria-hidden="true">
Video di atas menunjukkan alur pembaca layar di Mac OS. Perhatikan bagaimana fokus input berpindah langsung dari satu penggeser ke penggeser berikutnya. Ini karena kita telah menyembunyikan ikon yang mungkin menjadi perhentian dalam {i>slider<i} berikutnya. Tanpa atribut ini, pengguna perlu berhenti, mendengarkan, dan melewati gambar yang mungkin tidak dapat mereka lihat.
SVG adalah sekumpulan matematika, mari kita tambahkan elemen <title>
untuk judul kursor mouse gratis dan komentar yang dapat dibaca manusia tentang apa yang dibuat oleh matematika:
<svg viewBox="0 0 24 24">
<title>A note icon</title>
<path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/>
</svg>
Selain itu, kami telah menggunakan cukup banyak HTML yang ditandai dengan jelas, sehingga formulir tersebut diuji dengan sangat baik di mouse, keyboard, pengontrol video game, dan pembaca layar.
JavaScript
Kami telah membahas cara warna isian jalur dikelola dari JavaScript, jadi sekarang mari kita lihat JavaScript terkait <form>
:
const form = document.querySelector('form');
form.addEventListener('input', event => {
const formData = Object.fromEntries(new FormData(form));
console.table(formData);
})
Setiap kali formulir berinteraksi dan diubah, konsol akan mencatat formulir tersebut sebagai objek ke dalam tabel agar mudah ditinjau sebelum dikirim ke server.
Kesimpulan
Setelah Anda tahu cara saya melakukannya, bagaimana Anda melakukannya? Hal ini membuat arsitektur komponen yang menyenangkan. Siapa yang akan membuat versi pertama dengan slot dalam framework favorit mereka? 🙂
Mari kita diversifikasi pendekatan kami dan mempelajari semua cara untuk membangun di web. Buat demo, tweet link-nya, dan kami akan menambahkannya ke bagian Remix komunitas di bawah.