Labuhkan anotasi pada Range DOM, kemudian letakkan labelnya menggunakan segi empat tepat fragmen yang dirender oleh julat tersebut. Panduan ini menunjukkan demo pelayar desktop Mac ringkas yang mengekalkan nota pada tempatnya apabila frasa merentasi elemen sebaris dan berbalut menjadi beberapa baris.

Tugas ini khusus: lampirkan satu anotasi yang kelihatan pada frasa dalam susun atur halaman web biasa tanpa membina semula teksnya. Anda akan mengenal pasti frasa itu, memilih fragmen untuk label, dan mengukur semula selepas perubahan susun atur. MDN mendokumenkan Range.getClientRects() sebagai API pelayar untuk mendapatkan segi empat tepat yang diduduki oleh julat. Kaedah Range: getClientRects().

Mengapa label tersasar daripada teks yang berbalut?

Sesuatu frasa mempunyai dua perwakilan yang berkaitan: kedudukannya dalam dokumen dan geometri semasanya pada skrin. WHATWG mentakrifkan julat melalui titik sempadan mula dan akhir, yang masing-masing terdiri daripada nod dan ofset. Titik akhir itu boleh terletak dalam nod teks yang berlainan, membolehkan satu julat merentasi elemen penegasan yang sedia ada. Piawaian DOM.

Satu segi empat tepat sempadan menghilangkan perincian. Bayangkan frasa bermula di tengah-tengah satu baris dan berakhir berhampiran permulaan baris seterusnya. Segi empat tepat yang meliputinya merangkumi ruang kosong di sisi kedua-dua baris. Oleh itu, label yang dipusatkan pada segi empat tepat itu boleh kelihatan terpisah daripada perkataan. Floating UI secara jelas mengenal pasti masalah ini bagi pautan berbilang baris dan pilihan julat. sebaris.

Segi empat tepat individu juga perlu ditafsirkan. W3C menyatakan bahawa julat boleh mengembalikan kedua-dua segi empat tepat sempadan elemen yang dipilih dan segi empat tepat teks, mengikut turutan kandungan. Oleh itu, elemen bersarang boleh menghasilkan segi empat tepat yang bertindih; bilangan segi empat tepat bukan ukuran bilangan baris yang boleh dipercayai. Sempadan teks menggunakan metrik fon dan bukannya garis luar glif yang dilukis dengan tepat. Modul CSSOM View.

Fragmen yang manakah patut menjadi sauh anotasi?

Pilih peraturan peletakan sebelum menulis kod penentududukan. Panduan keputusan berikut membezakan teks yang dianotasi daripada tempat labelnya muncul.

Tingkah laku yang dikehendaki Geometri rujukan Peraturan peletakan
Nota yang mengikuti frasa Keseluruhan julat Letakkan di bawah fragmen terakhir yang boleh digunakan dalam susun atur mendatar ringkas dari kiri ke kanan
Label berhampiran interaksi penuding Segi empat tepat fragmen julat Pilih fragmen pada koordinat klien interaksi
Label gambaran keseluruhan berpusat Segi empat tepat yang meliputi keseluruhan julat Terima bahawa label mungkin berada di atas ruang kosong
Penandaan latar bagi keseluruhan frasa Keseluruhan julat Gunakan serlahan teks secara berasingan daripada peletakan label

Demo ini menggunakan peraturan pertama. Demo ini sengaja menetapkan mod penulisan dan arah supaya segi empat tepat terakhir menjadi rujukan titik akhir yang berguna. Anggap itu sebagai syarat contoh ini. W3C menyatakan turutan kandungan bagi segi empat tepat ini; ia tidak menjanjikan turutan sejagat dari penjuru kiri atas ke penjuru kanan bawah. Modul CSSOM View.

Untuk peletakan berasaskan penuding dengan Floating UI, perantara inline() menerima koordinat x dan y relatif kepada ruang pandang. Dokumentasi mengehadkan pilihan berasaskan koordinat ini kepada segi empat tepat yang terpisah, jadi ia tidak patut digambarkan sebagai pemilih aksara tanpa batasan. sebaris.

Bina demo teks berbalut yang lengkap pada Mac

Gunakan versi desktop Firefox semasa dan buka tab kosong pada about:blank. Tekan Command + Option + K untuk membuka Konsol Web halaman tersebut. Mozilla mendokumenkan pintasan ini dan mengesahkan bahawa konsol menjalankan JavaScript dalam konteks halaman. Konsol Web.

Jalankan program lengkap di bawah dalam konsol tersebut. Program ini mencipta semua kandungan sampel, gaya dan kawalannya, jadi projek, import atau pustaka luaran tidak diperlukan. Frasa sintetik itu merentasi elemen penegasan yang sedia ada. Anotasi itu ialah label paparan sahaja; ia tidak mempunyai kawalan penyuntingan.

(() => {
  window.fragmentDemo?.destroy();
  const host = document.createElement('section');
  host.style.cssText = 'margin:48px 24px;padding-bottom:900px';
  const p = document.createElement('p');
  p.dir = 'ltr';
  p.style.cssText = 'font:20px/1.6 Georgia,serif;width:24rem;max-width:80vw;writing-mode:horizontal-tb';
  const a = document.createTextNode('Sample A: amber tiles follow the curved path ');
  const em = document.createElement('em');
  em.textContent = 'past the small blue circle and ';
  const c = document.createTextNode('toward the final silver square. End.');
  p.append(a, em, c);
  const button = document.createElement('button');
  button.textContent = 'Change text width';
  const status = document.createElement('p');
  host.append(button, p, status);
  document.body.append(host);
  const range = document.createRange();
  range.setStart(a, 'Sample A: '.length);
  range.setEnd(c, c.data.indexOf(' End.'));
  const note = document.createElement('div');
  note.textContent = 'Note A: review this phrase';
  note.style.cssText = 'position:fixed;z-index:1000;background:#fff2ad;color:#222;padding:6px 10px;font:14px/1.4 system-ui;pointer-events:none';
  document.body.append(note);
  const style = document.createElement('style');
  style.textContent = '::highlight(fragment-demo) {background-color:#dbeafe;}';
  document.head.append(style);
  const canHighlight = typeof Highlight !== 'undefined' && !!window.CSS?.highlights;
  if (canHighlight) CSS.highlights.set('fragment-demo', new Highlight(range));
  status.textContent = canHighlight ? 'The blue phrase owns Note A.' : 'Text highlighting unavailable; Note A still uses the range.';
  function update() {
    if (!host.isConnected) return;
    const rects = Array.from(range.getClientRects()).filter(r => r.width > 0 && r.height > 0);
    const r = rects.at(-1);
    note.hidden = !r || range.collapsed;
    if (note.hidden) return;
    const maxLeft = Math.max(8, innerWidth - note.offsetWidth - 8);
    note.style.left = Math.max(8, Math.min(r.left, maxLeft)) + 'px';
    note.style.top = (r.bottom + 8) + 'px';
  }
  let narrow = false;
  button.onclick = () => {
    narrow = !narrow;
    p.style.width = narrow ? '16rem' : '24rem';
    update();
  };
  const observer = new ResizeObserver(update);
  observer.observe(p);
  window.addEventListener('resize', update);
  window.addEventListener('scroll', update, true);
  document.fonts.ready.then(update);
  update();
  window.fragmentDemo = {destroy() {
    observer.disconnect();
    window.removeEventListener('resize', update);
    window.removeEventListener('scroll', update, true);
    if (canHighlight) CSS.highlights.delete('fragment-demo');
    host.remove(); note.remove(); style.remove();
  }};
})();

Titik akhirnya mengecualikan awalan Sample A: dan akhiran End.. Klik Change text width untuk bertukar antara dua lebar perenggan. Julat yang sama kekal sebagai sasaran anotasi sementara label diletakkan semula di bawah fragmen terakhir yang boleh digunakan. Tatal dan ubah saiz tetingkap untuk meneliti kelakuannya. Buang demo dengan window.fragmentDemo.destroy().

Program ini lulus semakan sintaks JavaScript, dan ofset sampel serta pengiraan aritmetik kedudukan fragmen lulus semakan deterministik. Pemaparan pelayar tidak dijalankan di sini; langkah di atas membolehkan pengesahan visual.

Bagaimanakah demo mengekalkan aliran dan pembentukan teks?

Julat itu mengukur teks sedia ada. Selepas membina sampel, program membiarkan nod teks dan elemen penegasan frasa itu kekal di tempatnya. Program menambah label secara berasingan dan, secara pilihan, melukis frasa melalui CSS Custom Highlight API, yang menurut dokumentasi MDN berfungsi tanpa mengubah struktur DOM yang mendasarinya. API serlahan tersuai CSS.

Perbezaan itu penting apabila menyesuaikan pendekatan ini. Menambah padding sebaris, sempadan atau jidar antara unit aksara boleh mewujudkan sempadan pembentukan. W3C juga mengenal pasti vertical-align bukan permulaan dan sempadan pengasingan dwiarah sebagai keadaan yang memecahkan pembentukan. Elakkan menyisipkan pembalut aksara yang diletakkan secara individu semata-mata untuk mendapatkan koordinat; ukur hasil sedia ada pelayar. Modul CSS Text Tahap 3, Pembentukan Merentasi Sempadan Elemen.

Bagi teks aplikasi sebenar, tentukan titik akhir julat daripada sempadan teks yang dimaksudkan. Ofset teks DOM menggunakan unit kod; ia bukan bilangan glif yang kelihatan. Pastikan titik akhir sejajar dengan aksara lengkap yang dimaksudkan dan jangan anggap setiap aksara yang dipaparkan menggunakan satu ofset. Piawaian DOM.

Serlahan adalah pilihan. MDN menyenaraikan Highlight sebagai Baseline 2025 dan menyatakan bahawa pelayar lama mungkin tidak menyokongnya. Semakan ciri dalam demo mengekalkan peletakan anotasi apabila serlahan tidak tersedia serta memaparkan mesej status yang menerangkan keadaan itu. Highlight.

Apakah yang perlu dikemas kini apabila halaman mengalir semula?

Demo mengukur semula apabila saiz perenggan berubah, tetingkap diubah saiznya dan halaman ditatal. ResizeObserver mengesan perubahan dimensi elemen, termasuk perubahan yang tidak berkaitan dengan saiz semula tetingkap pelayar. Panggil baliknya di sini hanya menggerakkan label berasingan, lalu mengelakkan gelung maklum balas yang berulang kali mengubah saiz perenggan yang diukur. ResizeObserver.

Pemuatan fon memerlukan kemas kini tersendiri. Program ini mengukur dengan serta-merta, kemudian mengukur semula apabila document.fonts.ready selesai. MDN menyatakan bahawa janji ini selesai selepas pemuatan fon dokumen dan operasi susun atur yang berkaitan tamat. Perubahan fon atau kandungan yang dicetuskan aplikasi kemudian perlu meminta pengukuran baharu secara jelas. Sifat FontFaceSet: ready.

Kekalkan koordinat dalam satu sistem. Demo menggunakan label berkedudukan tetap pada halaman kosong dan menggunakan koordinat klien secara langsung. Menambah ofset tatal dokumen akan menukarkannya kepada koordinat dokumen. MDN menerangkan bahawa segi empat tepat klien adalah relatif kepada ruang pandang dan penambahan ofset tatal ialah penukaran yang digunakan apabila koordinat relatif kepada dokumen dikehendaki. Kaedah Element: getBoundingClientRect().

Contoh ringkas ini mengehadkan peletakan mendatar tetapi tidak melaksanakan pengelakan perlanggaran menegak, penyembunyian apabila di luar skrin atau bekas yang diubah melalui transformasi secara arbitrari. Contoh ini juga tidak memulihkan anotasi selepas muat semula atau penggantian teks sepenuhnya. Bagi aplikasi, kekalkan cara untuk mengenal pasti petikan yang dimaksudkan, bina semula julatnya selepas pemaparan, kemudian ukur semula.

Bilakah anda patut menggunakan Floating UI?

Gunakan Floating UI apabila label memerlukan peletakan yang mengambil kira pemotongan dan kitar hayat kemas kini yang terurus. Antara muka rujukan maya yang didokumenkan menyokong julat melalui dua kaedah: getBoundingClientRect() yang mengembalikan segi empat tepat yang meliputi keseluruhan julat dan getClientRects() yang mengembalikan segi empat tepat fragmennya. Berikan contextElement elemen sebenar yang mengandungi teks supaya pemotongan dan pengesanan kemas kini mempunyai konteks elemen. Elemen Maya.

Hantarkan rujukan maya itu kepada computePosition() dan masukkan inline() berhampiran permulaan tatasusunan perantara, sebelum flip(). Padankan kedudukan CSS elemen terapung dengan strategi yang dipilih. Dokumentasi menerangkan flip() untuk menukar sisi apabila ruang tidak mencukupi dan shift() untuk mengalihkan label dalam had pemotongannya. sebaris, computePosition.

Mulakan autoUpdate() hanya semasa anotasi dipasang, dan panggil fungsi pembersihan yang dikembalikannya apabila label dibuang. Mekanisme kemas kininya yang didokumenkan meliputi penatalan induk, perubahan saiz dan anjakan susun atur. Namun begitu, cetuskan kemas kini selepas perubahan aplikasi yang mengubah fragmen teks yang dipilih tanpa mengubah dimensi bekas yang diperhatikan. autoUpdate.

Diagnosis anotasi yang masih kelihatan tidak betul

Lakukan semakan ini mengikut turutan supaya masalah geometri tidak menyamarkan masalah penyasaran teks.

  1. Sahkan frasa. Periksa range.toString() dan semak kedua-dua titik akhir sebelum melaraskan koordinat.
  2. Periksa fragmen. Log Array.from(range.getClientRects()). Berbilang entri yang bertindih mungkin mencerminkan kandungan sebaris bersarang; jangan tafsirkan bilangannya sebagai bilangan baris.
  3. Semak peraturan peletakan. Segi empat tepat yang meliputi keseluruhan julat, fragmen terakhir dan fragmen yang dipilih melalui penuding memenuhi tingkah laku anotasi yang berbeza.
  4. Semak sistem koordinat. Bagi demo halaman kosong, kekalkan label tetap dalam koordinat klien.
  5. Ulangi selepas perubahan susun atur. Ubah lebar, tatal, ubah saiz dan tunggu fon selesai dimuatkan. Bina semula julat jika aplikasi menggantikan nod teksnya.
  6. Semak andaian susun atur. Bagi penulisan menegak, arah bercampur, lajur atau bekas yang diubah melalui transformasi, takrifkan dan uji peraturan pemilihan fragmen yang sesuai sebelum menggunakan semula pintasan fragmen terakhir dalam demo.

Anotasi yang boleh dipercayai bermula dengan julat teks yang tepat dan peraturan peletakan yang jelas. Biarkan pelayar mengurus pembalutan dan pembentukan, kemudian ukur semula fragmen yang dirender apabila susun atur berkaitan berubah. Ini memberikan nota hubungan yang stabil dengan frasa sambil membolehkan perkataan mengalir secara semula jadi.

Sumber