קטעי טקסט מאפשרים לכם לציין קטע טקסט בפרגמנט ה-URL. כשמנווטים לכתובת URL עם קטע טקסט כזה, הדפדפן יכול להדגיש אותו ולהביא אותו לתשומת ליבו של המשתמש.
מזהי מקטעים (fragment)
גרסה 80 של Chrome הייתה גרסה משמעותית. היא כללה כמה תכונות שחיכו להן הרבה זמן, כמו מודולים של ECMAScript ב-Web Workers, איחוד ערכי null, שרשור אופציונלי ועוד. כמו תמיד, ההודעה על הגרסה פורסמה בפוסט בבלוג של 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 עם קטע טקסט כזה, סוכן המשתמש יכול להדגיש אותו ולהביא אותו לתשומת ליבו של המשתמש.
תאימות דפדפן
מטעמי אבטחה, התכונה דורשת שהקישורים ייפתחו בהקשר של noopener.
לכן, חשוב לכלול את rel="noopener" בתגי העיגון של <a> או להוסיף את noopener לרשימת התכונות של פונקציונליות החלון של Window.open().
start
בצורה הפשוטה ביותר, התחביר של קטעי טקסט הוא: סמל הסולמית #, אחריו :~:text= ולבסוף start, שמייצג את הטקסט בקידוד אחוזים שאליו רוצים לקשר.
#:~:text=start
לדוגמה, נניח שאני רוצה לקשר לכותרת ECMAScript Modules in Web Workers בפוסט בבלוג שבו מוכרזות תכונות ב-Chrome 80, כתובת ה-URL במקרה הזה תהיה:
קטע הטקסט מודגש כך. אם לוחצים על הקישור בדפדפן שתומך בתכונה, כמו Chrome, קטע הטקסט מודגש ומוצג בדף:
start וגם end
מה אם אני רוצה לקשר לכל הקטע שנקרא ECMAScript Modules in Web Workers, ולא רק לכותרת שלו? אם נשתמש בקידוד אחוזים לכל הטקסט של הקטע, כתובת ה-URL שתתקבל תהיה ארוכה מדי ולא נוחה לשימוש.
למזלכם, יש דרך טובה יותר. במקום כל הטקסט, אני יכול לתחום חלק ספציפי בטקסט באמצעות התחביר start,end. אני מציין כמה מילים בקידוד אחוזים בתחילת קטע הטקסט, וכמה מילים בקידוד אחוזים בסוף קטע הטקסט, ומוסיף פסיק ביניהן.
כך זה נראה:
ב-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 כדוגמה? התשובה היא שבגרסה הזו הושקו קטעי טקסט:
שימו לב שבצילום המסך שלמעלה המילה "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, שמאפשר לכם לקשר לכל טקסט על ידי בחירה שלו, ואז לחיצה על "העתקת קישור לטקסט שנבחר" בתפריט ההקשר. התוסף הזה זמין בדפדפנים הבאים:
- קישור לקטע טקסט ב-Google Chrome
- קישור לקטע טקסט ב-Microsoft Edge
- קישור לקטע טקסט ב-Mozilla Firefox
- קישור לקטע טקסט ב-Apple Safari
כמה קטעי טקסט בכתובת 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
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.
יצירת קישור פרוגרמטי ל-Text Fragment
ה-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 של קטעי טקסט שנוצרות באופן אוטומטי.
סיכום
כתובת URL של מקטעי טקסט היא תכונה יעילה שמאפשרת לקשר לטקסט שרירותי בדפי אינטרנט. הקהילה האקדמית יכולה להשתמש בו כדי לספק קישורים מדויקים מאוד לציטוטים או להפניות. מנועי חיפוש יכולים להשתמש בו כדי ליצור קישורי עומק לתוצאות טקסט בדפים. אתרים של רשתות חברתיות יכולים להשתמש בתכונה הזו כדי לאפשר למשתמשים לשתף קטעים ספציפיים של דף אינטרנט במקום צילומי מסך לא נגישים. אני מקווה שתתחילו להשתמש בכתובות URL של קטעי טקסט ותמצאו אותן שימושיות כמוני. הקפידו להתקין את התוסף לדפדפן Link to Text Fragment.
קישורים רלוונטיים
- טיוטת מפרט
- TAG Review
- רישום ב-Chrome Platform Status
- באג מעקב ב-Chrome
- שרשור Intent to Ship
- שרשור WebKit-Dev
- שרשור בנושא עמדת Mozilla לגבי תקנים
תודות
התכונה "קטעי טקסט" הוטמעה וצוינה על ידי ניק בוריס ודיוויד בוקאן, בעזרת גרנט וואנג. תודה ל-Joe Medley על הבדיקה היסודית של המסמך הזה.