Perintah dan konteks
Sebuah pembaca dokumen menampilkan kecocokan pencarian, anotasi, dan kecocokan saat ini dalam rich text. Membungkus setiap kecocokan dalam tag span akan mengganggu seleksi teks, pengeditan, dan tata letak. Rancang solusi CSS Custom Highlight API yang mencakup siklus hidup Range, pembaruan registri, cascade, status aksesibilitas, fallback, dan performa. Ini adalah pertanyaan frontend tentang rendering teks dan progressive enhancement.
Apa yang dievaluasi oleh pewawancara
- Membedakan objek JavaScript Range, Highlight, dan
::highlight(). - Membangun kembali range yang usang (stale) setelah penggantian teks atau pengeditan.
- Memahami bahwa highlight tidak mengubah DOM dan dapat bertingkat (cascade) dengan
::selection. - Merancang kontras, kecocokan saat ini, fokus, dan semantik keyboard.
- Menyediakan fallback yang aman dan mengukur biayanya.
Pertanyaan klarifikasi yang perlu diajukan
- Apakah browser dan WebView target mendukung API ini?
- Apakah dokumen dapat diedit, divirtualisasi, atau sering dirender ulang?
- Berapa banyak kecocokan yang ada, dan bisakah sebuah kecocokan melintasi beberapa text node?
- Apakah mode gelap, forced colors, dan pembaca layar (screen reader) diperlukan?
- Apakah fallback berbasis marked-DOM dapat diterima saat API tidak didukung?
Jawaban 30 detik
“Saya akan merepresentasikan setiap kecocokan sebagai Range, mengelompokkan range dalam sebuah Highlight, dan mendaftarkannya di CSS.highlights untuk penataan gaya ::highlight(name). Saat teks berubah, hapus pendaftaran lama dan bangun kembali dari versi teks dan offset alih-alih mempertahankan node yang terlepas. Pisahkan lapisan pencarian, anotasi, dan kecocokan saat ini; tampilkan jumlah dan status keyboard di luar sekadar warna. Deteksi dukungan fitur, beralih ke teks bertanda yang aman, dan lakukan tolok ukur pada jumlah kecocokan, update p95, frame, dan memori.”
Jawaban mendalam
Langkah 1: Buat range dan highlight
API ini memungkinkan JavaScript membuat Range teks arbitrer, menggabungkannya dalam sebuah Highlight, dan mendaftarkan Highlight tersebut ke dalam HighlightRegistry. CSS menata gaya range tersebut dengan ::highlight(name) tanpa menambahkan elemen pembungkus.
const range = new Range();
range.setStart(textNode, start);
range.setEnd(textNode, end);
const hit = new Highlight(range);
CSS.highlights.set("search", hit);Kode produksi tetap harus menangani range yang melintasi beberapa node dan masa pakai node.
Langkah 2: Rekonsiliasi pembaruan teks
Pertahankan versi dokumen, jalur text-node, dan offset karakter bersama setiap kecocokan. Render ulang atau pengeditan dapat melepaskan node, membuat Range-nya menjadi usang (stale). Hapus entri registri lama dan bangun kembali dari indeks teks baru; jangan hanya menyimpan referensi DOM.
Langkah 3: Kelola lapisan (layers)
Gunakan nama terpisah untuk pencarian, anotasi, kecocokan saat ini, dan saran pemeriksaan ejaan. Tentukan cascade yang diinginkan bersama ::selection dan highlight user-agent lainnya. Memperbarui satu objek kecocokan saat ini tidak boleh memaksa setiap kecocokan untuk dibangun ulang.
Langkah 4: Berikan umpan balik yang aksesibel
Warna tidak boleh menjadi satu-satunya sinyal. Tampilkan jumlah kecocokan saat ini, navigasi yang dapat difokuskan, indikator fokus visual, dan alternatif forced-colors. Jangan berasumsi bahwa highlight itu sendiri akan diumumkan oleh pembaca layar; daftar hasil harus mengekspos status semantik.
Langkah 5: Kendalikan performa
Lakukan debounce pada input, lakukan pembaruan registri secara batch, dan batasi pekerjaan pada jendela yang terlihat jika memungkinkan. Ukur pemindaian teks, update p95, kalkulasi gaya, scroll frame, dan memori. Hindari satu mutasi registri per penekanan tombol.
Langkah 6: Fallback progresif
Lakukan deteksi fitur dan pilih Custom Highlight, marked DOM, atau daftar hasil teks biasa. Fallback DOM harus meng-escape teks, mempertahankan tautan, dan menghindari pembungkus duplikat yang bersarang. Output server harus tetap dapat dibaca sebelum peningkatan di sisi klien dilakukan.
Langkah 7: Pengujian dan penerimaan
Uji kecocokan lintas node, render ulang, pengeditan, mode gelap, forced colors, salin (copy), virtualisasi, RTL, dan browser yang tidak didukung. Bandingkan teks hasil, urutan keyboard, first paint, FPS scroll, update p95, dan memori; fallback tidak boleh menghilangkan kecocokan.
Jawaban model
“Saya akan menjaga DOM dokumen tetap tidak berubah: merepresentasikan kecocokan sebagai Range, mengelompokkannya dalam Highlight, mendaftarkan nama di CSS.highlights, dan menatanya dengan ::highlight(). Setiap hasil membawa versi teks dan offset; perenderan ulang menghapus pendaftaran yang usang dan membangunnya kembali. Pencarian, anotasi, dan kecocokan saat ini memiliki lapisan terpisah, sementara jumlah, fokus, dan status semantik membuat kecocokan saat ini dapat diakses.
Deteksi fitur memilih Custom Highlight atau fallback marked-DOM/daftar hasil yang aman. Debounce, pembaruan batch, dan batasan jendela yang terlihat akan mengendalikan biaya komputasi. Penerimaan mencakup range lintas-node, fungsi salin, pengeditan, mode gelap, forced colors, virtualisasi, dan browser yang tidak didukung, dengan membandingkan p95, FPS, memori, dan kesetaraan hasil.”
Kesalahan umum
- Membungkus setiap kecocokan dalam span → mengganggu struktur teks dan seleksi → lebih baik gunakan Range/Highlight.
- Mempertahankan Range lama → render ulang melepaskan node → bangun kembali berdasarkan versi teks.
- Hanya menggunakan warna → pengguna forced-colors dan buta warna kehilangan informasi status → tambahkan status semantik dan fokus.
- Melakukan mutasi pada setiap tombol → menyebabkan lonjakan beban komputasi gaya (style churn) → lakukan debounce dan batching.
- Menggabungkan (concatenating) HTML fallback → menimbulkan risiko injeksi dan kesalahan nesting → lakukan escape dan batasi range yang ditandai.
Pertanyaan lanjutan dan tanggapan
Pertanyaan lanjutan 1: Mengapa tidak menggunakan span?
Custom Highlight membiarkan DOM tidak berubah, mengurangi interferensi dengan seleksi, pengeditan, dan tata letak. Span tetap menjadi fallback kompatibilitas dengan kontrol escaping dan nesting.
Pertanyaan lanjutan 2: Apa yang terjadi pada Range setelah pengeditan?
Node-nya mungkin diganti atau dilepaskan. Bangun kembali dari versi teks baru dan offset alih-alih menggunakan referensi lama.
Pertanyaan lanjutan 3: Apakah pembaca layar akan mengumumkan highlight?
Jangan berasumsi demikian. Tampilkan jumlah hasil, status saat ini, dan navigasi keyboard sebagai teks semantik.
Pertanyaan lanjutan 4: Bagaimana Anda membuktikan tidak ada regresi?
Gunakan dokumen dan jumlah kecocokan tetap untuk membandingkan update p95, kerja kalkulasi gaya, FPS scroll, memori, perilaku penyalinan, dan virtualisasi.