🐙

「1文字ずつ表示」させただけで終わるのはエアコンつけたまま実家に帰るのと同じ【アクセシビリティ】

2022/07/09に公開

突然のコードサンプル

よくみるヤツに今更何を?

1文字ずつ表示する系の演出自体は頻繁に要求されるので「はいはい、アレね」くらいのテンションでやっていましたが、上記ツイートの参考サイトとして掲載されていた
https://www.richardekwonye.com/about
↑である気づきを得ました。

1文字ずつ表示させて満足したら困るユーザーがいる

大量生成されたspanが全部アクセシビリティツリーに入っちゃったらスクリーンリーダーユーザーは「エイチ オー ジー イー エフ ユー ジー エー」みたいに読み上げられて「?」状態になってしまうという、ちょっと考えたらわかることを見落としていました。大量生成されたspanにはaria-hidden="true"が指定されていなければならない...
悔い改めたコードを供養します。

ソース

思いつきで書いたので伸び代のあるコードに仕上がってると思いますがご容赦ください

HTML

    <p class="text-onebyone">
      <span class="for-accessibility">1文字ずつ表示させる</span>
      <span class="text-split">1文字 ずつ 表示 させる</span>
    </p>

SCSS

.text-onebyone {
  position: relative;
  .text-split {
    font-size: 4rem;
    clip-path: inset(0 0 0);
    .text-each {
      display: inline-block;
      opacity: 0;
      transform: translateY(100%);
      &.is-active {
        transition: 1s;
        opacity: 1;
        transform: translateY(0%);
      }
    }
  }
  .for-accessibility {
    position: absolute;
    width: 1px;
    height: 1px;
    clip: rect(0, 0, 0, 0);
  }
}

JavaScript

const textOneByOne = document.querySelector(".text-split");
let getText = textOneByOne.textContent;
textOneByOne.textContent = "";
getText = getText.split("");
getText.forEach(function (elem, index) {
  const newText = "<span aria-hidden='true' class='text-each'>" + elem + "</span>";
  textOneByOne.insertAdjacentHTML("beforeend", newText);
});

const textEach = textOneByOne.querySelectorAll(".text-each");
const delayTime = 100; //何秒遅れで次の文字が表示されるか設定

textEach.forEach(function (elem, index) {
  setTimeout(function () {
    elem.style.transitionDelay = delayTime * index + "ms";
    elem.classList.add("is-active");
  }, delayTime);
});

おわり

引用元のツイート著者も発信していますが、隠れている部分をoverflowではなくclip-pathで実現するのがclip-pathのプチハックとして満足度が非常に高かった...
WAI-ARIAにわかなので、アクセシビリティ的に「ここ詰め甘いぞ」ってポイントあるかもしれません。誤りを流布したくないのでご指摘頂けると非常に助かります

Discussion