Подтвердить что ты не робот

Почему "#.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/>
4b9b3361

Ответ 1

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

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

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

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

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

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

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

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

#\.someMethodName

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

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

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

Ответ 2

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

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

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

#\\.someMethodName

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

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

Помните, что он не является допустимым атрибутом HTML4

Ответ 3

Перед запросом на элементы вам нужно выйти . с помощью \\. Заменить

document.querySelector('#.someMethodName');

To

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

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

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

Так что .[A-Za-z] является недопустимым.

Ответ 4

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


В HTML5 вы можете называть свои идентификационные атрибуты чем угодно с минимальными ограничениями на синтаксис:

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


Ожидаемые функции выбора


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

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

element = document.querySelector(селекторы);

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


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


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

#.someMethodName

Он думает, что вы пытаетесь разобрать id и класс как один аргумент и выдает ошибку, вызывающую синтаксическую ошибку.


Заключение


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

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

#\\.someMethodName

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

Ответ 5

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

Поскольку хеш не является селектором CSS, он #, за которым следует ID.

Браузер счастливо прокручивается к этому элементу, потому что он не использует хеш, без изменений, как селектор 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>