Menambatkan elemen satu sama lain dengan penempatan anchor CSS

Bagaimana Anda saat ini menautkan satu elemen ke elemen lainnya? Anda dapat mencoba melacak posisinya, atau menggunakan beberapa bentuk elemen wrapper.

<!-- index.html -->
<div class="container">
  <a href="/link" class="anchor">I’m the anchor</a>
  <div class="anchored">I’m the anchored thing</div>
</div>
/* styles.css */
.container {
  position: relative;
}
.anchored {
  position: absolute;
}

Solusi ini sering kali tidak ideal. Mereka membutuhkan JavaScript atau memperkenalkan markup tambahan. CSS anchor positioning API bertujuan untuk mengatasi hal ini dengan menyediakan CSS API untuk elemen tethering. Skala menyediakan cara untuk memosisikan dan mengukur satu elemen berdasarkan posisi dan ukuran elemen lainnya.

Gambar menampilkan jendela browser mockup yang memerinci anatomi tooltip.

Dukungan browser

Anda dapat mencoba CSS anchor positioning API di Chrome Canary di balik "Fitur Web Platform Eksperimental" penanda. Untuk mengaktifkan tanda tersebut, buka Chrome Canary dan buka chrome://flags. Kemudian, aktifkan "Fitur platform web eksperimental" penanda.

Tersedia juga polyfill dalam pengembangan oleh tim di Oddbird. Pastikan untuk memeriksa repositori di github.com/oddbird/css-anchor-positioning.

Anda dapat memeriksa dukungan anchor dengan:

@supports(anchor-name: --foo) {
  /* Styles... */
}

Perhatikan bahwa API ini masih dalam tahap eksperimental dan dapat berubah. Artikel ini membahas bagian-bagian penting di tingkat atas. Penerapan saat ini juga tidak sepenuhnya disinkronkan dengan spesifikasi Grup Kerja CSS.

Permasalahan

Mengapa Anda perlu melakukan ini? Kasus penggunaan yang penting adalah membuat tooltip atau pengalaman seperti tooltip. Dalam hal ini, Anda sering kali ingin melakukan tethering tooltip ke konten yang direferensikan. Cara tertentu untuk mengaitkan elemen ke elemen lainnya sering kali diperlukan. Anda juga berharap bahwa interaksi dengan halaman tidak merusak tethering tersebut—misalnya, jika pengguna men-scroll atau mengubah ukuran UI.

Bagian lain dari masalah ini adalah jika Anda ingin memastikan elemen yang di-tethering tetap terlihat—misalnya, jika Anda membuka tooltip dan terpotong oleh batas area pandang. Ini mungkin bukan pengalaman yang baik bagi pengguna. Anda ingin tooltip beradaptasi.

Solusi saat ini

Saat ini, ada beberapa cara yang dapat Anda gunakan untuk mengatasi masalah ini.

Yang pertama adalah "{i>Wrap the anchor<i}" dasar pendekatan. Anda mengambil kedua elemen dan memasukkannya ke dalam container. Kemudian, Anda dapat menggunakan position untuk memosisikan tooltip relatif terhadap anchor.

<div class="containing-block">
  <div class="tooltip">Anchor me!</div>
  <a class="anchor">The anchor</a>
</div>
.containing-block {
  position: relative;
}

.tooltip {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  transform: translateX(-50%);
}

Anda dapat memindahkan container dan semuanya akan tetap berada di tempat yang Anda inginkan.

Pendekatan lainnya mungkin adalah jika Anda mengetahui posisi anchor atau Anda dapat melacaknya. Anda dapat meneruskannya ke tooltip dengan properti kustom.

<div class="tooltip">Anchor me!</div>
<a class="anchor">The anchor</a>
:root {
  --anchor-width: 120px;
  --anchor-top: 40vh;
  --anchor-left: 20vmin;
}

.anchor {
  position: absolute;
  top: var(--anchor-top);
  left: var(--anchor-left);
  width: var(--anchor-width);
}

.tooltip {
  position: absolute;
  top: calc(var(--anchor-top));
  left: calc((var(--anchor-width) * 0.5) + var(--anchor-left));
  transform: translate(-50%, calc(-100% - 10px));
}

Namun, bagaimana jika Anda tidak mengetahui posisi anchor Anda? Anda mungkin perlu melakukan intervensi dengan JavaScript. Anda bisa melakukan sesuatu seperti yang dilakukan kode berikut, tetapi ini berarti gaya Anda mulai bocor dari CSS dan masuk ke JavaScript.

const setAnchorPosition = (anchored, anchor) => {
  const bounds = anchor.getBoundingClientRect().toJSON();
  for (const [key, value] of Object.entries(bounds)) {
    anchored.style.setProperty(`--${key}`, value);
  }
};

const update = () => {
  setAnchorPosition(
    document.querySelector('.tooltip'),
    document.querySelector('.anchor')
  );
};

window.addEventListener('resize', update);
document.addEventListener('DOMContentLoaded', update);

Hal ini mulai menimbulkan beberapa pertanyaan:

  • Kapan saya menghitung gaya?
  • Bagaimana cara menghitung gaya?
  • Seberapa sering saya menghitung gaya?

Apakah itu menyelesaikan masalahnya? Hal ini mungkin cocok untuk kasus penggunaan Anda, tetapi ada satu masalah: solusi kami tidak beradaptasi. Tidak responsif. Bagaimana jika elemen anchor saya terpotong oleh area tampilan?

Sekarang Anda perlu memutuskan apakah akan bereaksi terhadap hal ini dan bagaimana caranya. Jumlah pertanyaan dan keputusan yang perlu Anda buat mulai bertambah. Yang perlu Anda lakukan adalah menambatkan satu elemen ke elemen lainnya. Dalam kondisi ideal, solusi Anda akan menyesuaikan dan bereaksi terhadap lingkungannya.

Untuk menghilangkan beberapa rasa masalah itu, Anda dapat menggunakan solusi JavaScript untuk membantu Anda. Hal ini akan menimbulkan biaya penambahan dependensi ke project Anda, dan dapat menimbulkan masalah performa, bergantung pada cara Anda menggunakannya. Misalnya, beberapa paket menggunakan requestAnimationFrame untuk menjaga posisi tetap benar. Artinya, Anda dan tim Anda harus memahami paket dan opsi konfigurasinya. Akibatnya, pertanyaan dan keputusan Anda mungkin tidak berkurang, tetapi akan berubah. Ini adalah bagian dari “mengapa” untuk penempatan anchor CSS. Dengan demikian, Anda tidak perlu memikirkan masalah performa saat menghitung posisi.

Berikut adalah tampilan kode untuk menggunakan "floating-ui", paket populer untuk masalah ini:

import {computePosition, flip, offset, autoUpdate} from 'https://cdn.jsdelivr.net/npm/@floating-ui/dom@1.2.1/+esm';

const anchor = document.querySelector('.anchor')
const tooltip = document.querySelector('.tooltip')

const updatePosition = () => {  
  computePosition(anchor, tooltip, {
    placement: 'top',
    middleware: [offset(10), flip()]
  })
    .then(({x, y}) => {
      Object.assign(tooltip.style, {
        left: `${x}px`,
        top: `${y}px`
      })
  })
};

const clean = autoUpdate(anchor, tooltip, updatePosition);

Coba posisikan ulang anchor dalam demo ini yang menggunakan kode tersebut.

"tooltip" mungkin tidak berperilaku seperti yang Anda harapkan. Elemen ini bereaksi saat berada di luar area pandang pada sumbu y, tetapi tidak pada sumbu x. Baca dokumentasi, dan Anda mungkin akan menemukan solusi yang sesuai untuk Anda.

Namun, menemukan paket yang cocok untuk proyek Anda bisa memakan banyak waktu. Hal ini merupakan keputusan tambahan dan dapat menjengkelkan jika tidak berfungsi seperti yang Anda inginkan.

Menggunakan penempatan posisi anchor

Masukkan CSS anchor positioning API. Idenya adalah untuk mempertahankan gaya Anda di CSS dan mengurangi jumlah keputusan yang perlu Anda buat. Anda berharap mendapatkan hasil yang sama, tetapi tujuannya adalah untuk meningkatkan pengalaman developer.

  • JavaScript tidak diperlukan.
  • Biarkan browser menentukan posisi terbaik dari panduan Anda.
  • Tidak ada lagi ketergantungan terhadap pihak ketiga
  • Tidak ada elemen wrapper.
  • Bekerja dengan elemen yang ada di lapisan atas.

Mari kita reka ulang dan atasi masalah yang kita coba selesaikan di atas. Namun, sebagai gantinya, gunakan analogi perahu dengan jangkar. Keduanya mewakili elemen anchor dan anchor. Air mewakili blok yang memuatnya.

Pertama, Anda harus memilih cara menentukan anchor. Anda dapat melakukannya dalam CSS dengan menetapkan properti anchor-name pada elemen anchor. Kolom ini menerima nilai dashed-ident.

.anchor {
  anchor-name: --my-anchor;
}

Atau, Anda akan dapat menentukan anchor dalam HTML dengan atribut anchor. Nilai atribut adalah ID elemen anchor. Tindakan ini akan membuat anchor implisit.

<a id="my-anchor" class="anchor"></a>
<div anchor="my-anchor" class="boat">I’m a boat!</div>

Setelah menentukan anchor, Anda dapat menggunakan fungsi anchor. Fungsi anchor menggunakan 3 argumen:

  • Elemen anchor: anchor-name anchor yang akan digunakan—atau, Anda dapat menghilangkan nilai untuk menggunakan anchor implicit. Kolom ini dapat ditentukan melalui hubungan HTML, atau dengan properti anchor-default dengan nilai anchor-name.
  • Sisi anchor: Kata kunci dari posisi yang ingin Anda gunakan. Nilainya bisa berupa top, right, bottom, left, center, dll. Atau, Anda dapat meneruskan persentase. Misalnya, 50% akan sama dengan center.
  • Penggantian: Ini adalah nilai penggantian opsional yang menerima durasi atau persentase.

Anda menggunakan fungsi anchor sebagai nilai untuk properti inset (top, right, bottom, left, atau setara logisnya) dari elemen anchor. Anda juga dapat menggunakan fungsi anchor di calc:

.boat {
  bottom: anchor(--my-anchor top);
  left: calc(anchor(--my-anchor center) - (var(--boat-size) * 0.5));
}

 /* alternative with anchor-default */
.boat {
  anchor-default: --my-anchor;
  bottom: anchor(top);
  left: calc(anchor(center) - (var(--boat-size) * 0.5));
}

Tidak ada properti inset center sehingga salah satu opsinya adalah menggunakan calc jika Anda mengetahui ukuran elemen anchor. Mengapa tidak menggunakan translate? Anda bisa menggunakan ini:

.boat {
  anchor-default: --my-anchor;
  bottom: anchor(top);
  left: anchor(center);
  translate: -50% 0;
}

Namun, browser tidak mempertimbangkan posisi yang diubah untuk elemen anchor. Akan jelas mengapa hal ini penting saat mempertimbangkan penggantian posisi dan pemosisian otomatis.

Anda mungkin telah melihat penggunaan properti khusus --boat-size di atas. Namun, jika ingin menjadikan ukuran elemen anchor sebagai dasar, Anda juga dapat mengakses ukuran tersebut. Anda dapat menggunakan fungsi anchor-size, bukan menghitungnya sendiri. Misalnya, untuk membuat kapal kita empat kali lebar angkur:

.boat {
  width: calc(4 * anchor-size(--my-anchor width));
}

Anda juga memiliki akses ke tinggi menggunakan anchor-size(--my-anchor height). Dan Anda dapat menggunakannya untuk menyetel ukuran salah satu sumbu atau keduanya.

Bagaimana jika Anda ingin menambatkan ke elemen dengan pemosisian absolute? Aturannya adalah elemen tidak boleh berupa saudara. Dalam hal ini, Anda dapat menggabungkan anchor dengan penampung yang memiliki posisi relative. Kemudian Anda dapat menambatkannya.

<div class="anchor-wrapper">
  <a id="my-anchor" class="anchor"></a>
</div>
<div class="boat">I’m a boat!</div>

Tonton demo ini yang memungkinkan Anda menarik angkur dan kapal akan mengikuti.

Melacak posisi scroll

Dalam beberapa kasus, elemen anchor Anda mungkin berada dalam container scroll. Pada saat yang sama, elemen anchor Anda mungkin berada di luar penampung tersebut. Karena scroll terjadi pada thread yang berbeda dengan tata letak, Anda memerlukan cara untuk melacaknya. Properti anchor-scroll dapat melakukannya. Anda menetapkannya pada elemen anchor dan memberinya nilai anchor yang ingin dilacak.

.boat { anchor-scroll: --my-anchor; }

Coba demo ini yang dapat Anda gunakan untuk mengaktifkan dan menonaktifkan anchor-scroll dengan kotak centang di pojok.

Analoginya sedikit datar di sini, seperti dalam dunia yang ideal, perahu dan jangkar Anda berada di air. Selain itu, fitur seperti Popover API mempromosikan kemampuan untuk menjaga elemen terkait tetap dekat. Namun, posisi anchor akan berfungsi dengan elemen yang berada di lapisan atas. Ini adalah salah satu manfaat utama di balik API: kemampuan menambatkan elemen dalam alur yang berbeda.

Perhatikan demo ini yang memiliki container scroll dengan anchor yang memiliki tooltip. Elemen tooltip yang merupakan popover mungkin tidak ditempatkan bersama dengan anchor:

Namun, Anda akan melihat bagaimana popover melacak masing-masing link anchor. Anda dapat mengubah ukuran penampung scroll tersebut dan posisinya akan diperbarui untuk Anda.

Penggantian posisi dan pemosisian otomatis

Di sinilah daya pemosisian anchor naik satu level. position-fallback dapat memosisikan elemen anchor berdasarkan serangkaian penggantian yang Anda berikan. Anda memandu browser dengan gaya Anda dan membiarkannya mengatur posisi untuk Anda.

Kasus penggunaan umum di sini adalah tooltip yang harus beralih antara ditampilkan di atas atau di bawah anchor. Dan perilaku ini didasarkan pada apakah tooltip akan terpotong oleh container-nya. Penampung itu biasanya adalah area pandang.

Jika mempelajari kode demo terakhir, Anda akan melihat ada properti position-fallback yang digunakan. Jika men-scroll penampung, Anda mungkin melihat popover anchor tersebut melonjak. Hal ini terjadi saat anchor masing-masing mendekati batas area pandang. Pada saat itu, popover mencoba menyesuaikan agar tetap berada di area pandang.

Sebelum membuat position-fallback eksplisit, pemosisian anchor juga akan menawarkan pemosisian otomatis. Anda bisa mendapatkan balik itu secara gratis dengan menggunakan nilai auto di fungsi anchor dan properti inset yang berlawanan. Misalnya, jika Anda menggunakan anchor untuk bottom, tetapkan top ke auto.

.tooltip {
  position: absolute;
  bottom: anchor(--my-anchor auto);
  top: auto;
}

Alternatif untuk pemosisian otomatis adalah menggunakan position-fallback eksplisit. Tindakan ini mengharuskan Anda menentukan kumpulan penggantian posisi. Browser akan menelusurinya sampai menemukan ekstensi yang dapat digunakan, lalu menerapkan pemosisian tersebut. Jika tidak dapat menemukan kode yang berfungsi, setelan default adalah fungsi pertama yang ditentukan.

position-fallback yang mencoba menampilkan tooltip di atas lalu di bawah dapat terlihat seperti ini:

@position-fallback --top-to-bottom {
  @try {
    bottom: anchor(top);
    left: anchor(center);
  }

  @try {
    top: anchor(bottom);
    left: anchor(center);
  }
}

Menerapkannya ke tooltip akan terlihat seperti ini:

.tooltip {
  anchor-default: --my-anchor;
  position-fallback: --top-to-bottom;
}

Penggunaan anchor-default berarti Anda dapat menggunakan kembali position-fallback untuk elemen lain. Anda juga dapat menggunakan properti kustom cakupan untuk menetapkan anchor-default.

Pertimbangkan lagi demo ini menggunakan boat. Ada position-fallback yang ditetapkan. Saat Anda mengubah posisi angkur, kapal akan menyesuaikan agar tetap berada dalam kontainer. Coba ubah nilai padding juga yang menyesuaikan padding isi. Perhatikan cara browser mengoreksi pemosisian. Posisi diubah dengan mengubah perataan petak penampung.

Kali ini position-fallback menjadi lebih panjang dengan mencoba posisi searah jarum jam.

.boat {
  anchor-default: --my-anchor;
  position-fallback: --compass;
}

@position-fallback --compass {
  @try {
    bottom: anchor(top);
    right: anchor(left);
  }

  @try {
    bottom: anchor(top);
    left: anchor(right);
  }

  @try {
    top: anchor(bottom);
    right: anchor(left);
  }

  @try {
    top: anchor(bottom);
    left: anchor(right);
  }
}

Contoh

Sekarang Anda memiliki gagasan tentang fitur utama untuk pemosisian anchor, mari kita lihat beberapa contoh menarik selain tooltip. Contoh-contoh ini bertujuan untuk membuat ide Anda mengalir dengan cara-cara yang dapat Anda gunakan untuk menggunakan positioning anchor. Cara terbaik untuk meningkatkan spesifikasi ini adalah dengan memasukkan data dari pengguna sungguhan seperti Anda.

Menu konteks

Mari kita mulai dengan menu konteks menggunakan Popover API. Idenya adalah mengklik tombol dengan tanda V akan menampilkan menu konteks. Dan menu itu akan memiliki menu sendiri yang akan diperluas.

Markup bukanlah bagian yang penting di sini. Namun, Anda memiliki tiga tombol yang masing-masing menggunakan popovertarget. Anda kemudian memiliki tiga elemen menggunakan atribut popover. Hal ini memberi Anda kemampuan untuk membuka menu konteks tanpa JavaScript. Tampilannya akan terlihat seperti ini:

<button popovertarget="context">
  Toggle Menu
</button>        
<div popover="auto" id="context">
  <ul>
    <li><button>Save to your Liked Songs</button></li>
    <li>
      <button popovertarget="playlist">
        Add to Playlist
      </button>
    </li>
    <li>
      <button popovertarget="share">
        Share
      </button>
    </li>
  </ul>
</div>
<div popover="auto" id="share">...</div>
<div popover="auto" id="playlist">...</div>

Sekarang, Anda dapat menentukan position-fallback dan membagikannya di antara menu konteks. Kita juga memastikan untuk membatalkan penetapan gaya inset apa pun untuk popover.

[popovertarget="share"] {
  anchor-name: --share;
}

[popovertarget="playlist"] {
  anchor-name: --playlist;
}

[popovertarget="context"] {
  anchor-name: --context;
}

#share {
  anchor-default: --share;
  position-fallback: --aligned;
}

#playlist {
  anchor-default: --playlist;
  position-fallback: --aligned;
}

#context {
  anchor-default: --context;
  position-fallback: --flip;
}

@position-fallback --aligned {
  @try {
    top: anchor(top);
    left: anchor(right);
  }

  @try {
    top: anchor(bottom);
    left: anchor(right);
  }

  @try {
    top: anchor(top);
    right: anchor(left);
  }

  @try {
    bottom: anchor(bottom);
    left: anchor(right);
  }

  @try {
    right: anchor(left);
    bottom: anchor(bottom);
  }
}

@position-fallback --flip {
  @try {
    bottom: anchor(top);
    left: anchor(left);
  }

  @try {
    right: anchor(right);
    bottom: anchor(top);
  }

  @try {
    top: anchor(bottom);
    left: anchor(left);
  }

  @try {
    top: anchor(bottom);
    right: anchor(right);
  }
}

Tindakan ini akan memberi Anda UI menu konteks bertingkat adaptif. Coba ubah posisi konten dengan memilih. Opsi yang Anda pilih memperbarui perataan petak. Hal ini juga memengaruhi cara pemosisian anchor memosisikan popover.

Fokus dan ikuti

Demo ini menggabungkan primitif CSS dengan menyertakan :has(). Idenya adalah mentransisikan indikator visual untuk input yang memiliki fokus.

Lakukan hal ini dengan menetapkan anchor baru saat runtime. Untuk demo ini, properti kustom cakupan akan diperbarui pada fokus input.

#email {
    anchor-name: --email;
  }
  #name {
    anchor-name: --name;
  }
  #password {
    anchor-name: --password;
  }
:root:has(#email:focus) {
    --active-anchor: --email;
  }
  :root:has(#name:focus) {
    --active-anchor: --name;
  }
  :root:has(#password:focus) {
    --active-anchor: --password;
  }

:root {
    --active-anchor: --name;
    --active-left: anchor(var(--active-anchor) right);
    --active-top: calc(
      anchor(var(--active-anchor) top) +
        (
          (
              anchor(var(--active-anchor) bottom) -
                anchor(var(--active-anchor) top)
            ) * 0.5
        )
    );
  }
.form-indicator {
    left: var(--active-left);
    top: var(--active-top);
    transition: all 0.2s;
}

Tapi, bagaimana Anda bisa melanjutkan hal ini? Anda dapat menggunakannya untuk beberapa bentuk overlay petunjuk. Tooltip dapat berpindah di antara lokasi menarik dan memperbarui kontennya. Anda dapat melakukan crossfade konten. Animasi terpisah yang memungkinkan Anda menganimasikan display atau Lihat Transisi dapat berfungsi di sini.

Penghitungan diagram batang

Hal seru lain yang dapat Anda lakukan dengan penempatan posisi anchor adalah menggabungkannya dengan calc. Bayangkan sebuah diagram dengan beberapa popover yang menganotasi diagram.

Anda dapat melacak nilai tertinggi dan terendah menggunakan CSS min dan max. CSS untuk kueri tersebut akan terlihat seperti ini:

.chart__tooltip--max {
    left: anchor(--chart right);
    bottom: max(
      anchor(--anchor-1 top),
      anchor(--anchor-2 top),
      anchor(--anchor-3 top)
    );
    translate: 0 50%;
  }

Ada beberapa JavaScript yang berfungsi untuk memperbarui nilai bagan dan beberapa CSS untuk menata gaya bagan. Namun, positioning anchor menangani update tata letak untuk kita.

Ubah Ukuran Tuas

Anda tidak harus hanya menambatkan ke satu elemen. Anda dapat menggunakan banyak anchor untuk sebuah elemen. Anda mungkin telah memperhatikannya dalam contoh diagram batang. Tooltip tersebut ditambatkan ke diagram, lalu di batang yang sesuai. Jika Anda membawa konsep itu lebih jauh, Anda bisa menggunakannya untuk mengubah ukuran elemen.

Anda dapat memperlakukan titik link seperti tuas ubah ukuran kustom dan condong ke nilai inset.

.container {
   position: absolute;
   inset:
     anchor(--handle-1 top)
     anchor(--handle-2 right)
     anchor(--handle-2 bottom)
     anchor(--handle-1 left);
 }

Dalam demo ini, GreenSock Draggable membuat tuas dapat ditarik. Namun, elemen <img> berubah ukuran untuk mengisi penampung yang disesuaikan untuk mengisi celah di antara tuas.

Pilih Menu?

Yang terakhir ini sedikit memberi gambaran tentang apa yang akan terjadi. Namun, Anda dapat membuat popover yang dapat difokuskan dan sekarang memiliki penempatan anchor. Anda dapat membuat dasar-dasar elemen <select> yang dapat ditata gayanya.

<div class="select-menu">
<button popovertarget="listbox">
 Select option
 <svg>...</svg>
</button>
<div popover="auto" id="listbox">
   <option>A</option>
   <option>Styled</option>
   <option>Select</option>
</div>
</div>

anchor implisit akan mempermudah hal ini. Namun, CSS untuk titik awal yang belum sempurna dapat terlihat seperti ini:

[popovertarget] {
 anchor-name: --select-button;
}
[popover] {
  anchor-default: --select-button;
  top: anchor(bottom);
  width: anchor-size(width);
  left: anchor(left);
}

Gabungkan fitur Popover API dengan pemosisian Anchor CSS dan Anda pun sudah dekat.

Anda dapat dengan mudah memperkenalkan hal-hal seperti :has(). Anda dapat memutar penanda saat terbuka:

.select-menu:has(:open) svg {
  rotate: 180deg;
}

Ke mana Anda akan melanjutkannya? Apa lagi yang kita perlukan agar select berfungsi? Kita akan menyimpannya untuk artikel berikutnya. Namun jangan khawatir, elemen pilihan yang bisa disesuaikan akan segera hadir. Nantikan kabar terbarunya.


Selesai!

Platform web terus berkembang. Pemosisian anchor CSS adalah bagian penting untuk meningkatkan cara Anda mengembangkan kontrol UI. Hal ini akan menjauhkan Anda dari beberapa keputusan rumit tersebut. Tetapi itu juga akan memungkinkan Anda melakukan hal-hal yang belum pernah dapat Anda lakukan sebelumnya. Misalnya menata gaya elemen <select>. Utarakan pendapat Anda.

Foto oleh CHUTTERSNAP di Unsplash