Отсканируйте страницу и найдите отсутствующие теги заголовка

#javascript #java #accessibility #html-heading

Вопрос:

Мы внедряем доступность на нашем сайте. Поскольку контент на сайте является авторским, одним из требований, заданных клиентом, было получение информации о том, пропускаются ли теги заголовка на странице. Например. если тег h3 используется после h1 вместо h2. Пожалуйста, дайте мне знать, если это можно сделать предпочтительно на Javascript/Java.

Комментарии:

1. Что вы имеете в виду под»Явой»? Java в браузере была удалена почти из каждого браузера.

Ответ №1:

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

  • оставайтесь на том же (том же уровне)
  • уменьшение (резервное копирование одного или нескольких уровней)
  • увеличение (только на один).

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

Приведенный ниже фрагмент кода проверит все это, а затем вернет массив элементов для отладки.

Возвращаемые поля являются:

  • Предыдущий уровень заголовка: предыдущий правильный уровень заголовка, чтобы вы могли проверить вложенность (полезно посмотреть, действительно ли ошибка заключается в том, что этот уровень заголовка неверен и должен быть на один уровень ниже!),
  • seenHeadingLevel: уровень заголовка, который мы видели,
  • Ожидаемый уровень заголовка: уровень заголовка, который мы ожидали увидеть,
  • seenHeadingText: текст заголовка, который пропустил уровень заголовка, чтобы вы могли его найти.,
  • Предыдущий заголовок: текст предыдущего заголовка, чтобы вы могли легко найти его на странице.

Использование

Чтобы использовать следующий фрагмент кода, вы можете вызвать его checkheadings() для проверки всего документа.

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

Пожалуйста, обратите внимание: Поскольку технически допустимо иметь более одного <h1> документа в документе, это не проверяется, однако стоит отметить, что считается хорошей практикой иметь только один <h1> на странице.

Пример кода

 function getHeadingLevel(heading) {
    return parseInt(heading.tagName[1]);
}

function createError(expectedHeadingLevel, previousHeadingLevel, previousHeadingText, currentHeadingLevel, currentHeadingText){
  var err = {};
  err.previousHeadingLevel = (previousHeadingLevel == 0) ? "no previous headings" : previousHeadingLevel;
  err.seenHeadingLevel = currentHeadingLevel;
  err.expectedHeadingLevel = expectedHeadingLevel;
  err.seenHeadingText = currentHeadingText;
  err.previousHeadingText = previousHeadingText;
  
  return err;
}


function checkheadings(container) {
    container = container || 'body';
    var cont = document.querySelector(container);
    var headings = cont.querySelectorAll("h1, h2, h3, h4, h5, h6");
    var errors = [];
    var previousHeadingLevel = 0;
    var previousHeadingText = "Document Start - no headings yet";
    
    if (headings.length < 1) {
        errors.push("no headings detected");
        return errors;
    }

    for (x = 0; x < headings.length; x  ) {
        var currentHeadingLevel = getHeadingLevel(headings[x]);
        var currentHeadingText = headings[x].textContent;
        var expectedHeadingLevel = previousHeadingLevel   1;
        if (currentHeadingLevel > expectedHeadingLevel) {
            //errors.push("H"   expectedLevel   " skipped. Previous correct heading was H"   previousHeadingLevel   " containing text:"   previousHeadingText   ". Unexpected H"   currentHeadingLevel   " text: "   currentHeadingText);
            
            errors.push(createError(expectedHeadingLevel, previousHeadingLevel, previousHeadingText, currentHeadingLevel, currentHeadingText));
            
            continue;
        }

        previousHeadingLevel = currentHeadingLevel;
        previousHeadingText = currentHeadingText;
    }


    return errors;
}

console.log("1 error", checkheadings('.test1'));
console.log("3 errors", checkheadings('.test2'));
console.log("no errors", checkheadings('.test3'));
console.log("entire document", checkheadings()); 
 <div class="test1">
  <h1>h1-1</h1>
  <h2>h2-1</h2>
  <h4>h4-1 - skipped</h4>
  <h3>h3-1</h3>
  <h2>h2-2</h2>
  <h3>h3-2</h3>
  <h2>h2-2</h2>
  <h2>h2-3</h2>
  <h3>h3-3</h3>
</div>
<div class="test2">
  <h2>h2 - skipped</h2>
  <h1>h1-1</h1>
  <h4>h4-1 - skipped</h4>
  <h3>h3-1 - skipped</h3>
</div>
<div class="test3">
  <h1>h1-1</h1>
  <h2>h2-1</h2>
  <h3>h3-1</h3>
  <h2>h2-2</h2>
  <h3>h3-2</h3>
  <h2>h2-3</h2>
  <h3>h3-3</h3>
  <h4>h4-1</h4>
  <h5>h5-1</h5>
</div> 

Комментарии:

1. Это очень хороший служебный скрипт. Отличная работа! Когда я тестировал (в chrome), он продолжал выдавать ошибки cont.querySelectorAll , но изменение cont на document заставило все работать. Несколько мыслей по этому поводу: (1) сценарии могут сообщить вам, пропущены ли уровни, но ни один алгоритм не может определить, используется ли правильный уровень заголовка — это требует проверки человеком, и (2) элементы секционирования могут изменить ожидаемый поток, тем самым давая ложные срабатывания. Отличный ответ.

2. Как странно, он выдал ошибку, я только построил его в скрипке, так что я предполагаю, что это как-то связано с по умолчанию document.querySelector('body'); (или вы его назвали с селектором?) — Я только построили его таким образом для демонстрации (чтобы я мог запускать сценарии 3) и на возможность тестировать разделы, я буду видеть, если я могу это исправить. Отличные моменты в отношении 2-х необходимых битов человеческой проверки! Теперь я ломаю голову над тем, могу ли я также учитывать элементы секционирования 😋

Ответ №2:

Напишите базовый веб-искатель java https://mkyong.com/java/jsoup-basic-web-crawler-example/ и с помощью Jsoup вы можете выполнить синтаксический анализ

 // Group of all h-Tags
Elements hTags = doc.select("h1, h2, h3, h4, h5, h6");

// Group of all h1-Tags
Elements h1Tags = hTags.select("h1");
// Group of all h2-Tags
Elements h2Tags = hTags.select("h2");
// ... etc.
 

Убедитесь, что у нас есть несколько H1, что также является проблемой в SEO

Ответ №3:

Вы можете использовать document.querySelectorAll("h1, h2, h3, h4, h5, h6") , а затем проанализировать полученный список узлов.

Я не уверен, как выглядит ваш желаемый результат. Этот фрагмент кода вернет массив с номерами всех пропущенных файлов. Также он ожидает только одного h1, h2, … соответственно.

 const headings = document.querySelectorAll("h1, h2, h3, h4, h5, h6")

const getHeadingNumber = (heading) => parseInt(heading.tagName[1])

let lastHeadingNumber;
const skippedHeadings = []
for (let heading of headings) {
  if(!lastHeadingNumber) {
    lastHeadingNumber = getHeadingNumber(heading)
    continue;
  }
  
  const currentHeadingNumber = getHeadingNumber(heading)
  const expectedHeadingNumber = lastHeadingNumber   1
  
  if(expectedHeadingNumber !== currentHeadingNumber) {
    skippedHeadings.push(expectedHeadingNumber)
  }
  
  lastHeadingNumber = currentHeadingNumber;
}
console.log(skippedHeadings) 
 <h1></h1>
<h3></h3>
<h5></h5>