为什么"#.id"在CSS/jQuery中是一个糟糕的选择器但它在HTML锚点中有效?

gma*_*man 26 html jquery css-selectors jquery-selectors fragment-identifier

我正在使用JSDoc.它生成具有句点的ID,如

<a id=".someMethodName"></a>
Run Code Online (Sandbox Code Playgroud)

如果页面的另一部分有

<a href="#.someMethodName"></a> 
Run Code Online (Sandbox Code Playgroud)

这非常有效.单击第二个锚点滚动到第一个.

但是,document.querySelectorjQuery都不会找到锚点.

为什么浏览器本身接受此锚点但jQuery和querySelector不接受?

test("document.querySelector('#.someMethodName')", function() {
  document.querySelector('#.someMethodName');
});
test("$('#.someMethodName')", function() {
  $('#.someMethodName');
});

function test(msg, fn) {
  try {
    var result = fn();
    log(msg, result);
  } catch(e) {
    log(msg, e);
  }
}

function log() {
  var pre = document.createElement("pre");
  pre.appendChild(document.createTextNode(Array.prototype.join.call(arguments, " ")));
  document.body.appendChild(pre);
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#.someMethodName">click here to go to anchor and see errors</a>
<pre>
put
some
text
here
so
the
page
is
long
enough
that
when
we
click
the
anchor
the
browser
has
as
a
place
to
scroll
that
is
off
screen
otherwise
we'd
have
no
way
to
see
if
it
worked
or
not
</pre>
<a id=".someMethodName">we should scroll to here</a>
<p>did we make it?</p>
<hr/>
Run Code Online (Sandbox Code Playgroud)

Bol*_*ock 22

HTML5允许在ID属性值中有一个句点,并且浏览器已经处理了这个问题几十年没有任何问题(这就是为什么HTML4中的限制 - 本身不是由HTML定义,而是由它所基于的SGML定义 - 在HTML5中放宽了,现在免于SGML的传统包袱).所以问题不在于属性值.

RFC 3986定义的片段标识符的语法是:

fragment    = *( pchar / "/" / "?" )
Run Code Online (Sandbox Code Playgroud)

字符集pchar包括句点的地方.所以.someMethodName是一个有效的片段标识符,这就是为什么<a href="#.someMethodName">有效.

#.someMethodName它不是一个有效的选择器,原因有两个:

  1. ID选择器由#后跟一个ident组成,CSS中的ident不能包含句点.
  2. 因此,句点保留给类选择器(类似地由句点后跟一个标识组成).

简而言之,解析器在#找到CSS ident之后却没有找到.它,因为它直接跟在它之后,使得选择器无效.这是令人惊讶的,因为ID选择器的表示法实际上是基于片段标识符的URI表示法 - 这一点很明显,它们都以#符号开头,以及它们都用于引用由该标识符在文档中唯一标识的元素.期望在URI片段中起作用的任何东西也可以在ID选择器中工作并不是没有道理的 - 在大多数情况下它真的.但是因为CSS有自己的语法,它不一定与URI语法相关(因为它们是两个完全不相关的标准1),所以你会得到像这样的边缘情况.

由于句点是片段标识符的一部分,因此您需要使用反斜杠对其进行转义,以便在ID选择器中使用它:

#\.someMethodName
Run Code Online (Sandbox Code Playgroud)

不要忘记你需要在JavaScript字符串中转义反斜杠本身(例如document.querySelector()与jQuery 一起使用):

document.querySelector('#\\.someMethodName')
$('#\\.someMethodName')
Run Code Online (Sandbox Code Playgroud)

1 几年前,一个W3C社区小组成立(我是其中的一员)围绕着一个名为" 使用CSS选择器作为片段标识符"的提议,正如您可以想象的那样,以一种有趣的方式结合这两种技术.然而,这从未起飞,并且唯一已知的实现是一些可能甚至不被维护的浏览器扩展.


NaN*_*NaN 15

对于HTML5是一个有效的id属性:

ID可以采取什么形式没有其他限制 ; 特别是,ID可以只包含数字,以数字开头,以下划线开头,仅包括标点符号等

由于它不是一个有效的CSS标识,以便与使用它querySelector()或者$()您应该逃避这样的:

#\\.someMethodName
Run Code Online (Sandbox Code Playgroud)

Mozilla开发者网络:

要匹配不遵循CSS语法的ID或选择器(例如,通过不恰当地使用冒号或空格),必须使用反斜杠转义字符.由于反斜杠是JavaScript中的转义字符,如果要输入文字字符串,则必须将其转义两次(一次用于JavaScript字符串,另一次用于querySelector):

请注意,它不是有效的HTML4 id属性

  • @tac:这是JSDoc的作者或HTML工作组的错误怎么样?HTML 4 id属性甚至没有考虑到CSS或jQuery的设计 - 限制来自SGML中的NAME令牌,该令牌设计为*年*之前甚至存在这两件事之一.显而易见的是,这些ID旨在被命名为锚点,而且正如我在答案中所提到的(唯一一个这样做),`.someMethodName`是一个完全合法的URI片段标识符.要求更改ID只是为了让你*更容易编写选择器是asinine. (5认同)
  • @CodesInChaos*"请注意它不是有效的HTML4 id属性"*.OP的问题清楚地表明这是不直观的,破坏了使JQ或CSS成为痛苦的行为. (2认同)