Com os fragmentos de texto, é possível especificar um snippet de texto no fragmento de URL. Ao navegar para um URL com esse fragmento de texto, o navegador pode enfatizar e/ou chamar a atenção do usuário.
Identificadores de fragmento
O Chrome 80 foi um grande lançamento. Ele continha vários recursos muito esperados, como Módulos ECMAScript em Web Workers, coalescência anulada, encadeamento opcional e muito mais. O lançamento foi, como de costume, anunciado em uma postagem do blog (link em inglês) no blog do Chromium. Veja um trecho da postagem do blog na captura de tela abaixo.
Você provavelmente está se perguntando o que significam todas as caixas vermelhas. Eles são o resultado da execução do
snippet a seguir no DevTools. Ele destaca todos os elementos que têm um atributo id
.
document.querySelectorAll('[id]').forEach((el) => {
el.style.border = 'solid 2px red';
});
Posso colocar um link direto para qualquer elemento destacado com uma caixa vermelha graças ao
identificador de fragmento
que uso no hash do
URL da página. Supondo que eu queira um link direto para a caixa Envie feedback em nossos
Fóruns de produtos, eu poderia fazer isso criando o URL
https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1
.
Como é possível observar no painel "Elementos" das Ferramentas para desenvolvedores, o elemento em questão tem um atributo id
com o valor HTML1
.
Se eu analisar esse URL com o construtor URL()
do JavaScript, os diferentes componentes serão revelados.
Observe a propriedade hash
com o valor #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: ""
}
*/
No entanto, o fato de ter que abrir as Ferramentas para desenvolvedores para encontrar o id
de um elemento diz muito sobre a probabilidade de essa seção específica da página ter sido criada pelo autor da postagem do blog.
E se eu quiser vincular a algo sem um id
? Digamos que eu queira vincular o título Módulos ECMAScript
in Web Workers. Como a captura de tela abaixo mostra, o <h1>
em questão não tem um atributo id
, o que significa que não é possível criar um link para esse cabeçalho. Esse é o problema que os
fragmentos de texto resolvem.
Fragmentos de texto
A proposta Text Fragments adiciona suporte à especificação de um snippet de texto no hash do URL. Ao navegar para um URL com esse fragmento de texto, o user agent pode enfatizá-lo e/ou chamar a atenção dele.
Compatibilidade com navegadores
Por motivos de segurança, o recurso exige que os links sejam abertos em um
contexto de noopener
.
Portanto, inclua
rel="noopener"
na
marcação de âncora <a>
ou adicione
noopener
à sua
lista Window.open()
de recursos de funcionalidade de janela.
start
Na forma mais simples, a sintaxe dos fragmentos de texto é esta: o símbolo de hash #
seguido por
:~:text=
e, finalmente, start
, que representa o texto
codificado por porcentagem
para o qual quero vincular.
#:~:text=start
Por exemplo, digamos que eu queira um link para o título Módulos ECMAScript in Web Workers na postagem do blog que anuncia recursos no Chrome 80, o URL neste caso seria:
O fragmento de texto é enfatizado assim. Se você clicar no link em um navegador compatível, como o Chrome, o fragmento de texto será destacado e será exibido na tela:
start
e end
E se eu quiser vincular a toda a seção intitulada Módulos ECMAScript in Web Workers, não apenas o cabeçalho? A codificação por porcentagem de todo o texto da seção tornaria o URL resultante muito longo.
Felizmente, existe uma maneira melhor. Em vez do texto inteiro, posso enquadrar o texto desejado usando a
sintaxe start,end
. Portanto, é preciso especificar algumas palavras codificadas por porcentagem no início do texto desejado e algumas palavras codificadas por porcentagem no final dele, separadas por vírgula ,
.
O resultado é este:
Para start
, tenho ECMAScript%20Modules%20in%20Web%20Workers
, depois uma vírgula ,
seguida
por ES%20Modules%20in%20Web%20Workers.
como end
. Quando você clica em um navegador compatível como o Chrome, a seção inteira é destacada e rolada para visualização:
Agora você pode se perguntar sobre minha escolha de start
e end
. Na verdade, o URL um pouco mais curto
https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript%20Modules,Web%20Workers.
com apenas duas palavras de cada lado também funcionaria. Compare start
e end
com os
valores anteriores.
Se eu der um passo adiante e usar apenas uma palavra para start
e end
, você verá que estou com problemas. O URL
https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript,Workers.
está ainda mais curto agora, mas o fragmento de texto destacado não é mais o pretendido originalmente. O destaque é interrompido na primeira ocorrência da palavra Workers.
, que está correta, mas não é o que eu pretendia destacar. O problema é que a seção desejada não é identificada exclusivamente pelos
valores atuais de uma palavra start
e end
:
prefix-
e -suffix
Usar valores longos o suficiente para start
e end
é uma solução para gerar um link exclusivo.
No entanto, em algumas situações, isso não é possível. Por que escolhi a postagem do blog
sobre a versão do Chrome 80 como exemplo? A resposta é que, nesta versão, foram introduzidos fragmentos de texto:
Observe como na captura de tela acima a palavra “texto” aparece quatro vezes. A quarta ocorrência é escrita
em uma fonte de código verde. Para criar um link para essa palavra específica, defina start
como text
. Como a palavra "texto" é apenas uma palavra, não pode haver end
. E agora? O URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=text
corresponde à primeira ocorrência da palavra "Text" no título:
Felizmente existe uma solução. Em casos como esse, posso especificar um prefix-
e um -suffix
. A
palavra antes da fonte do código verde "texto" é "o" e a palavra posterior é "parâmetro". Nenhuma das
outras três ocorrências da palavra "texto" tem as mesmas palavras ao redor. Com esse
conhecimento, posso ajustar o URL anterior e adicionar prefix-
e -suffix
. Como os outros parâmetros, eles também precisam ser codificados por porcentagem e podem conter mais de uma palavra.
https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=the-,text,-parameter
.
Para permitir que o analisador identifique claramente o prefix-
e o -suffix
, eles precisam ser separados
do start
e do end
opcional com um traço -
.
A sintaxe completa
A sintaxe completa dos fragmentos de texto é mostrada abaixo. Os colchetes indicam um parâmetro opcional.
Os valores de todos os parâmetros precisam ser codificados por porcentagem. Isso é especialmente importante para os caracteres de traço
-
, "e" comercial &
e vírgula ,
. Portanto, eles não estão sendo interpretados como parte da sintaxe
da diretiva de texto.
#:~:text=[prefix-,]start[,end][,-suffix]
Cada um dos elementos prefix-
, start
, end
e -suffix
corresponde apenas ao texto de um único
elemento no nível de bloco,
mas os intervalos de start,end
completos podem abranger vários blocos. Por exemplo,
:~:text=The quick,lazy dog
não vai corresponder no exemplo abaixo, porque a string inicial "The fast" não aparece em um único elemento no nível do bloco ininterrupto:
<div>
The
<div></div>
quick brown fox
</div>
<div>jumped over the lazy dog</div>
No entanto, ele corresponde neste exemplo:
<div>The quick brown fox</div>
<div>jumped over the lazy dog</div>
Como criar URLs de fragmento de texto com uma extensão de navegador
Criar URLs de fragmentos de texto manualmente é entediante, especialmente quando se trata de garantir que eles sejam únicos. Se você realmente quiser, a especificação tem algumas dicas e lista as etapas para gerar URLs de fragmento de texto. Fornecemos uma extensão de navegador de código aberto chamada Link para o fragmento de texto, que permite vincular qualquer texto selecionando-o e clicando em "Copiar link para o texto selecionado" no menu de contexto. Esta extensão está disponível para os seguintes navegadores:
- Link para o fragmento de texto do Google Chrome
- Link para o fragmento de texto do Microsoft Edge
- Link para o fragmento de texto do Mozilla Firefox
- Link para o fragmento de texto do Apple Safari
Vários fragmentos de texto em um URL
Vários fragmentos de texto podem aparecer em um URL. Os fragmentos de texto específicos precisam ser
separados por um caractere "e" comercial &
. Confira um exemplo de link com três fragmentos de texto:
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
.
Como misturar elementos e fragmentos de texto
Os fragmentos de elementos tradicionais podem ser combinados com fragmentos de texto. Não há problema em ter ambos no mesmo URL, por exemplo, para fornecer um substituto significativo caso o texto original na página seja alterado, de modo que o fragmento de texto não corresponda mais. O URL
https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1:~:text=Give%20us%20feedback%20in%20our%20Product%20Forums.
que direciona para a seção Envie feedback na seção
Fóruns de produtos
contém um fragmento de elemento (HTML1
) e um fragmento de texto
(text=Give%20us%20feedback%20in%20our%20Product%20Forums.
):
A diretiva de fragmento
Há um elemento da sintaxe que ainda não expliquei: a diretiva de fragmento :~:
. Para evitar
problemas de compatibilidade com fragmentos de elementos de URL já existentes, como mostrado acima, a
especificação de fragmentos de texto introduz a diretiva
de fragmento. A diretiva de fragmento é uma parte do fragmento de URL delimitada pela sequência de código
:~:
. Ele é reservado para instruções do user agent, como text=
, e é removido do URL
durante o carregamento para que os scripts de autor não interajam diretamente com ele. As instruções do user agent também são chamadas de diretivas. No caso concreto, a text=
é chamada de diretiva de texto.
Detecção de recursos
Para detectar a compatibilidade, teste a propriedade fragmentDirective
somente leitura em document
. A diretiva
de fragmento é um mecanismo para que os URLs especifiquem instruções direcionadas ao navegador em vez do
documento. O objetivo é evitar a interação direta com o script do autor, para que futuras instruções do user agent possam ser adicionadas sem medo de introduzir alterações interruptivas no conteúdo atual. Um
exemplo potencial dessas adições futuras podem ser dicas de tradução.
if ('fragmentDirective' in document) {
// Text Fragments is supported.
}
A detecção de recursos é destinada principalmente aos casos em que links são gerados dinamicamente (por exemplo, por mecanismos de pesquisa) para evitar a veiculação de links de fragmentos de texto para navegadores que não têm suporte a eles.
Como definir o estilo de fragmentos de texto
Por padrão, os navegadores estilizam fragmentos de texto da mesma forma que mark
(normalmente preto sobre amarelo, as cores do sistema CSS para mark
). A folha de estilo do user agent contém um CSS semelhante a este:
:root::target-text {
color: MarkText;
background: Mark;
}
Como você pode notar, o navegador expõe um pseudoseletor
::target-text
que pode ser usado para
personalizar o destaque aplicado. Por exemplo, você pode projetar fragmentos de texto para serem texto preto
em um segundo plano vermelho. Como sempre, verifique o contraste de cores
para que o estilo modificado não cause problemas de acessibilidade e confira se o destaque realmente
se destaca visualmente do restante do conteúdo.
:root::target-text {
color: black;
background-color: red;
}
Polifilabilidade
O recurso de fragmentos de texto pode ter polyfill aplicado até certo ponto. Fornecemos um polyfill, usado internamente pela extensão, para navegadores que não oferecem suporte integrado a fragmentos de texto em que a funcionalidade é implementada em JavaScript.
Geração de links de fragmento de texto programático
O polyfill contém um arquivo fragment-generation-utils.js
que você pode importar e usar para gerar links de fragmento de texto. Isso é
descrito no exemplo de código abaixo:
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);
}
Extrair fragmentos de texto para fins de análise
Muitos sites usam o fragmento para roteamento. É por isso que os navegadores removem fragmentos de texto para não corromper essas páginas. Há uma necessidade confirmada de expor links de fragmentos de texto para páginas, por exemplo, para fins de análise, mas a solução proposta ainda não foi implementada. Como solução alternativa por enquanto, use o código abaixo para extrair as informações desejadas.
new URL(performance.getEntries().find(({ type }) => type === 'navigate').name).hash;
Segurança
As diretivas de fragmento de texto são invocadas apenas em navegações completas (que não sejam da mesma página) resultantes de
uma
ativação do usuário.
Além disso, as navegações originadas de uma origem diferente do destino exigirão que
a navegação ocorra em um contexto
noopener
, de modo que
a página de destino tenha um isolamento suficiente. As diretivas de fragmentos de texto são
aplicadas apenas ao frame principal. Isso significa que o texto não será pesquisado dentro de iframes, e a navegação
de iframe não invocará um fragmento de texto.
Privacidade
É importante que as implementações da especificação de fragmentos de texto não vazem se um fragmento
de texto for encontrado em uma página ou não. Embora os fragmentos de elemento estejam totalmente sob o controle do autor da página original, os fragmentos de texto podem ser criados por qualquer pessoa. Lembre-se de que, no exemplo acima, não havia como criar um link para o título ECMAScript Modules in Web Workers, já que o <h1>
não tinha um id
, mas como qualquer pessoa, incluindo eu, poderia simplesmente vincular a qualquer lugar elaborando cuidadosamente o fragmento de texto?
Imagine que eu executei uma rede de publicidade ruim evil-ads.example.com
. Imagine também que, em um dos meus iframes de anúncio, eu criei dinamicamente um iframe de origem cruzada oculto para dating.example.com
com um URL de fragmento de texto dating.example.com#:~:text=Log%20Out
quando o usuário interagir com o anúncio. Se o texto "Log Out" for encontrado, isso significa que a vítima está
conectada a dating.example.com
, o que pode ser usado para criar um perfil de usuário. Como uma implementação simples de
fragmentos de texto pode decidir que uma correspondência bem-sucedida causaria uma mudança de foco, no
evil-ads.example.com
, eu poderia detectar o evento blur
e saber quando uma correspondência ocorreu. No
Chrome, implementamos fragmentos de texto de modo que o cenário acima não acontece.
Outro ataque pode ser explorar o tráfego de rede com base na posição de rolagem. Vamos supor que eu tenha acesso aos registros
de tráfego de rede da minha vítima, por exemplo, como administrador da intranet de uma empresa. Agora imagine que existia um longo documento de recursos humanos O que fazer se você sofreu de... e uma lista de condições como burnout, ansiedade etc. Eu poderia colocar um pixel de rastreamento ao lado de cada item na lista. Se eu determinar que o carregamento do documento temporariamente ocorre com o carregamento do
pixel de rastreamento ao lado do item de esgotamento, por exemplo, posso, como administrador da intranet, determinar que
um funcionário clicou em um link de fragmento de texto com :~:text=burn%20out
que ele
possa ter considerado confidencial e não visível para ninguém. Como esse exemplo é um pouco complexo no começo e como a exploração dele requer condições muito específicas, a equipe de segurança do Chrome avaliou o risco de implementar a rolagem na navegação para ser gerenciável.
Outros user agents podem mostrar um elemento de interface de rolagem manual em vez disso.
Para sites que quiserem desativar, o Chromium oferece suporte a um valor de cabeçalho Document Policy que pode ser enviado para que os user agents não processem URLs de fragmentos de texto.
Document-Policy: force-load-at-top
Como desativar fragmentos de texto
A maneira mais fácil de desativar o recurso é usando uma extensão que pode injetar cabeçalhos de resposta HTTP, por exemplo, ModHeader (não um produto do Google), para inserir um cabeçalho de resposta (não solicitação) da seguinte maneira:
Document-Policy: force-load-at-top
Outra maneira mais complexa de desativar é usando a configuração empresarial
ScrollToTextFragmentEnabled
.
Para fazer isso no macOS, cole o comando abaixo no terminal.
defaults write com.google.Chrome ScrollToTextFragmentEnabled -bool false
No Windows, siga a documentação no site de suporte da Ajuda do Google Chrome Enterprise.
Fragmentos de texto na pesquisa na Web
Para algumas pesquisas, o mecanismo de pesquisa do Google fornece uma resposta rápida ou um resumo com um snippet de conteúdo de um site relevante. Estes trechos em destaque têm mais chances de aparecer quando uma pesquisa é feita na forma de uma pergunta. Ao clicar em um trecho em destaque, o usuário é levado diretamente ao texto dele na página da Web de origem. Isso funciona graças aos URLs de fragmentos de texto criados automaticamente.
Conclusão
O URL de fragmentos de texto é um recurso eficiente para vincular textos arbitrários em páginas da Web. A comunidade acadêmica pode usá-los para fornecer citações ou referências de alta precisão. Os mecanismos de pesquisa podem usá-lo para links diretos para resultados de texto nas páginas. Sites de redes sociais podem usá-lo para permitir que os usuários compartilhem trechos específicos de uma página da Web em vez de capturas de tela inacessíveis. Espero que você comece a usar URLs de fragmento de texto e os ache tão úteis quanto eu. Não se esqueça de instalar a extensão de navegador Link to Text Fragment.
Links relacionados
- Rascunho das especificações
- Análise da TAG
- Entrada de status da plataforma do Chrome
- Bug de rastreamento do Chrome
- Intent de envio da linha de execução
- Linha de execução WebKit-Dev
- Conversa de posição de padrões do Mozilla
Agradecimentos
Os fragmentos de texto foram implementados e especificados por Nick Burris e David Bokan, com contribuições de Grant Wang (links em inglês). Agradecemos a Joe Medley pela revisão completa deste artigo. Imagem principal de Greg Rakozy no Unsplash.