Fragmenty tekstu pogrubione linki, do których nikt wcześniej nie linkował

Dzięki fragmentom tekstu możesz umieścić fragment tekstu we fragmencie adresu URL. Podczas otwierania adresu URL z takim fragmentem tekstu przeglądarka może go uwydatnić i/lub zwrócić na niego uwagę użytkownika.

Identyfikatory fragmentów

Chrome 80 okazał się wielkim hitem. Zawierała ona szereg bardzo oczekiwanych funkcji, takich jak moduły ECMAScript w środowiskach Web Workers, łączenie zerowe, opcjonalne łańcuch i wiele innych. Jak zwykle ogłosiliśmy o premierze w poście na blogu na blogu Chromium. Fragment posta możesz zobaczyć na poniższym zrzucie ekranu.

Post na blogu Chromium z czerwonymi polami wokół elementów z atrybutem id.

Pewnie zastanawiasz się, co oznaczają wszystkie czerwone pola. Są one wynikiem uruchomienia tego fragmentu w Narzędziach deweloperskich. Wyróżnia wszystkie elementy, które mają atrybut id.

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

Mogę umieścić precyzyjny link do dowolnego elementu wyróżnionego czerwonym polem dzięki identyfikatorowi fragmentu, którego używam później w szyfrowaniu adresu URL strony. Zakładając, że chcę przesłać precyzyjny link do pola Fora produktów, mogę ręcznie utworzyć adres URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1. Jak widać w panelu Elementy w Narzędziach dla deweloperów, dany element ma atrybut id o wartości HTML1.

Narzędzia deweloperskie pokazujące id elementu.

Analizując ten adres URL za pomocą konstruktora URL() w języku JavaScript, ujawniam różne komponenty. Zwróć uwagę na właściwość hash o wartości #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: ""
}
*/

Sam fakt, że trzeba było otworzyć narzędzia dla programistów, by znaleźć id elementu, mówi wiele o tym, jakie jest prawdopodobieństwo, że autor posta na blogu ma zamieścić link do tej konkretnej sekcji strony.

Co zrobić, jeśli chcę utworzyć link do elementu bez atrybutu id? Powiedzmy, że chcę utworzyć link do nagłówka ECMAScript Modules in Web Workers (Moduły ECMAScript w instancjach Web Workers). Jak widać na zrzucie ekranu poniżej, wskazane pole <h1> nie ma atrybutu id, co oznacza, że nie mogę dodać linku do tego nagłówka. Ten problem rozwiązuje fragmenty tekstu.

Narzędzia deweloperskie z nagłówkiem bez id.

Fragmenty tekstu

Propozycja Fragmenty tekstu umożliwia określanie fragmentu tekstu w ramach skrótu adresu URL. Podczas otwierania adresu URL z takim fragmentem tekstu klient użytkownika może go uwydatnić lub zwrócić na niego uwagę.

Zgodność z przeglądarką

Obsługa przeglądarek

  • 89
  • 89
  • x
  • x

Źródło

Ze względów bezpieczeństwa ta funkcja wymaga, aby linki otwierały się w kontekście noopener. Dlatego pamiętaj o umieszczeniu rel="noopener" w znacznikach kotwicy <a> lub dodaj noopener do listy Window.open() funkcji okna.

start

W najprostszej postaci składnia fragmentów tekstu jest następująca: symbol skrótu #, po którym następuje :~:text=, a na koniec start oznaczający zakodowany procentowo tekst, do którego chcę utworzyć link.

#:~:text=start

Jeśli na przykład chcę utworzyć link do nagłówka ECMAScript Modules in Web Workers (Moduły ECMAScript w aplikacjach Web Workers) w poście na blogu z informacjami o funkcjach w Chrome 80, adres URL w tym przypadku będzie wyglądał tak:

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

Fragment tekstu jest wyróżniony w ten sposób. Jeśli klikniesz link w obsługiwanej przeglądarce, takiej jak Chrome, fragment tekstu zostanie podświetlony i przewinie się do widoku:

Fragment tekstu został przewinięty do widoku i wyróżniony.

startend

Co w sytuacji, gdy chcę dodać link do całej sekcji zatytułowanej ECMAScript Modules w Web Workers, a nie tylko do jej nagłówka? Kodowanie procentowe całego tekstu sekcji sprawiłoby, że wynikowy URL byłby niepraktycznie długi.

Na szczęście istnieje lepszy sposób. Zamiast całego tekstu mogę wykadrować wybrany tekst, korzystając ze składni start,end. Dlatego określam kilka słów zakodowanych procentowo na początku żądanego tekstu, a kilka takich słów na końcu, rozdzielone przecinkami ,.

Wygląda to tak:

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

W przypadku start mam element ECMAScript%20Modules%20in%20Web%20Workers, następnie przecinek , i ES%20Modules%20in%20Web%20Workers. jako end. Po kliknięciu odpowiedniej przeglądarki, np. Chrome, cała sekcja jest podświetlana i przewinięta do widoku:

Fragment tekstu został przewinięty do widoku i wyróżniony.

Teraz możesz zastanawiać się nad wyborem start i end. Krótszy adres URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript%20Modules,Web%20Workers. też zadziałałby z 2 słowami po każdej stronie. Porównaj start i end z poprzednimi wartościami.

Jeśli pójdę o krok dalej i użyję tylko jednego słowa w przypadku start i end, łatwo zorientuję się, że mam kłopoty. Adres URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript,Workers. jest teraz jeszcze krótszy, ale wyróżniony fragment tekstu nie jest już pożądanym fragmentem. Wyróżnienie zatrzyma się na pierwszym wystąpieniu słowa Workers., które jest prawidłowe, ale nie zostało tak oznaczone. Problem polega na tym, że żądana sekcja nie jest jednoznacznie identyfikowana przez bieżące jednowyrazowe wartości start i end:

Niezamierzony fragment tekstu został przewinięty do widoku i podświetlony.

prefix--suffix

Jednym z rozwiązań, aby uzyskać unikalny link, jest użycie wystarczająco długich wartości w polach start i end. W niektórych sytuacjach nie jest to jednak możliwe. Na marginesie: dlaczego jako przykład wybrałam posta na blogu na temat wersji Chrome 80? Odpowiedź brzmi: w tej wersji wprowadziliśmy fragmenty tekstu:

Tekst posta na blogu: Fragmenty adresu URL tekstu. Użytkownicy i autorzy mogą teraz tworzyć linki do konkretnych fragmentów strony, korzystając z fragmentów tekstu w adresie URL. Podczas wczytywania strony przeglądarka podświetla tekst i przewija fragment, aby był widoczny. Na przykład poniższy URL wczytuje stronę wiki o słowie „Kot” i przewija do treści wymienionej w parametrze „tekst”.
Fragment posta na blogu z ogłoszeniem o fragmentach tekstu.

Zwróć uwagę, że na zrzucie ekranu nad słowem „tekst” występuje 4 razy. Następne wystąpienie jest zapisane zieloną czcionką. Jeśli chcę utworzyć link do tego konkretnego słowa, ustaw start na text. Słowo „tekst” jest tylko jednym słowem, więc nie może być end. Co teraz? Adres URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=text pasuje do pierwszego wystąpienia słowa „Text” występującego już w nagłówku:

Dopasowanie fragmentu tekstu w pierwszym wystąpieniu ciągu „Text”.

Na szczęście jest na to rozwiązanie. W takich przypadkach mogę określić prefix​- i -suffix. Słowo przed czcionką zielonego kodu „tekst” to „the”, a słowem po nim jest „parameter”. Żadne z 3 pozostałych wystąpień słowa „tekst” nie ma takich samych słów. Dzięki tej wiedzy mogę ulepszyć poprzedni adres URL i dodać prefix- oraz -suffix. Podobnie jak pozostałe parametry, również muszą być zakodowane za pomocą procentów i mogą zawierać więcej niż 1 słowo. https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=the-,text,-parameter. Aby parser mógł wyraźnie zidentyfikować prefix- i -suffix, muszą one być oddzielone od start i opcjonalnych end myślnikiem -.

Dopasowanie fragmentu tekstu w odpowiednim wystąpieniu „tekst”.

Pełna składnia

Pełna składnia fragmentów tekstu jest przedstawiona poniżej. Nawiasy kwadratowe oznaczają parametr opcjonalny. Wartości wszystkich parametrów muszą być zakodowane z użyciem wartości procentowych. Jest to szczególnie ważne w przypadku znaków -, ampersandów & i , przecinka, więc nie są interpretowane jako część składni dyrektywy tekstowej.

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

Każdy z tych elementów prefix-, start, end i -suffix będzie pasować do tekstu tylko w obrębie jednego elementu na poziomie bloku, ale pełne zakresy start,end mogą obejmować wiele bloków. Na przykład ciąg :~:text=The quick,lazy dog nie dopasuje się do tego przykładu, ponieważ początkowy ciąg znaków „The fast” nie pojawi się w jednym, nieprzerwanym elemencie na poziomie bloku:

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

Pasuje to jednak do tego przykładu:

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

Tworzenie adresów URL fragmentów tekstu za pomocą rozszerzenia przeglądarki

Ręczne tworzenie adresów URL fragmentów tekstu jest uciążliwe, zwłaszcza gdy chodzi o zapewnianie ich unikalności. Jeśli naprawdę chcesz, przeczytaj specyfikację, która zawiera kilka wskazówek i opisuje dokładne instrukcje generowania adresów URL fragmentów tekstu. Udostępniamy rozszerzenie przeglądarki typu open source o nazwie Link do fragmentu tekstu, które umożliwia dodanie linku do dowolnego tekstu przez jego zaznaczenie i kliknięcie „Kopiuj link do wybranego tekstu” w menu kontekstowym. To rozszerzenie jest dostępne w następujących przeglądarkach:

Link do fragmentu tekstu w rozszerzeniu przeglądarki.

Wiele fragmentów tekstu w jednym adresie URL

Pamiętaj, że w jednym adresie URL może pojawić się wiele fragmentów tekstu. Poszczególne fragmenty tekstu muszą być rozdzielone ampersandem &. Oto przykładowy link z 3 fragmentami tekstu: 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.

3 fragmenty tekstu w jednym adresie URL.

Łączenie elementów z tekstem

Tradycyjne fragmenty elementów można łączyć z fragmentami tekstu. Można używać obu adresów w tym samym adresie URL, np. umożliwiać stosowanie wartości zastępczej na wypadek zmiany oryginalnego tekstu na stronie, dzięki czemu fragment tekstu nie będzie już dopasowywany. Adres URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1:~:text=Give%20us%20feedback%20in%20our%20Product%20Forums. prowadzący do sekcji Prześlij opinię w sekcji Fora usług zawiera zarówno fragment elementu (HTML1), jak i tekst (text=Give%20us%20feedback%20in%20our%20Product%20Forums.):

Połączenie z fragmentem elementu i fragmentem tekstu

Dyrektywa fragment

Jest jeden element składni, którego jeszcze nie omówiliśmy: dyrektywa fragment :~:. Aby uniknąć problemów ze zgodnością z istniejącymi fragmentami elementów adresu URL, jak pokazano powyżej, specyfikacja fragmentów tekstu wprowadza dyrektywę dotyczącą fragmentu. Dyrektywa „fragment” to część fragmentu adresu URL rozdzielonych sekwencją kodu :~:. Jest zarezerwowana na instrukcje związane z klientem użytkownika, np. text=, i jest usuwana z adresu URL podczas wczytywania, aby skrypty autorskie nie mogły bezpośrednio z nimi korzystać. Instrukcje dotyczące klienta użytkownika są też nazywane dyrektywami. W konkretnym przypadku właściwość text= jest nazywana dyrektywą tekstową.

Wykrywanie funkcji

Aby wykryć obsługę, przetestuj właściwość fragmentDirective tylko do odczytu w document. Dyrektywa fragmentowa to mechanizm stosowany w przypadku adresów URL do określania instrukcji skierowanych do przeglądarki, a nie do dokumentu. Ma to na celu uniknięcie bezpośredniej interakcji ze skryptem autora, dzięki czemu można będzie dodawać kolejne instrukcje dotyczące klientów użytkownika bez obaw o wprowadzanie zmian powodujących niezgodność w istniejących treściach. Jednym z przykładów takich dodania w przyszłości mogą być wskazówki dotyczące tłumaczeń.

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

Wykrywanie funkcji przydaje się głównie w przypadkach, gdy linki są generowane dynamicznie (np. przez wyszukiwarki), aby uniknąć wyświetlania fragmentów tekstu linków w przeglądarkach, które ich nie obsługują.

Style fragmentów tekstu

Domyślnie przeglądarki ustalają style fragmentów tekstu w taki sam sposób, w jaki określa styl mark (zwykle jest on czarny na żółtym, a kolory systemowe CSS w przypadku mark). Arkusz stylów klienta użytkownika zawiera taki kod CSS:

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

Jak widać, przeglądarka wyświetla pseudoselektor ::target-text, którego można użyć do dostosowania zastosowanego wyróżnienia. Możesz np. zaprojektować fragmenty tekstu tak, aby były czarne na czerwonym tle. Jak zawsze pamiętaj o sprawdzeniu kontrastu kolorów, aby zastępowanie stylu nie powodowało problemów z ułatwieniami dostępu i dopilnowania, aby wyróżnienie wyraźnie wyróżniało się na tle reszty treści.

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

Polyfillability

Funkcja „Fragmenty tekstu” może być w pewnym stopniu wypełniana poligraficznie. Na potrzeby przeglądarek, które nie obsługują wbudowanej obsługi fragmentów tekstu, a funkcje są implementowane w kodzie JavaScript, udostępniamy kod polyfill używany wewnętrznie przez rozszerzenie.

Element polyfill zawiera plik fragment-generation-utils.js, który możesz zaimportować i wykorzystać do generowania linków do fragmentów tekstu. Zostało to opisane w przykładowym kodzie poniżej:

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);
}

Uzyskiwanie fragmentów tekstu do celów analitycznych

Wiele witryn używa tego fragmentu do kierowania ruchu, dlatego przeglądarki usuwają z niego fragmenty tekstu, aby nie uszkodzić tych stron. Istnieje potwierdzona potrzeba udostępniania linków z fragmentami tekstu do stron np. do celów analitycznych, ale proponowane rozwiązanie nie zostało jeszcze wdrożone. Aby obejść ten problem, możesz użyć poniższego kodu do wyodrębnienia potrzebnych informacji.

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

Bezpieczeństwo

Dyrektywy dotyczące fragmentów tekstu są wywoływane tylko w przypadku pełnych nawigacji (innych niż na tej samej stronie) w wyniku aktywacji użytkownika. Poza tym nawigacja z innego miejsca wylotu będzie wymagać, aby nawigacja odbyła się w kontekście noopener, tak aby strona docelowa była wystarczająco odizolowana. Dyrektywy dotyczące fragmentów tekstu są stosowane tylko do ramki głównej. Oznacza to, że tekst nie będzie przeszukiwany w elementach iframe, a nawigacja w elementach iframe nie będzie wywoływać fragmentu tekstu.

Prywatność

Ważne jest, aby implementacje specyfikacji fragmentów tekstu nie informowały o tym, czy na stronie znaleziono dany fragment tekstu. Fragmenty elementów są w pełni pod kontrolą autora oryginalnej strony, ale każdy może je tworzyć. Przypomnijmy sobie, że w powyższym przykładzie nie ma możliwości dodania linku do nagłówka ECMAScript Modules in Web Workers (Moduły ECMAScript w środowiskach Web Workers), ponieważ element <h1> nie miał parametru id, ale jak ktokolwiek, w tym ja, mógłby po prostu utworzyć link do dowolnego miejsca, starannie tworząc odpowiedni fragment tekstu?

Wyobraź sobie, że prowadzisz złą sieć reklamową evil-ads.example.com. Wyobraź sobie, że w jednym z moich elementów iframe z reklamami dynamicznie utworzyłem ukryty element iframe z innych domen w witrynie dating.example.com z adresem URL fragmentu tekstu dating.example.com#:~:text=Log%20Out, gdy użytkownik wejdzie w interakcję z reklamą. Jeśli zostanie znaleziony tekst „Wyloguj się”, ofiara jest obecnie zalogowana w usłudze dating.example.com, której mogę użyć do profilowania użytkowników. Ponieważ implementacja naiwnych fragmentów tekstu może zdecydować, że udane dopasowanie powinno spowodować przełączenie zaznaczenia, na evil-ads.example.com mogę nasłuchiwać zdarzenia blur i w ten sposób wiedzieć, kiedy wystąpiło dopasowanie. Wprowadziliśmy w Chrome fragmenty tekstu w taki sposób, że nie może dojść do takiej sytuacji.

Kolejnym atakiem może być wykorzystanie ruchu sieciowego na podstawie pozycji przewijania. Załóżmy, że mam dostęp do dzienników ruchu sieciowego ofiary, np. administratora firmowego intranetu. Teraz wyobraźmy sobie, że istnieje długi dokument dla kadr (Co zrobić, jeśli cierpię na...) i lista takich chorób jak wypalenie, lęk itd. Mógłbym umieścić piksel śledzący obok każdej pozycji na liście. Jeśli następnie uznam, że wczytywanie dokumentu odbywa się jednocześnie z wczytywaniem piksela śledzącego obok elementu wypalenia, jako administrator intranetu będę w stanie ustalić, czy pracownik kliknął link z fragmentem tekstu z atrybutem :~:text=burn%20out, który uznał za poufny i niewidoczny dla nikogo. Ten przykład zaczyna się od wplatanego zjawiska, a jego wykorzystanie wymaga spełnienia bardzo określonych warunków wstępnych, dlatego zespół ds. bezpieczeństwa Chrome ocenił ryzyko związane z wdrożeniem funkcji przewijania podczas nawigacji w celu ułatwienia zarządzania. Inne klienty użytkownika mogą zamiast tego wyświetlać element interfejsu z ręcznym przewijaniem.

W przypadku witryn, które chcą zrezygnować z tej funkcji, Chromium obsługuje wartość nagłówka Zasady dokumentu, którą może wysłać, aby klienty użytkownika nie przetwarzały adresów URL fragmentów tekstu.

Document-Policy: force-load-at-top

Wyłączanie fragmentów tekstu

Najprostszym sposobem na wyłączenie tej funkcji jest użycie rozszerzenia, które może wstrzykiwać nagłówki odpowiedzi HTTP, na przykład ModHeader (nie usługa Google) w celu wstawienia nagłówka odpowiedzi (nie żądania) w ten sposób:

Document-Policy: force-load-at-top

Innym, bardziej skomplikowanym sposobem rezygnacji, jest użycie ustawienia „korporacyjne” ScrollToTextFragmentEnabled. Aby to zrobić w systemie macOS, wklej w terminalu polecenie poniżej.

defaults write com.google.Chrome ScrollToTextFragmentEnabled -bool false

W systemie Windows postępuj zgodnie z dokumentacją Centrum pomocy Google Chrome Enterprise.

W przypadku niektórych wyszukiwań wyszukiwarka Google podaje szybką odpowiedź lub podsumowanie z fragmentem treści z odpowiedniej witryny. Te fragmenty z odpowiedzią najczęściej pojawiają się, gdy wyszukiwane hasło ma postać pytania. Kliknięcie fragmentu z odpowiedzią powoduje przejście użytkownika bezpośrednio do tekstu tego fragmentu z odpowiedzią na źródłowej stronie internetowej. Działa to dzięki automatycznie tworzonym adresom URL fragmentów tekstu.

Strona wyników wyszukiwania Google z fragmentem z odpowiedzią. Na pasku stanu wyświetla się URL fragmentów tekstu.
Po kliknięciu wyświetli się odpowiednia sekcja strony.

Podsumowanie

URL z fragmentami tekstu to zaawansowana funkcja umożliwiająca tworzenie linków do dowolnego tekstu na stronach internetowych. Społeczność naukowa może z niej korzystać, aby podawać bardzo dokładne cytowania lub linki. Wyszukiwarki mogą go używać, aby tworzyć precyzyjne linki do wyników tekstowych na stronach. Witryny sieci społecznościowych mogą za jego pomocą umożliwić użytkownikom udostępnianie określonych fragmentów strony internetowej zamiast niedostępnych zrzutów ekranu. Mam nadzieję, że zaczniesz korzystać z adresów URL fragmentów tekstu i ciesz się nimi tak jak ja. Pamiętaj, aby zainstalować rozszerzenie przeglądarki Link to Text Fragment.

Podziękowania

Fragmenty tekstu zostały wdrożone i określone przez Nicka Burrisa i Davida Bokana przy udziale Granta Wanga. Dziękujemy Joe Medley za dokładne zapoznanie się z tym artykułem. Baner powitalny od Grega Rakozy'ego w serwisie Unsplash.