Os fragmentos de texto permitem 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 uma grande versão. Ele continha uma série de recursos muito esperados, como módulos ECMAScript em Web Workers, coalescência nula, 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. Confira um trecho da postagem do blog na captura de tela abaixo.
Você provavelmente está se perguntando o que significam as caixas vermelhas. Elas são o resultado da execução do
fragmento abaixo no DevTools. Ele destaca todos os elementos que têm um atributo id
.
document.querySelectorAll('[id]').forEach((el) => {
el.style.border = 'solid 2px red';
});
É possível colocar um link direto para qualquer elemento destacado com uma caixa vermelha usando o
identificador de fragmento,
que é usado no hash do
URL da página. Supondo que eu quisesse criar um link direto para a caixa Envie seu feedback no
Fóruns de produtos no
lado, eu poderia fazer isso criando manualmente o URL
https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1
.
Como você pode ver 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: ""
}
*/
O fato de eu ter que abrir as ferramentas do desenvolvedor para encontrar o id
de um elemento fala muito
sobre a probabilidade de essa seção específica da página ser vinculada pelo autor da
postagem do blog.
E se eu quiser vincular a um site sem id
? Digamos que eu queira vincular o título ECMAScript Modules
in Web Workers. Como mostrado na captura de tela abaixo, o <h1>
em questão não
tem um atributo id
, o que significa que não há como vincular esse cabeçalho. Esse é o problema que
os fragmentos de texto resolvem.
Fragmentos de texto
A proposta de fragmentos de texto adiciona suporte para especificar um trecho de texto no hash do URL. Ao navegar para um URL com esse fragmento, o user agent pode enfatizá-lo e/ou mostrá-lo à atenção do usuário.
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 sua
marcação de âncora <a>
ou adicione
noopener
à
lista Window.open()
de recursos de funcionalidade da janela.
start
Na forma mais simples, a sintaxe dos fragmentos de texto é a seguinte: o símbolo de cerquilha #
seguido por
:~:text=
e, por fim, start
, que representa o
texto codificado em percentual
que quero vincular.
#:~:text=start
Por exemplo, digamos que eu queira vincular o título ECMAScript Modules in Web Workers na postagem do blog que anuncia os recursos do Chrome 80. O URL nesse caso seria:
O fragmento de texto é enfatizado desta maneira. Se você clicar no link em um navegador compatível, como o Chrome, o fragmento de texto será destacado e rolado para aparecer:
start
e end
E se eu quiser vincular a seção inteira intitulada Módulos ECMAScript nos Web Workers, não apenas o cabeçalho? A codificação de percentual de todo o texto da seção tornaria o URL resultante longo demais para ser prático.
Felizmente, há uma maneira melhor. Em vez de todo o texto, posso enquadrar o texto desejado usando a
sintaxe start,end
. Portanto, especifiquei algumas palavras codificadas por porcentagem no início
do texto desejado e outras no final, separadas
por uma vírgula ,
.
Ela tem esta aparência:
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, toda a seção é destacada e rolada para aparecer:
Você pode estar se perguntando 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 teria funcionado. Compare start
e end
com os
valores anteriores.
Se eu der um passo adiante e usar apenas uma palavra para start
e end
, você vai
perceber 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, mas o fragmento de texto destacado não é mais o desejado originalmente. O
destaque para na primeira ocorrência da palavra Workers.
, que é o correto, mas não é o que eu
pretendi destacar. O problema é que a seção desejada não é identificada exclusivamente pelos
valores atuais de start
e end
de uma palavra:
prefix-
e -suffix
Usar valores longos o suficiente para start
e end
é uma solução para conseguir um link exclusivo.
No entanto, isso não é possível em algumas situações. Por que escolhi a
postagem do blog de lançamento do Chrome 80 como exemplo? A resposta é que, nesta versão, os fragmentos de texto
foram introduzidos:
Observe que, na captura de tela acima, a palavra "text" aparece quatro vezes. A quarta ocorrência é
gravada em uma fonte de código verde. Se eu quisesse vincular a essa palavra específica, definiria start
como text
. Como a palavra "text" é apenas uma palavra, não pode haver um 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" que já está no título:
Felizmente, há uma solução. Em casos como esse, posso especificar um prefix-
e um -suffix
. A
palavra antes da fonte de código verde "texto" é "o" e a palavra depois é "parâmetro". Nenhuma das
outras três ocorrências da palavra "text" tem as mesmas palavras ao redor. Com esse
conhecimento, posso ajustar o URL anterior e adicionar prefix-
e -suffix
. Assim como os outros parâmetros, eles também precisam ser codificados em percentual 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 em percentual. Isso é especialmente importante para os caracteres traço
-
, ampersand &
e vírgula ,
, para que não sejam interpretados como parte da sintaxe
do diretivo de texto.
#:~:text=[prefix-,]start[,end][,-suffix]
Cada prefix-
, start
, end
e -suffix
corresponderá apenas ao texto de um único
elemento no nível do bloco,
mas os intervalos start,end
completos podem abranger vários blocos. Por exemplo,
:~:text=The quick,lazy dog
não vai corresponder ao exemplo abaixo, porque a string inicial
"The quick" não aparece em um único elemento de nível de bloco ininterrupto:
<div>
The
<div></div>
quick brown fox
</div>
<div>jumped over the lazy dog</div>
No entanto, ele corresponde a este 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 é tedioso, especialmente quando se trata de garantir que eles sejam exclusivos. Se você realmente quiser, a especificação traz 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 fragmento de texto que permite criar um link para qualquer texto selecionando-o e clicando em "Copiar link para o texto selecionado" no menu de contexto. Essa extensão está disponível para os seguintes navegadores:
- Link para fragmento de texto do Google Chrome
- Link para fragmento de texto do Microsoft Edge
- Link para fragmento de texto no 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 precisam ser
separados por um caractere & &
. 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
.
Misturando fragmentos de elementos e texto
Os fragmentos de elementos tradicionais podem ser combinados com fragmentos de texto. É perfeitamente aceitável ter os dois
no mesmo URL, por exemplo, para fornecer um substituto útil caso o texto original na página
mude, 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 vincula à seção Envie feedback nos
fóruns de produtos
contém um fragmento de elemento (HTML1
) e um fragmento de texto
(text=Give%20us%20feedback%20in%20our%20Product%20Forums.
):
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 delimitado 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 possam interagir diretamente com ele. As instruções do user agent também
são chamadas de diretivas. No caso concreto, text=
é chamado de diretiva de texto.
Detecção de recursos
Para detectar a compatibilidade, teste a propriedade fragmentDirective
somente leitura no document
. A diretiva de fragmento
é um mecanismo para URLs especificarem instruções direcionadas ao navegador, e não ao
documento. O objetivo é evitar a interação direta com o script do autor para que as instruções do agente do usuário
futuras possam ser adicionadas sem medo de introduzir mudanças importantes no conteúdo atual. Um
exemplo possível de tais adições futuras são as dicas de tradução.
if ('fragmentDirective' in document) {
// Text Fragments is supported.
}
A detecção de recursos é principalmente destinada a casos em que os 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 oferecem suporte a eles.
Como definir o estilo de fragmentos de texto
Por padrão, os navegadores estilizam fragmentos de texto da mesma forma que estilizam
mark
(normalmente preto em amarelo,
as cores do sistema do CSS
para mark
). A folha de estilo do user-agent contém CSS parecido com este:
:root::target-text {
color: MarkText;
background: Mark;
}
Como você pode ver, o navegador expõe um pseudoseletor
::target-text
que pode ser usado para
personalizar o realce aplicado. Por exemplo, você pode projetar seus fragmentos de texto para serem pretos
em um fundo vermelho. Como sempre,
verifique o contraste de cores
para que o estilo de substituição não cause problemas de acessibilidade e para garantir que o destaque realmente
se destaque visualmente do restante do conteúdo.
:root::target-text {
color: black;
background-color: red;
}
Capacidade de polivalidade
Até certo ponto, o recurso de fragmentos de texto pode receber polyfill. Fornecemos um polyfill, que é 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 fragmentos de texto programático
O polyfill contém um arquivo
fragment-generation-utils.js
que pode ser importado e usado para gerar links de fragmentos 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);
}
Como conseguir fragmentos de texto para fins de análise
Muitos sites usam o fragmento para roteamento, e é por isso que os navegadores removem os fragmentos de texto para não quebrar essas páginas. Há uma necessidade reconhecida 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 (diferentes da página atual) que são o resultado de
uma
ativação do usuário.
Além disso, as navegações originadas de uma origem diferente do destino exigem que a
navegação ocorra em um contexto
noopener
, de modo que
a página de destino seja isolada o suficiente. As diretivas de fragmento 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
do iframe não vai 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
foi encontrado em uma página ou não. Embora os fragmentos de elementos estejam totalmente sob o controle do
autor da página original, os fragmentos de texto podem ser criados por qualquer pessoa. Lembra como no meu exemplo acima
não havia como vincular ao título ECMAScript Modules in Web Workers, já que o <h1>
não
tinha um id
, mas como alguém, incluindo eu, poderia vincular a qualquer lugar criando cuidadosamente
o fragmento de texto?
Imagine que eu gerenciasse uma rede de publicidade mal-intencionada evil-ads.example.com
. Além disso, imagine que em um dos meus iframes
de anúncios, criei dinamicamente um iframe oculto de origem cruzada para dating.example.com
com um URL
de fragmento de texto
dating.example.com#:~:text=Log%20Out
quando o usuário interage com o anúncio. Se o texto "Log Out" for encontrado, sei que a vítima está
conectada a dating.example.com
, que posso usar para criar o perfil do usuário. Como uma implementação de fragmentos
de texto simples pode decidir que uma correspondência bem-sucedida deve causar uma mudança de foco, em
evil-ads.example.com
, eu poderia detectar o evento blur
e saber quando uma correspondência ocorreu. No
Chrome, implementamos os fragmentos de texto de modo que o cenário acima não possa acontecer.
Outro ataque pode ser a exploração do 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 vítima, como o administrador da intranet de uma empresa. Agora imagine que
exista um longo documento de recursos humanos O que fazer se você sofre de… e uma lista de
condições, como esgotamento, ansiedade etc. Poderia colocar um pixel de rastreamento ao lado de cada item na
lista. Se eu determinar que o carregamento do documento ocorre ao mesmo tempo que o carregamento do
pixel de rastreamento ao lado de, digamos, o item burn out, posso, como administrador da intranet, determinar que
um funcionário clicou em um link de fragmento de texto com :~:text=burn%20out
que o funcionário
provavelmente presumiu ser confidencial e não visível para ninguém. Como esse exemplo é um pouco
artificial para começar e, como a exploração dele exige condições muito específicas,
a equipe de segurança do Chrome avaliou que o risco de implementar o rolagem na navegação é gerenciável.
Outros user agents podem decidir mostrar um elemento de interface de rolagem manual.
Para sites que não querem participar, 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 fragmento de texto.
Document-Policy: force-load-at-top
Como desativar fragmentos de texto
A maneira mais fácil de desativar o recurso é usar 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 é usar 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 Central de Ajuda do Google Chrome Enterprise.
Fragmentos de texto na pesquisa na Web
Em algumas pesquisas, o mecanismo de pesquisa do Google fornece uma resposta rápida ou um resumo com um trecho de conteúdo de um site relevante. Esses trechos em destaque têm mais chances de aparecer quando uma pesquisa é feita na forma de uma pergunta. Clicar em um trecho em destaque direciona o usuário diretamente ao texto do trecho em destaque 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 poderoso para vincular a textos arbitrários em páginas da Web. A comunidade acadêmica pode usá-los para fornecer citações ou links de referência altamente precisos. Os mecanismos de pesquisa podem usá-lo para criar links diretos para resultados de texto nas páginas. Os sites de rede social podem usar essa opção 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 fragmentos de texto e os considere tão úteis quanto eu. Instale a extensão Link to Text Fragment para o navegador.
Links relacionados
- Especificação do rascunho
- Revisão do TAG
- Entrada "Status da plataforma do Chrome"
- Bug de rastreamento do Chrome
- Conversa com a intenção de enviar
- Discussão do WebKit-Dev
- Tema de posição dos padrões da Mozilla
Agradecimentos
Os fragmentos de texto foram implementados e especificados por Nick Burris e David Bokan, com contribuições de Grant Wang. Agradecemos a Joe Medley pela revisão completa deste artigo. Imagem principal de Greg Rakozy no Unsplash.