openlang

Статус «Сохранено» зачитывается дважды

После одного сохранения скринридер дважды произнёс «Saved». За этим стоит состояние всего с одним переходом в saved, и тест редьюсера это показывает.

Дважды менялся DOM. Компонент статуса рисует область только когда есть сообщение, примерно message && <p aria-live="polite">{message}</p>, так что переход от «нет сообщения» к Saved вставляет совершенно новую live-область, уже с текстом внутри. Рекомендация MDN обратная. Сначала пустая область, дать ей время стать доступной для вспомогательных технологий, потом менять содержимое, и там же оговорка, что поведение разное в разных сочетаниях браузера и скринридера. Область, которая появляется сразу с текстом, - как раз тот случай, о котором предупреждают, и у меня он обернулся двойным чтением.

Выходит, объединение было верным, а озвучка - нет, и ничто в типе не могло этого показать. Тип говорит, каков статус. А переживёт ли узел области перерисовку, зависит уже от DOM, и чинить надо там. Нарисовать область один раз, держать её смонтированной, менять только текст внутри.

Разговор продолжается 3

Следуя доводам
  1. Ссылка на ответ

    Нажали «Сохранить». В старом дереве области нет. Новое приходит с областью и текстом сразу. Одна задача, одна пачка изменений. Скринридер получает новую область и её содержимое в один момент, и что он с этим сделает, решает он сам.

    Поэтому совет MDN читается как инструкция про цикл событий. Создать область пустой, а содержимое положить из более поздней задачи, и для областей, созданных из скрипта, там прямо предлагается setTimeout(). Если держать узел смонтированным, получаешь то же самое бесплатно, потому что область зарегистрирована задолго до первого сообщения.

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

  2. Ссылка на ответ

    Область теперь всё время на месте. Сохранили, там Saved. Поменяли одно поле, сохранили снова, и текст опять Saved. Та же строка, тот же узел. Для скринридера ничего не изменилось, так это вообще озвучат? А если хитрость в том, чтобы очистить и вернуть текст из более поздней задачи, то разве это не та же двухшаговая схема, которая дала tess.p двойное чтение?

  3. Ссылка на ответ

    Тут два вопроса, и на первый React отвечает раньше, чем в дело вступает скринридер. Если компонент снова рендерит Saved вместо Saved, React видит тот же текст и DOM не трогает. Изменения нет, скринридеру нечего заметить и нечего объявлять.

    Приём «очистить и поставить заново» старше любого фреймворка из этой ветки (привычка времён jQuery, .text(''), а потом setTimeout, чтобы вернуть сообщение, и её копировали ещё долго после того, как все забыли, ради какого скринридера она появилась), и по форме он не совпадает с двойным чтением у tess.p. У неё регион появлялся уже с текстом. Здесь регион зарегистрирован с самого начала, очистка - это удаление, а при значении aria-relevant по умолчанию, то есть additions text, удаления объявлять не положено. Второй шаг - обычная смена текста.

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

Другие стороны того же вопроса

  1. Покрасил одну полоску здоровья, покраснели все

    На этот раз меня укусили общие ресурсы в интерфейсе Godot. У каждого юнита в моём маленьком прототипе есть сцена полоски здор…

    Ответы 10gdscript
  2. Должна ли отклонённая плитка сдвигать палитру?

    Если просто создать корутину в Lua, ещё ничего не выполняется. Хост вызывает coroutine.resume, и только тогда генератор работ…

  3. Кто владеет буфером Vulkan после отправки?

    C++ RAII-обёртка над буфером Vulkan записывает работу с этим буфером, отправляет её и выходит из области видимости. Деструкто…

    Ответы 5cppc