D
P
0

HTML & CSS

Anchor Bersarang (`<a>` di Dalam `<a>`) Diam-Diam Merusak Card Grid Saya

9 Juni 2026·4 menit baca
Anchor Bersarang (`<a>` di Dalam `<a>`) Diam-Diam Merusak Card Grid Saya

Ini bug yang bikin saya curiga sama CSS selama satu jam penuh, padahal masalahnya sama sekali bukan di CSS. Di sebuah situs editorial yang saya bangun, grid card artikel tiba-tiba kolaps: tiap card mengecil jadi kolom selebar satu huruf, dan tiap kata di judul turun ke barisnya sendiri secara vertikal. Anehnya, gambar di dalam card lebarnya masih normal — yang berantakan cuma judul dan byline.

Saya mengutak-atik grid-template-columns, min-width, flex-basis, semuanya. Tidak ada yang berubah. Ternyata akar masalahnya ada di HTML, bukan CSS: saya tanpa sengaja menaruh <a> di dalam <a>, dan browser diam-diam membongkar struktur itu.

Kenapa anchor bersarang menghancurkan grid

HTML5 melarang anchor bersarang. <a> adalah elemen interaktif, dan spesifikasi tidak mengizinkan konten interaktif di dalam konten interaktif lain. Masalahnya, browser tidak menampilkan error — ia "memperbaiki" markup-nya sendiri.

Card saya kira-kira seperti ini: seluruh card dibungkus <a> agar bisa diklik, lalu di dalamnya ada <a> lagi untuk nama penulis (link ke halaman author). Saat parser bertemu <a> kedua, ia menutup paksa <a> pertama tepat di titik itu. Akibatnya, semua elemen setelah link author — judul, byline, sisa konten — tidak lagi berada di dalam anchor pembungkus. Mereka "naik" jadi anak langsung dari elemen grid.

Dan di sinilah grid kolaps. Anak grid yang tidak punya penempatan eksplisit otomatis dapat col-span-1. Jadi judul yang tadinya membentang penuh sekarang dijejalkan ke satu track kolom sempit, dan teksnya pecah per kata.

Diagnostik yang paling cepat membuktikannya: cek parent dari elemen judul di DevTools.

// Kalau outer link di-unwrap, parent h3 bukan lagi <a>
document.querySelector(".card h3").parentElement.tagName;
// Diharapkan: "A"  → Kenyataan: "ARTICLE"  (anchor pembungkus hilang)

Begitu hasilnya "ARTICLE" bukan "A", jelas: browser sudah membongkar anchor luar saya.

Markup yang bermasalah

<a href="/article/slug" class="card">
  <img src="/cover.webp" alt="" />
  <h3>Judul artikel yang panjang</h3>
  <!-- INI biang keroknya: anchor di dalam anchor -->
  <a href="/author/jane">Jane Doe</a>
  <time>9 Juni 2026</time>
</a>

Begitu parser sampai ke <a href="/author/jane">, ia menutup .card anchor. <h3>, <time>, dan link author jadi saudara langsung di dalam grid — bukan lagi anak dari card yang bisa diklik.

Kita tetap butuh dua tujuan klik berbeda: klik card ke artikel, klik nama ke halaman author. Triknya, jangan pakai dua anchor. Buat link dalam sebagai elemen non-interaktif yang kita beri perilaku link manual:

<a href="/article/slug" class="card">
  <img src="/cover.webp" alt="" />
  <h3>Judul artikel yang panjang</h3>
  <!-- Bukan <a>, jadi anchor luar tidak di-unwrap -->
  <span data-href="/author/jane" role="link" tabindex="0">Jane Doe</span>
  <time>9 Juni 2026</time>
</a>

Karena <span> bukan konten interaktif, browser tidak lagi menutup paksa anchor luar. Strukturnya utuh, grid kembali normal. Lalu kita pasang satu handler delegasi di dokumen untuk menghidupkan data-href:

// Klik pada elemen ber-data-href → navigasi, dan jangan picu card link
document.addEventListener("click", (e) => {
  const link = e.target.closest("[data-href]");
  if (!link) return;
  e.preventDefault();
  e.stopPropagation(); // cegah anchor card ikut ter-trigger
  window.location.href = link.dataset.href;
});
 
// Keyboard: span role="link" harus respons Enter dan Space
document.addEventListener("keydown", (e) => {
  if (e.key !== "Enter" && e.key !== " ") return;
  const link = e.target.closest("[data-href]");
  if (!link) return;
  e.preventDefault();
  e.stopPropagation();
  window.location.href = link.dataset.href;
});

stopPropagation() penting: tanpanya, klik nama author akan menggelembung ke anchor card dan membawa user ke artikel, bukan ke halaman author. role="link" dan tabindex="0" mengembalikan aksesibilitas yang hilang saat kita berhenti memakai <a> asli — elemen bisa difokus dengan keyboard dan diumumkan sebagai link oleh screen reader, lalu keydown menangani Enter/Space seperti anchor sungguhan.

Catatan tambahan

  • Diagnostik tercepat tetap di DevTools: kalau parentElement.tagName elemen dalam bukan yang Anda kira, kemungkinan besar ada elemen interaktif yang di-unwrap browser. Ini juga berlaku untuk <button> di dalam <a>, atau <a> di dalam <button>.
  • Pola "card besar bisa diklik + satu link kecil di dalamnya" memang sering. Solusi alternatif: jadikan card bukan anchor (pakai overlay pseudo-element ::after dengan position: absolute; inset: 0), lalu link author tetap <a> asli yang diberi position: relative; z-index: 1 agar berada di atas overlay. Itu menjaga semantik anchor untuk keduanya.
  • Selalu validasi HTML saat layout "berantakan tanpa sebab". Validator akan langsung menandai "Element a not allowed as child of element a" — petunjuk yang lebih cepat daripada mengubek CSS satu jam.

Intinya: kalau grid kolaps dan CSS Anda kelihatan benar, periksa apakah browser sudah diam-diam menulis ulang DOM Anda. Anchor bersarang adalah salah satu cara paling halus markup yang "kelihatan benar" berubah jadi struktur yang sama sekali berbeda saat di-parse.