Почему"#.id " плохой селектор в CSS / jQuery, но он работает в HTML-якоре?

я использую JSDoc. Он генерирует идентификаторы с периодом как в

<a id=".someMethodName"></a>

если другая часть страницы имеет

<a href="#.someMethodName"></a> 

это прекрасно работает. Щелчок по второму якорю приведет к первому.

однако, ни document.querySelector и jQuery не найдет якорь.

почему сам браузер принимает этот якорь, а 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);
}
<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/>

5 ответов


HTML5 позволяет иметь период в значении атрибута ID, и браузеры обрабатывали это без каких - либо проблем в течение десятилетий (вот почему ограничение в HTML 4 - само по себе определяется не HTML, а SGML, на котором оно основано-было ослаблено в HTML5, теперь свободном от устаревшего багажа SGML). Так что проблема не в значении атрибута.

грамматика идентификатора фрагмента, определенного RFC 3986 - это:

fragment    = *( pchar / "/" / "?" )

где набор символов pchar включает в себя период. Так что .someMethodName является допустимым идентификатором фрагмента, поэтому <a href="#.someMethodName"> строительство.

но #.someMethodName не является допустимым селектор, и причина двоякая:

  1. селектор ID состоит из # затем идент, и идентификатор в CSS не может содержать точку.
  2. таким образом, период зарезервирован для селектора классов (который аналогично состоит из следующего периода по иденту).

короче говоря, парсер ожидает идентификатор CSS после # но не найти его из-за ., что непосредственно следует за ним, делая селектор недействительным. Это удивительно, потому что обозначение селектора ID фактически основано на обозначении URI для идентификатора фрагмента - как видно из того, что оба они начинаются с # знак, а также тот факт, что они оба используются для ссылки на элемент однозначно выявлены внутри документа по этому идентификатору. Вполне разумно ожидать, что все, что работает в фрагменте URI, также будет работать в селекторе ID - и в большинстве случаев это is правда. Но потому, что CSS имеет свою собственную грамматику, которая не обязательно коррелирует с грамматикой URI (потому что они два совершенно несвязанных стандарта1), вы получаете крайние случаи, такие как этот.

поскольку период является частью идентификатора фрагмента, вам понадобится чтобы избежать его с обратной косой чертой, чтобы использовать его в селекторе ID:

#\.someMethodName

не забывайте, что вам нужно избежать обратной косой черты в строке JavaScript (например, для использования с document.querySelector() и jQuery):

document.querySelector('#\.someMethodName')
$('#\.someMethodName')

1несколько лет назад W3C Community Group был сформирован (членом которого я являюсь) вокруг предложения, известного как использование селекторов CSS в качестве идентификаторов фрагментов это, как вы можете представьте себе, женился на двух технологиях интересным образом. Однако это никогда не снималось, и единственными известными реализациями являются некоторые расширения браузера, которые, вероятно, даже не поддерживаются.


на в HTML5 является допустимым атрибутом id:

нет никаких других ограничений на то, какую форму ID может принять; в в частности, идентификаторы могут состоять только из цифр, начать с цифры, начать с символа подчеркивания, состоящих из знаков препинания и т. д.

Так как это не является действительным идентификатор CSS, чтобы использовать его с querySelector() или $() вы должны избежать этого, как это:

#\.someMethodName

Сеть Разработчиков Mozilla:

для соответствия идентификатору или селекторам, которые не следуют синтаксису CSS (с помощью двоеточие или пробел неуместно, например),вы должны бежать характер с задней косой чертой. Как обратная косая черта является Escape-символом в JavaScript, если вы вводите литеральную строку,вы должны бежать это дважды (один раз для строки JavaScript, а другой раз для querySelector):

имейте в виду, что это не является действительным HTML4 атрибут id


вы должны бежать . С \ перед запросом элементов. Заменить

document.querySelector('#.someMethodName');

до

document.querySelector('#\.someMethodName');

Также обратите внимание, что технически, для HTML 4 требуемый формат значения ID указан ниже:

маркеры ID и NAME должны начинаться с буквы ([A-Za-z]) и могут сопровождаться любым количеством букв, цифр ([0-9]), дефисов ("-"), подчеркиваний ("_"), двоеточий ( " :") и периодов (".").

так .[A-Za-z] является недействительным..


относительно соглашений об именах HTML5 ID


в HTML5, вы можете назовите свой ID атрибуты все, что вы хотите практически без ограничений по синтаксису:

нет никаких других ограничений на то, какую форму может принимать идентификатор; в частности, идентификаторы могут состоять только из цифр, начинаться с цифры, начинаться с подчеркивания, состоять только из пунктуации и т. д.


какие функции селектора ждем


однако при использовании селекторов JavsScript, таких как документ.querySelector(), важно отметить, что синтаксис как он оценивает свои аргументы.

возвращает первый элемент в документе (с использованием глубины первого предварительного порядка обхода узлов документа / первым элементом в разметке документа и итерации через последовательные узлы по порядку количества дочерних узлов), который соответствует указанная группа селекторов.

элемент = документ.querySelector(селекторов);

  • element является объектом элемента.
  • selectors - строка, содержащая один или несколько селекторов CSS, разделенных запятыми.


когда вы путаете функции селектора


Итак, здесь мы видим, что он пытается разобрать селекторы CSS. В основном, функция интерпретирует любую строку, начинающуюся с # как класс и любая строка, начинающаяся с # как id, так что когда вы пытаетесь передать ему строку, как это:

#.someMethodName

он думает, что вы пытаетесь разобрать id и Класс all как один аргумент и выдает ошибку, называя ее синтаксической ошибкой.


В Заключение


Итак, в заключение, в то время как ваши значения ID технически допустимы, используя . и # будет путать эти функции селектора JavaScript, такие как $(selector) и document.querySelector(selector) etc.

чтобы устранить эту проблему, вам нужно сообщить функции, что вы пытаетесь использовать . или # в качестве символа вместо идентификатора путем экранирования символов без идентификаторов:

#\.someMethodName

рабочая демонстрация этого в действии


почему сам браузер принимает этот якорь, а jQuery и querySelector-нет?

потому что хэш не является селектором CSS, это # с последующим идентификатором.

браузер счастливо прокручивается к этому элементу, потому что он не использует хэш, без изменений, как селектор CSS. Вероятно, он вообще не использует селектор CSS, а скорее его внутренний метод поиска элементов по ID - тот, который также вызывается document.getElementById, что также не волнует точка. Доказательство:

document.getElementById(".someMethodName").style.color = "green";
<div id=".someMethodName">I'm green because I was found by <code>document.getElementById(".someMethodName")</code></div>

хотя это правда, что CSS использует # чтобы отметить начало селектора идентификаторов, это не означает, что каждый # everywhere-это начало селектора идентификаторов CSS.

если браузер сделал используйте хэш в качестве селектора CSS, он, по-видимому, будет правильно избегать его до его использования.