קישור מודגש במקום שבו אף אחד לא ביצע קישור לפני כן: קטעי טקסט

קטעי טקסט מאפשרים לכם לציין קטע טקסט בפרגמנט ה-URL. כשמנווטים לכתובת URL עם קטע טקסט כזה, הדפדפן יכול להדגיש אותו ולהביא אותו לתשומת ליבו של המשתמש.

מזהי מקטעים (fragment)

גרסה 80 של Chrome הייתה גרסה משמעותית. היא כללה כמה תכונות שחיכו להן הרבה זמן, כמו מודולים של ECMAScript ב-Web Workers, איחוד ערכי null, שרשור אופציונלי ועוד. כמו תמיד, ההודעה על הגרסה פורסמה בפוסט בבלוג של Chromium. בצילום המסך הבא אפשר לראות קטע מהפוסט בבלוג.

פוסט בבלוג של Chromium עם תיבות אדומות מסביב לרכיבים עם מאפיין id.

בטח שאלתם את עצמכם מה המשמעות של כל התיבות האדומות. הן התוצאה של הרצת קטע הקוד הבא בכלי הפיתוח. הוא מדגיש את כל הרכיבים שיש להם מאפיין id.

document.querySelectorAll('[id]').forEach((el) => {
  el.style.border = 'solid 2px red';
});

אני יכול להוסיף קישור עומק לכל רכיב שמודגש בתיבה אדומה באמצעות מזהה המקטע, שבו אני משתמש בגיבוב (hash) של כתובת ה-URL של הדף. נניח שרציתי ליצור קישור עומק לתיבה Give us feedback in our Product Forums בצד, יכולתי לעשות זאת על ידי יצירה ידנית של כתובת ה-URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1. כמו שאפשר לראות בחלונית Elements של הכלים למפתחים, לרכיב הרלוונטי יש מאפיין id עם הערך HTML1.

כלי פיתוח שמציגים את ה-id של רכיב.

אם מנתחים את כתובת ה-URL הזו באמצעות ה-constructor של URL() ב-JavaScript, הרכיבים השונים נחשפים. שימו לב למאפיין hash עם הערך #HTML1.

new URL('https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1');
/* Creates a new `URL` object
URL {
  hash: "#HTML1"
  host: "blog.chromium.org"
  hostname: "blog.chromium.org"
  href: "https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1"
  origin: "https://blog.chromium.org"
  password: ""
  pathname: "/2019/12/chrome-80-content-indexing-es-modules.html"
  port: ""
  protocol: "https:"
  search: ""
  searchParams: URLSearchParams {}
  username: ""
}
*/

אבל העובדה שהייתי צריך לפתוח את הכלים למפתחים כדי למצוא את ה-id של רכיב מסוים, אומרת הרבה על הסבירות שהמחבר של הפוסט בבלוג התכוון לקשר לחלק הספציפי הזה בדף.

מה אם אני רוצה לקשר למשהו בלי id? נניח שאני רוצה לקשר לכותרת ECMAScript Modules in Web Workers. כמו שאפשר לראות בצילום המסך הבא, ל-<h1> הרלוונטי אין מאפיין id, כלומר אין לי דרך לקשר לכותרת הזו. זו הבעיה שקטעי טקסט פותרים.

כלי פיתוח שמציגים כותרת בלי id.

קטעי טקסט

ההצעה Text Fragments מוסיפה תמיכה בציון קטע טקסט ב-hash של כתובת ה-URL. כשמנווטים לכתובת URL עם קטע טקסט כזה, סוכן המשתמש יכול להדגיש אותו ולהביא אותו לתשומת ליבו של המשתמש.

תאימות דפדפן

Browser Support

  • Chrome: 89.
  • Edge: 89.
  • Firefox: 131.
  • Safari: 18.2.

Source

מטעמי אבטחה, התכונה דורשת שהקישורים ייפתחו בהקשר של noopener. לכן, חשוב לכלול את rel="noopener" בתגי העיגון של <a> או להוסיף את noopener לרשימת התכונות של פונקציונליות החלון של Window.open().

start

בצורה הפשוטה ביותר, התחביר של קטעי טקסט הוא: סמל הסולמית #, אחריו :~:text= ולבסוף start, שמייצג את הטקסט בקידוד אחוזים שאליו רוצים לקשר.

#:~:text=start

לדוגמה, נניח שאני רוצה לקשר לכותרת ECMAScript Modules in Web Workers בפוסט בבלוג שבו מוכרזות תכונות ב-Chrome 80, כתובת ה-URL במקרה הזה תהיה:

https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript%20Modules%20in%20Web%20Workers

קטע הטקסט מודגש כך. אם לוחצים על הקישור בדפדפן שתומך בתכונה, כמו Chrome, קטע הטקסט מודגש ומוצג בדף:

קטע הטקסט נגלל לתצוגה ומודגש.

start וגם end

מה אם אני רוצה לקשר לכל הקטע שנקרא ECMAScript Modules in Web Workers, ולא רק לכותרת שלו? אם נשתמש בקידוד אחוזים לכל הטקסט של הקטע, כתובת ה-URL שתתקבל תהיה ארוכה מדי ולא נוחה לשימוש.

למזלכם, יש דרך טובה יותר. במקום כל הטקסט, אני יכול לתחום חלק ספציפי בטקסט באמצעות התחביר start,end. אני מציין כמה מילים בקידוד אחוזים בתחילת קטע הטקסט, וכמה מילים בקידוד אחוזים בסוף קטע הטקסט, ומוסיף פסיק ביניהן.

כך זה נראה:

https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript%20Modules%20in%20Web%20Workers,ES%20Modules%20in%20Web%20Workers..

ב-start, יש לי ECMAScript%20Modules%20in%20Web%20Workers, ואז פסיק, ואחריו ES%20Modules%20in%20Web%20Workers. בתור end. כשלוחצים על הקישור בדפדפן שתומך בתכונה, כמו Chrome, כל הקטע מודגש ומוצג:

קטע הטקסט נגלל לתצוגה ומודגש.

עכשיו אתם בטח תוהים למה בחרתי ב-start וב-end. למעשה, גם כתובת ה-URL הקצרה יותר https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript%20Modules,Web%20Workers. עם שתי מילים בלבד בכל צד הייתה פועלת. משווים בין start ו-end לערכים הקודמים.

אם נמשיך צעד אחד קדימה ונשתמש במילה אחת בלבד גם ל-start וגם ל-end, אפשר לראות שיש בעיה. כתובת ה-URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript,Workers. עכשיו קצרה עוד יותר, אבל קטע הטקסט המודגש הוא כבר לא זה שנבחר במקור. ההדגשה נעצרת במופע הראשון של המילה Workers., וזה נכון, אבל לא מה שהתכוונתי להדגיש. הבעיה היא שהקטע שנבחר לא מזוהה באופן ייחודי על ידי הערכים הנוכחיים של start ו-end, שמורכבים ממילה אחת:

קטע טקסט לא רצוי נגלל לתצוגה והודגש.

prefix- וגם -suffix

שימוש בערכים ארוכים מספיק בשביל start ו-end הוא פתרון אחד לקבלת קישור ייחודי. עם זאת, במצבים מסוימים זה לא אפשרי. דרך אגב, למה בחרתי בפוסט בבלוג על גרסת Chrome 80 כדוגמה? התשובה היא שבגרסה הזו הושקו קטעי טקסט:

טקסט של פוסט בבלוג: פרגמנטים של כתובות URL של טקסט. עכשיו משתמשים או יוצרים יכולים לקשר לחלק ספציפי בדף באמצעות קטע טקסט שמופיע בכתובת URL. כשהדף נטען, הדפדפן מדגיש את הטקסט וגולל את הקטע לתצוגה. לדוגמה, כתובת ה-URL הבאה טוענת דף ויקי בנושא &quot;חתול&quot; וגוללת לתוכן שמופיע בפרמטר `text`.
קטע מפוסט בבלוג שבו הוכרז על Text Fragments.

שימו לב שבצילום המסך שלמעלה המילה "text" מופיעה ארבע פעמים. המופע הרביעי כתוב בגופן קוד ירוק. אם הייתי רוצה לקשר למילה הספציפית הזו, הייתי מגדיר את start לערך text. המילה "טקסט" היא, ובכן, רק מילה אחת, אז לא יכול להיות end. מה עכשיו? כתובת ה-URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=text תואמת למופע הראשון של המילה "Text" שכבר נמצאת בכותרת:

התאמה של קטע טקסט במופע הראשון של "טקסט".

למזלנו, יש פתרון. במקרים כאלה, אני יכול לציין prefix- ו-suffix. המילה שלפני "text" בגופן הירוק של הקוד היא "the", והמילה שאחרי היא "parameter". לאף אחד משלושת המופעים האחרים של המילה "text" אין את אותן מילים מסביב. עם המידע הזה, אני יכול לשנות את כתובת ה-URL הקודמת ולהוסיף את prefix- ו--suffix. כמו הפרמטרים האחרים, גם הם צריכים להיות מקודדים באחוזים ויכולים להכיל יותר ממילה אחת. https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=the-,text,-parameter. כדי לאפשר למנתח לזהות בבירור את prefix- ואת -suffix, צריך להפריד אותם מ-start ומ-end האופציונלי באמצעות מקף -.

קטע טקסט שתואם למופע שנבחר של "טקסט".

התחביר המלא

התחביר המלא של קטעי טקסט מפורט בהמשך. (סוגריים מרובעים מציינים פרמטר אופציונלי). הערכים של כל הפרמטרים צריכים להיות מקודדים בקידוד URL. זה חשוב במיוחד לגבי התווים מקף -, אמפרסנד & ופסיק ,, כדי שהם לא יפורשו כחלק מהתחביר של הוראת הטקסט.

#:~:text=[prefix-,]start[,end][,-suffix]

כל אחד מהרכיבים prefix-,‏ start,‏ end ו--suffix יכול להתאים רק לטקסט בתוך רכיב יחיד ברמת הבלוק, אבל טווחים מלאים של start,end יכולים להשתרע על פני כמה בלוקים. לדוגמה, הביטוי :~:text=The quick,lazy dog לא תואם בדוגמה הבאה, כי המחרוזת הראשונית "The quick" לא מופיעה בתוך רכיב יחיד ברמת הבלוק, ללא הפרעות:

<div>
  The
  <div></div>
  quick brown fox
</div>
<div>jumped over the lazy dog</div>

עם זאת, יש התאמה בדוגמה הזו:

<div>The quick brown fox</div>
<div>jumped over the lazy dog</div>

יצירת כתובות URL של קטעי טקסט באמצעות תוסף לדפדפן

יצירה ידנית של כתובות URL עם מקטעי טקסט היא תהליך מייגע, במיוחד כשצריך לוודא שהן ייחודיות. אם אתם ממש רוצים, במפרט יש כמה טיפים ורשימה של השלבים המדויקים ליצירת כתובות URL של קטעי טקסט. אנחנו מספקים תוסף לדפדפן בקוד פתוח שנקרא Link to Text Fragment, שמאפשר לכם לקשר לכל טקסט על ידי בחירה שלו, ואז לחיצה על "העתקת קישור לטקסט שנבחר" בתפריט ההקשר. התוסף הזה זמין בדפדפנים הבאים:

Link to Text Fragment לדפדפן.

כמה קטעי טקסט בכתובת URL אחת

חשוב לשים לב שכמה קטעי טקסט יכולים להופיע בכתובת URL אחת. צריך להפריד בין קטעי הטקסט הספציפיים באמצעות תו אמפרסנד &. הנה דוגמה לקישור עם שלושה קטעי טקסט: https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=Text%20URL%20Fragments&text=text,-parameter&text=:~:text=On%20islands,%20birds%20can%20contribute%20as%20much%20as%2060%25%20of%20a%20cat's%20diet.

שלושה קטעי טקסט בכתובת URL אחת.

שילוב של רכיבים וקטעי טקסט

אפשר לשלב קטעי רכיבים מסורתיים עם קטעי טקסט. אין שום בעיה להשתמש בשני הסוגים באותה כתובת URL, למשל כדי לספק חלופה משמעותית למקרה שהטקסט המקורי בדף ישתנה, כך שקטע הטקסט לא יתאים יותר. כתובת ה-URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1:~:text=Give%20us%20feedback%20in%20our%20Product%20Forums. שמפנה לקטע Give us feedback in our Product Forums מכילה גם מקטע של רכיב (HTML1) וגם מקטע של טקסט (text=Give%20us%20feedback%20in%20our%20Product%20Forums.):

קישור גם עם מקטע של רכיב וגם עם מקטע של טקסט.

הוראת המקטע

יש רכיב אחד בתחביר שעדיין לא הסברתי: ההנחיה :~:. כדי למנוע בעיות תאימות עם מקטעים קיימים של רכיבי כתובת URL, כמו בדוגמה שלמעלה, המפרט של מקטעי הטקסט כולל את ההנחיה fragment. הוראת הפרגמנט היא חלק מפרגמנט URL שמוגדר על ידי רצף הקוד :~:. הוא שמור להוראות של סוכן המשתמש, כמו text=, והוא מוסר מכתובת ה-URL במהלך הטעינה כדי שסקריפטים של המחבר לא יוכלו לקיים איתו אינטראקציה ישירה. ההוראות לסוכן המשתמש נקראות גם הנחיות. במקרה הספציפי הזה, text= נקרא הוראת טקסט.

זיהוי תכונות

כדי לזהות תמיכה, בודקים את המאפיין fragmentDirective לקריאה בלבד ב-document. ההנחיה fragment directive היא מנגנון שמאפשר לכתובות URL לציין הוראות שמיועדות לדפדפן ולא למסמך. היא נועדה למנוע אינטראקציה ישירה עם הסקריפט של היוצר, כדי שיהיה אפשר להוסיף הוראות עתידיות לסוכן המשתמש בלי לחשוש משינויי תוכנה שעלולים לגרום לכשל בתוכן הקיים. דוגמה אחת לתוספות עתידיות כאלה יכולה להיות רמזים לתרגום.

if ('fragmentDirective' in document) {
  // Text Fragments is supported.
}

זיהוי תכונות מיועד בעיקר למקרים שבהם קישורים נוצרים באופן דינמי (לדוגמה, על ידי מנועי חיפוש) כדי להימנע מהצגת קישורים לקטעי טקסט בדפדפנים שלא תומכים בהם.

עיצוב קטעי טקסט

כברירת מחדל, דפדפנים מעצבים קטעי טקסט באותו אופן שבו הם מעצבים את mark (בדרך כלל שחור על גבי צהוב, צבעי המערכת של CSS ל-mark). גיליון הסגנונות של סוכן המשתמש מכיל CSS שנראה כך:

:root::target-text {
  color: MarkText;
  background: Mark;
}

כמו שאפשר לראות, הדפדפן חושף סלקטור פסאודו ::target-text שבו אפשר להשתמש כדי להתאים אישית את ההדגשה. לדוגמה, אפשר לעצב את קטעי הטקסט כך שיופיעו כטקסט שחור על רקע אדום. כמו תמיד, חשוב לבדוק את ניגודיות הצבעים כדי לוודא שהעיצוב החדש לא גורם לבעיות נגישות, ושההדגשה באמת בולטת מבחינה חזותית משאר התוכן.

:root::target-text {
  color: black;
  background-color: red;
}

Polyfill

אפשר להשתמש ב-polyfill במידה מסוימת בתכונה "קטעי טקסט". אנחנו מספקים polyfill, שמשמש באופן פנימי את התוסף, לדפדפנים שלא מספקים תמיכה מובנית ב-Text Fragments שבהם הפונקציונליות מוטמעת ב-JavaScript.

ה-polyfill מכיל קובץ fragment-generation-utils.js שאפשר לייבא ולהשתמש בו כדי ליצור קישורים לקטעי טקסט. הדוגמה הבאה ממחישה את זה:

const { generateFragment } = await import('https://unpkg.com/text-fragments-polyfill/dist/fragment-generation-utils.js');
const result = generateFragment(window.getSelection());
if (result.status === 0) {
  let url = `${location.origin}${location.pathname}${location.search}`;
  const fragment = result.fragment;
  const prefix = fragment.prefix ?
    `${encodeURIComponent(fragment.prefix)}-,` :
    '';
  const suffix = fragment.suffix ?
    `,-${encodeURIComponent(fragment.suffix)}` :
    '';
  const start = encodeURIComponent(fragment.textStart);
  const end = fragment.textEnd ?
    `,${encodeURIComponent(fragment.textEnd)}` :
    '';
  url += `#:~:text=${prefix}${start}${end}${suffix}`;
  console.log(url);
}

קבלת קטעי טקסט למטרות ניתוח נתונים

הרבה אתרים משתמשים במקטע לניתוב, ולכן הדפדפנים מסירים את מקטעי הטקסט כדי לא לשבש את הדפים האלה. יש צורך מוכר לחשוף קישורים של קטעי טקסט לדפים, למשל למטרות ניתוח, אבל הפתרון המוצע עדיין לא יושם. כפתרון זמני, אתם יכולים להשתמש בקוד הבא כדי לחלץ מידע.

new URL(performance.getEntries().find(({ type }) => type === 'navigate').name).hash;

אבטחה

הוראות של קטעי טקסט מופעלות רק בניווטים מלאים (לא באותו דף) שנובעים מפעילות משתמש. בנוסף, אם הניווט מתחיל ממקור שונה מהיעד, הוא צריך להתבצע בהקשר של noopener, כדי שדף היעד יהיה מבודד מספיק. הוראות של קטעי טקסט חלות רק על המסגרת הראשית. כלומר, לא מתבצע חיפוש של טקסט בתוך רכיבי iframe, וניווט ב-iframe לא מפעיל קטע טקסט.

פרטיות

חשוב שההטמעות של מפרט קטעי הטקסט לא ידליפו מידע על כך שקטע טקסט נמצא בדף או לא. בעוד שקטעי רכיבים נמצאים בשליטה מלאה של מחבר הדף המקורי, כל אחד יכול ליצור קטעי טקסט. זוכרים שבדוגמה שלי לא הייתה דרך לקשר לכותרת ECMAScript Modules in Web Workers, כי ל-<h1> לא היה id, אבל כל אחד, כולל אני, יכול פשוט לקשר לכל מקום על ידי יצירה קפדנית של קטע הטקסט?

נניח שאני מפעיל רשת מודעות זדונית evil-ads.example.com. נניח גם שבאחד מה-iframes של המודעות שלי, יצרתי באופן דינמי iframe מוסתר ממקורות שונים ל-dating.example.com עם כתובת URL של קטע טקסט dating.example.com#:~:text=Log%20Out ברגע שהמשתמש יוצר אינטראקציה עם המודעה. אם הטקסט "התנתקות" נמצא, אני יודע שהקורבן מחובר אל dating.example.com, ואני יכול להשתמש בזה כדי ליצור פרופיל משתמש. הטמעה פשוטה של קטעי טקסט עשויה להחליט שהתאמה מוצלחת צריכה לגרום להחלפת המיקוד, ב-evil-ads.example.com אפשר להאזין לאירוע blur וכך לדעת מתי התרחשה התאמה. ב-Chrome, הטמענו את Text Fragments באופן שמונע תרחיש כזה.

מתקפה אחרת יכולה להיות ניצול של התנועה ברשת על סמך מיקום הגלילה. נניח שהייתה לי גישה ליומני התנועה ברשת של הקורבן, למשל כאדמין של אינטראנט של חברה. עכשיו דמיינו שיש מסמך ארוך של משאבי אנוש בשם מה לעשות אם אתם סובלים מ… ואז רשימה של מצבים כמו שחיקה, חרדה וכו'. אני יכול להציב פיקסל מעקב ליד כל פריט ברשימה. אם אקבע שטעינת המסמך מתרחשת בו-זמנית עם טעינת הפיקסל למעקב לצד הפריט שחיקה, אוכל, כמנהל האינטראנט, לקבוע שעובד לחץ על קישור לקטע טקסט עם :~:text=burn%20out, שהעובד אולי הניח שהוא סודי ולא גלוי לאף אחד. מכיוון שהדוגמה הזו קצת מומצאת מלכתחילה, וכדי לנצל אותה צריך לעמוד בתנאים מוקדמים מאוד ספציפיים, צוות האבטחה של Chrome העריך שאפשר לנהל את הסיכון שבהטמעת גלילה בניווט. סוכני משתמש אחרים עשויים להציג במקום זאת רכיב בממשק המשתמש לגלילה ידנית.

אתרים שרוצים לבטל את ההסכמה יכולים לשלוח ערך כותרת של מדיניות מסמכים שנתמך ב-Chromium, כדי שסוכני משתמשים לא יעבדו כתובות URL של קטעי טקסט.

Document-Policy: force-load-at-top

השבתת קטעי טקסט

הדרך הכי קלה להשבית את התכונה היא להשתמש בתוסף שיכול להוסיף כותרות של תגובות HTTP, למשל ModHeader (לא מוצר של Google), כדי להוסיף כותרת של תגובה (לא בקשה) באופן הבא:

Document-Policy: force-load-at-top

דרך נוספת, מורכבת יותר, היא להשתמש בהגדרה ברמת הארגון ScrollToTextFragmentEnabled. כדי לעשות את זה ב-macOS, מדביקים את הפקודה הבאה במסוף.

defaults write com.google.Chrome ScrollToTextFragmentEnabled -bool false

ב-Windows, פועלים לפי ההוראות שבמסמכי התיעוד באתר התמיכה של מרכז העזרה של Google Chrome Enterprise.

בחיפושים מסוימים, מנוע החיפוש של Google מספק תשובה מהירה או סיכום עם תקציר תוכן מאתר רלוונטי. תקצירי תוצאות החיפוש הראשונות האלה מוצגים בדרך כלל כשהחיפוש הוא בצורת שאלה. לחיצה על תקציר תוצאת החיפוש הראשונה מעבירה את המשתמש ישירות לטקסט של תקציר תוצאת החיפוש הראשונה בדף האינטרנט המקורי. זה מתאפשר בזכות כתובות URL של קטעי טקסט שנוצרות באופן אוטומטי.

דף תוצאות חיפוש ב-Google שמוצג בו תקציר תוצאת החיפוש הראשונה. בשורת הסטטוס מוצגת כתובת ה-URL של קטעי הטקסט.
אחרי שלוחצים על הקישור, החלק הרלוונטי בדף נגלל לתצוגה.

סיכום

כתובת URL של מקטעי טקסט היא תכונה יעילה שמאפשרת לקשר לטקסט שרירותי בדפי אינטרנט. הקהילה האקדמית יכולה להשתמש בו כדי לספק קישורים מדויקים מאוד לציטוטים או להפניות. מנועי חיפוש יכולים להשתמש בו כדי ליצור קישורי עומק לתוצאות טקסט בדפים. אתרים של רשתות חברתיות יכולים להשתמש בתכונה הזו כדי לאפשר למשתמשים לשתף קטעים ספציפיים של דף אינטרנט במקום צילומי מסך לא נגישים. אני מקווה שתתחילו להשתמש בכתובות URL של קטעי טקסט ותמצאו אותן שימושיות כמוני. הקפידו להתקין את התוסף לדפדפן Link to Text Fragment.

תודות

התכונה "קטעי טקסט" הוטמעה וצוינה על ידי ניק בוריס ודיוויד בוקאן, בעזרת גרנט וואנג. תודה ל-Joe Medley על הבדיקה היסודית של המסמך הזה.