URI片段

URI片段在计算机超文本中是指从属于主资源的子资源的标识字符串。主资源由统一资源标识符（URI）标识，片段标识符指向从属资源。

由井号`#`引入的片段标识符是文档的URL的可选最后部分。通常用于标识该文档的一部分。在RFC 3986中指定了其通用语法。URI中的井号`#`分隔符不是片段标识符的一部分。

## 概述

在URI中，井号`#`在URL末尾附近引入可选片段。RFC 3986定义的URI通用语法还允许使用问号`?`引入可选的查询部分。在带有查询和片段的URI中，片段位于查询之后。查询部分取决于URI方案并由服务器评估，例如，`http:`支持与`ftp:`不同的查询。片段取决于文档MIME类型并由客户端（Web 浏览器）评估。客户端在获取文档时不应将URI片段发送到服务器，并且如果没有本地应用程序的帮助，片段不会参与HTTP重定向。

以井号`#`结尾的URI是通用语法允许的，并且这是一种空片段。在MIME文档类型（例如`text/html`或任何XML类型）中，不允许使用空标识符来匹配此语法上合法的构造。Web浏览器通常会在文档顶部显示一个空片段。

片段标识符的功能与URI的其余部分不同：它的处理完全是客户端进行的，没有Web服务器的参与，尽管服务器通常帮助确定MIME类型，并且MIME类型决定片段的处理。当代理（例如Web浏览器）从Web服务器请求Web资源时，代理将URI发送到服务器，但不发送片段。相反，代理等待服务器发送资源，然后代理根据文档类型和片段值处理资源。

在HTML网页中，代理将查找由HTML标记标识的锚点，该标记包含等于片段标识符的`id=`或`name=`属性。

## 例子

- 在MIME为`text/html`页面的URI（例如`http://www.example.org/foo.html#bar`）中，片段引用`id="bar"`的元素。
- 图形Web浏览器通常滚动到位置页面，以便由片段id标识的元素的顶部与视口（viewport）的顶部对齐；因此片段标识符经常用在目录和永久链接中。
- 可以通过CSS伪类`:target`更改被标识的元素的外观；维基百科使用它来高亮显示所选的参考文献。值得注意的是，CSS的`display:&nbsp;block`仅当内容是目标时才可用于显示内容，否则通过`display:&nbsp;none`隐藏。
- 已弃用的`name`属性（仅允许某些元素）在现已过时的浏览器中具有类似的用途。如果存在`name`，则必须和`id`相同。
- 在所有XML文档类型中，包括对应于`xml:id`或类似`id`属性的XHTML片段，都遵循`Name`语法并以字母、下划线或冒号开头。值得注意的是，它们不能以数字或连字符开头。
- `xml:id`是少数通用XML属性之一，例如`xml:lang`，无需显式声明命名空间即可使用。在XHTML中必须使用`id`，因为 XHTML 是在`xml:id`存在之前指定的。
- 在XML应用中，某种语法中的片段标识符可以是XPointer；例如，URI `http://www.example.org/foo.xml#xpointer(//Rube)` 中的片段标识符指的是由URI http://www.example.org/foo.xml标识的文档中名为“Rube”的所有XML元素。给定该URI，XPointer处理器将获取文档的表示（例如通过从Internet请求）并返回文档的“Rube”元素的表示。
- 在RDF词汇表中，例如RDFS、OWL或SKOS，片段标识符用于标识同一XML命名空间中的资源，但不一定对应于文档的特定部分。例如，`http://www.w3.org/2004/02/skos/core#broader`标识了SKOS Core词汇中的“broader”概念，但它并不指代`http://www.w3.org/2004/02/skos/core`标识的资源的特定部分。它是一个完整的 RDF 文件，其中声明了该特定概念的语义以及同一词汇表中的其他概念。
- 在 MIME `text/plain`文档的URI中，RFC 5147 使用关键字“`char`”和“`line`”指定文档内字符和行位置和范围的片段标识符。浏览器支持似乎缺乏。以下示例标识文本文档的第 11 行到第 20 行：
- `http://example.com/document.txt#line=10,20`
- 在 MIME `text/csv` 文档的 URI 中，RFC 7111 使用关键字"`row`" , "`col`", "`cell`"指定片段标识符作为行、列和单元格的选择器，例如：
- `http://example.com/data.csv#row=4` –选择第4行.
- `http://example.com/data.csv#col=2` – 选择第二列.
- `http://example.com/data.csv#row=5-7` – 选择从第5行开始的三个连续行.
- `http://example.com/data.csv#row=5-*` – 选择从第5行开始的所有行.
- `http://example.com/data.csv#cell=4,1-6,2` – 选择从第4行第1列开始到第6行第2列结束的区域.
- 在MIME audio/*、image/*、video/* 文档的 URI 中，很少有定义片段或片段语义。媒体片段 URI 1.0（基本）语法支持使用关键字`t`和`xywh`沿二维（时间和空间）寻址媒体资源。因此，可以在音频或视频 HTML5 元素的`src`属性中使用以下媒体片段 URI：
- `http://example.com/foo.mp4#t=10,20`
- `http://example.com/bar.webm#t=40,80&xywh=160,120,320,240`
- 其他网站使用片段部分将一些额外信息传递给在其上运行的脚本 - 例如，Google Video理解`#01h25m30s`格式的永久链接以在指定位置开始播放，而YouTube使用类似的代码，例如`#t=3m25s`.
- 在JavaScript中，当前HTML或XHTML页面的片段标识符可以在“hash”属性`location.hash`中访问 - 请注意，JavaScript 也可以与其他文档类型一起使用。随着AJAX的兴起，一些网站使用片段标识符来模拟浏览器的后退按钮行为，以进行不需要重新加载的页面更改，或模拟子页面。
- 例如，Gmail几乎每个界面都使用单个URL – 邮箱、个人邮件、搜索结果、设置 – 该片段用于使这些界面可以直接链接。
- Adobe Flash网站可以使用片段部分来通知用户网站或Web应用程序的状态，并促进深度链接，通常在SWFAddress JavaScript库的帮助下。
- 链接到JSON文档的URI可以指定指向特定值的指针。
- 例如，以`#/foo`结尾的URL可用于从以`{ "foo": ["bar", "baz"], ... }`开头的文档中的“键-值对”中提取值。
- 在 MIME `application/pdf` 文档的 URI 中，PDF查看器可识别许多片段标识符。例如，以 `.pdf#page=35`结尾的 URL 将导致大多数读者打开 PDF 并滚动到第35页。其他几个参数也是可能的，包括`#nameddest=`（类似于HTML锚点）、`#search="word1 word2"`, `#zoom=`等。多个参数可以用 & 符号组合：
- `http://example.org/doc.pdf#view=fitb&nameddest=Chapter3`.
- 在SVG中，片段可以指定`viewBox()`, `preserveAspectRatio()`, `transform()`等参数。

## W3C提案

对于与纯文本文档（无法存储锚元数据）一起使用的片段标识符，或者引用 HTML 文档中作者未使用锚标记的位置，已经提出了一些W3C提案：

- 2012年9月，Media Fragments URI 1.0 (basic)已成为W3C推荐标准。
- Chrome版本80及更高版本实现了 WICG Text Fragments,因此`#:~:text=foo`将导致浏览器搜索`foo`，突出显示匹配的文本，然后滚动到它。除了开始和结束之外，代码片段还可以指定上下文：必须在`foo`之前或之后但不会突出显示的文本（例如搜索前面带有“night”的“vision”）。
- Python的Package Index将文件的MD5哈希值附加到URL作为片段标识符。如果MD5未被破坏，这可以用来确保包的完整性。
- `https://pypi.python.org ... zodbbrowser-0.3.1.tar.gz#md5=38dc89f294b24691d3f0d893ed3c119c`
- hash-bang片段是以感叹号`!`开头的片段。它用于索引动态单页应用程序的现已被弃用的方法中。感叹号在HTML4、XHTML和XML标识符中是非法的，因此与该功能有一定程度的分离。然而，它在HTML5中是允许的。
- 2009年至2015年间，Google网站管理员提出并推荐了一种“AJAX 抓取方案”，在有状态AJAX页面的片段标识符中使用初始感叹号： `http://example.com/page?query#!state`
- 另一个实现是替换`#!`为`?_escaped_fragment_=`
- Hash-bang URI 被W3C的Jeni Tennison等许多人认为是有问题的，因为它们使那些没有在浏览器中激活JavaScript的人无法访问页面。它们还会破坏HTTP Referer标头，因为浏览器不允许发送Referer标头中的片段标识符。
- 2015 年，Google 弃用了他们的hash-bang AJAX抓取提案，转而建议使用渐进增强和HTML5的`history.pushState()`方法。
- Mozilla基金会Gervase Markham提出了一种用于搜索的片段标识符，其形式为`#!s!search terms`。在s(`#!s10!`) 后添加数字表示浏览器应搜索第n次出现的搜索词。负数(`#!s-3!`)从文档末尾开始向后搜索。Greasemonkey脚本可用于将此功能添加到兼容浏览器。
- `http://example.com/index.html#!s3!search terms`
- 苏黎世联邦理工学院的Erik Wilde和Marcel Baschnagel将其扩展为使用正则表达式（使用关键字“`match`”）来识别纯文本文档中的片段。他们还描述了一个原型实现作为Firefox浏览器的扩展。例如，以下命令将在文档中的任何位置查找不区分大小写的文本“RFC”：
- `http://example.com/document.txt#match=[rR][fF][cC]`
- 前瞻学会的K. Yee提出了用冒号和关键字分隔的“扩展片段标识符”，以将它们与锚标识符区分开来。具有“片段规范方案”id“`words`”的文本搜索片段标识符是该方案中的第一个提案。以下示例将在文档中搜索字符串“some context for a search term”的第一次出现，然后突出显示单词“search term”：
- `http://example.com/index.html#:words:some-context-for-a-(search-term)`
- 上述方案在Chrome 80版本中实现。
- LiveURLs项目提出了一种片段标识符格式，用于引用页面内的文本区域，其形式为`#FWS+C`，其中 F 是第一个单词的长度（最多5个字符），W是第一个单词本身，S是所选文本的长度，C是所选文本的32位CRC。他们使用`#LFWS+C`的形式实现了该方案的变体作为 Firefox 浏览器的扩展，其中L是片段本身的长度，采用两个十六进制数字。使用已实现的变体链接到单词“Fragment”将产生：
- `http://example.com/index.html#115Fragm8+-52f89c4c`
- 在 Firefox 5 之前，Firefox 支持 XPath 链接，例如 #xpath:/html/body/div3，它可以与书签结合使用，例如 http://antimatter15.com/wp/2009/11/xpath- bookmark-bookmarklet/ 用于链接缺少正确 ID 的 HTML 文档。此功能已作为 https://bugzilla.mozilla.org/show_bug.cgi?id=457102 中代码清理的一部分被删除
- 在EPUB电子书格式中，EPUB Canonical Fragment Identifier （epubcfi，2011-2017）定义了一种W3C/International Digital Publishing Forum标准化方法，用于使用片段标识符引用任意内容，通过文档结构和模式匹配来定位非锚定文本范围。这些动态深层链接有助于在文本更新和使用后定位内容，例如在Apple Books中。

## 外部链接

- W3C Media Fragments Working Group, establishing a URI syntax and semantics to address media fragments in audiovisual material (such as a region in an image or a sub-clip of a video)
- MediaMixer Community Portal collects presentations, tutorials, use cases and demonstrators related to use of Media Fragment technology