Обзор доступности и манипулирования DOM в JavaScript

Проблемы)

Как и многие люди, когда я начал писать статьи на Medium, мне нужен был способ встроить ленту на мой личный сайт-портфолио без необходимости вручную добавлять статьи каждый раз, когда я их публикую. Существует множество ресурсов, освещающих эту тему, поэтому я не буду повторять здесь подробные инструкции.





В конце концов я остановился на использовании бесплатного неофициального виджета Medium от Pixel Point, который после того, как вы введете URL-адрес своего профиля Medium и настроите несколько параметров, даст вам блок HTML, который вы можете добавить на свой сайт, который делает некоторую магию JavaScript для создания приятного Лента новостей среднего размера. Затем вы можете дополнительно использовать CSS для настройки внешнего вида. Это прекрасно работает, однако при тестировании моего сайта на доступность с помощью инструмента оценки доступности веб-сайтов (WAVE) я обнаружил, что в <img> элементах, созданных скриптом виджета, отсутствуют атрибуты alt. Если для вас это тарабарщина, почитайте HTML ‹img› alt Attribute.

Процесс

Поскольку теги <img> добавлялись в DOM с помощью JavaScript виджета при загрузке страницы, это было не так просто, как просто добавить атрибуты в мой статический HTML. Мне пришлось стряхнуть пыль с JavaScript в навыках работы с DOM, что было немного страшно после столь долгой жизни с радостью React.js. Тем не менее, я подумал, что это отличный способ освежить свои знания о DOM и получить дополнительную оценку того, что современные фреймворки делают для вас.

Вот как я разобрался с проблемой:

  • Поиск источника альтернативного текста
  • Выбор правильных элементов HTML из DOM
  • Добавление атрибута alt

Поиск источника альтернативного текста

Поскольку виджет предоставляет «ленту» определенного количества статей, жесткое кодирование замещающего текста для каждого изображения было невозможно. Это также противоречит первоначальной цели использования виджета, поэтому мне не нужно было обновлять свой сайт с каждым постом на Medium.

Для более крупного изображения я решил использовать описание статьи, которое извлекает виджет, поскольку оно будет уникальным для поста и доступно в DOM. Это своего рода компромисс, так как в идеале текст alt должен конкретно описывать изображение, но мне это недоступно на этой странице. Для аватара авторов было довольно ясно, что я могу взять текст из имени, отображаемого справа.

Выбор HTML-элементов из модели DOM

Сначала я думал, что это будет довольно просто, учитывая, что виджет использует довольно уникальные классы для каждого из элементов HTML. Я использовал инструменты разработчика, чтобы определить имена классов, на которые я хотел ориентироваться. Например, якорь <a>element, содержащий элемент main<img>, имеет класс medium-widget-article__image.

Уникальное имя класса означало, что это было так же просто, как document.getElementsByClassName("medium-widget-article__image"), и я бы выбрал этот элемент для управления, верно?

Неверно. Из-за асинхронного характера скрипта среднего виджета, когда выполнялся мой пользовательский код JavaScript, теги <a> и <img> еще не находились в DOM, и я получал HTMLCollection длины 0 (поэтому ничего такого)!

// First attempt at getting the <a> element
((d, w) => {
  console.log(d.getElementsByClassName("medium-widget-article__image"));
})(document, window);

Поэтому я сделал то, что делает любой хороший разработчик, и обратился за помощью к google/stackoverflow. В ответ на вопрос stackoverflow я нашел интерфейс MutationObserver, который позволяет вам следить за изменениями в DOM, а затем выполнять свою работу. Вот пример простого использования для поиска элементов <a> с классом medium-widget-article__image.

Как видите, теперь я получаю HTMLCollection длиной три, что соответствует трем статьям в ленте.

Добавление атрибута alt

Как только я идентифицировал элементы и смог получить и сохранить их с помощью MutationObserver, пришло время манипулировать ими.

Ниже я добавил готовый код с подробными комментариями. Здесь я также объясню некоторые дополнения.

Основное изображение

В mainImgObserver, начиная с line 4, я жду, пока будет отрендерен элемент с medium-widget-article_image, затем получаю этот элемент и сохраняю его в переменной на lines 8/9. Обратите внимание, что я превратил результат из getElementsByClassName() в массив и сопоставил его, чтобы получить firstElementChild. Это дает мне первый дочерний элемент выбранного элемента. Причина этого в том, что элемент ссылки <a> — это элемент с указанным именем класса, а дочерний элемент <img> — это тот, на который я хочу ориентироваться.

Я выполнил аналогичную операцию, чтобы получить текст описания для lines 11/12, однако мне не нужно было получать здесь дочерний элемент, поскольку я мог напрямую выбрать элемент с описанием, учитывая, что у него было определенное имя класса.

Наконец, чтобы применить атрибуты alt= к элементам <img>, я зациклился на массиве элементов <img> и установил img.alt равным соответствующему описанию.

Аватар

Аватар оказался намного проще, так как я узнал из инструмента WAVE, что, поскольку изображение аватара автора располагалось рядом с именем автора, мне просто нужно было установить элемент вот так <img alt="" ...

Я понимаю, что это также относится и к основному изображению, но ради этой статьи и изучения/манипулирования DOM я оставил описание в этом теге alt.

HTML после добавления тегов alt

<!-- Main Image -->
<img src="https://cdn-images-1.medium.com/fit/300/300/1*DeuT8iD3FaiRTevzz4VODQ.png" alt="Reviewing how performance and accessibility requirements were met and thinking about the future">
<!-- Avatar Image -->
<img src="https://i2.wp.com/miro.medium.com/fit/c/200/200/0*RgY7ABMwMVBvipXA" class="medium-widget-article__avatar-picture" alt="">

Вывод

Теперь у меня есть полностью доступная новостная лента Medium на моем личном веб-сайте портфолио, и я обновил свои знания о манипулировании DOM.

Если вы дочитали до этого места, спасибо за чтение, и я надеюсь, что вы тоже чему-то научились. Дайте мне знать, если у вас есть отзывы или вы сделали бы это по-другому!

Код

Фрагменты кода: index.html, scripts.js

Ознакомьтесь с другими моими проектами и статьями: