Closed7

Remix+CloudflareでWebサイトを作る 26(display: noneとアクセシビリティ、deferとSuspence、h1タグを複数使うのは良いのか)

saneatsusaneatsu

【2024-05-29】 display: none はアクセシビリティを悪くする

背景

Lighthouseでスコアを色々みるようになってからWebアクセシビリティにも少しだけ気を使えるようになってきた今日このごろ。

https://qiita.com/YutaroYoshikawa/items/2b10e83091834c72346d

ファイルアップロードのためにinputをtype="file" にしてdisplay: noneにするようなコンポーネントを作成中こんな記事をみかけた。

アクセシビリティ

つまりこういうこと。

  • Webサイトはいろいろな媒体・いろいろなユーザーが見るので、アクセシビリティを向上することでイケてるサイトにしよう
  • アクセシビリティツリーというツリー構造のデータを生成している
    • これはDOM、CSSOM(CSSから生成されるツリー構造のデータ)を元に生成される
    • つまり、CSSによってはアクセシビリティ情報に影響が出てしまう

display: none の問題点

今回の場合 display: none を使う
→スクリーンリーダーにも要素が認識されなくなる
→アクセシビリティツリーの要素に影響が...!

https://developer.mozilla.org/ja/docs/Web/CSS/display#アクセシビリティの考慮

MDNにも書いてある。

visibility: hidden はダメなの?

似たような非表示系にこれがあるが違いは何か。

https://developer.mozilla.org/ja/docs/Web/CSS/visibility#値

要素のボックスは不可視になります (描画されません) が、レイアウトには通常通り影響します。子孫要素は visibility が visible に設定されていれば可視になります。(タブ順で操作された時などに) 要素はフォーカスを受け取ることができません。

dispaly: none はほんとうに丸ごと削除するが、visibility: none は高さや幅を維持したまま消してくれる。
で、こちらも使用するとアクセシビリティツリーからは削除される。


【CSS】display:noneとvisibility:hiddenの違いと非表示にする際の注意点 | オジマネ から。
わかりやすい。

まとめ

https://qiita.com/kabechiyo13/items/29fb9083cdec3f8d24d2

ありがたや。

じゃ、どうすんのよ

hiddenを使ってもアクセシビリティに影響する。
使ってくださいと言わんばかりにこの属性があるならなんか、こう...よしなにやっといてもらえないかね?

<input type="file" accept="image/png, image/jpeg" hidden />

opacityを0にすれば?

0にしたら見えなくなるだけでアクセシビリティに影響はないんだよな。
ただ見えなくても該当箇所をクリックしたらファイル選択のモーダルが開いてしまう。

https://developer.mozilla.org/ja/docs/Web/CSS/pointer-events

しかし、これは pointer-events: none にすれば回避できるのでは...?

ということで書いてみよう

https://zenn.dev/link/comments/8b2c16644dbc9b

こんな記事を見たのでlabelではなくbuttonを使って書いてみる。

function FileUpload() {
  const fileInput = useRef<HTMLInputElement | null>(null);
  const handleClick = () => {
    if (!fileInput || !fileInput.current) {
      return;
    }

    fileInput.current.click();
  };

  const [src, setSrc] = useState<string>("");
  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    if (!event || !event.target || !event.target.files) {
      return;
    }

    const file = event.target.files[0];
    setSrc(URL.createObjectURL(file));
  };

  return (
    <div>
      <button type="button" onClick={handleClick}>
        {src ? (
          <img
            src={src}
            alt="uploaded-thumbnail"
            className="h-60 w-96 border object-contain rounded-xl"
          />
        ) : (
          <div className="h-60 w-96 border object-contain rounded-xl flex items-center justify-center text-sm text-muted-foreground">
            クリックして画像を選択
          </div>
        )}
      </button>

      <input
        id="article-thumbnail"
        ref={fileInput}
        type="file"
        accept="image/png, image/jpeg"
        // className="opacity-0 pointer-events-none"
        // 下のコメントで教えてもらったが、Tailwindにはsr-onlyというものがあるのでそれを使えば良さそう
        className="sr-only" // こっちでOK
        onChange={handleChange}
      />
    </div>
  );
}

簡易なものが作れた。
このborderで囲っている箇所の右側に見えないinput があるんだけどpointer-event-none のおかげでクリックしてもファイル選択モーダルが開かない。

また opacity: 0 の場合display: none visibility: hidden と違って、キーボードのタブフォーカスも可能になる!

ん〜これはこれで良さそうだけど、ベストプラクティスを知りたい。
明日調べる。

追記:下のコメントで書いていただいてある通りTailwindを使っているのであれば sr-only というものが使えるとのこと👏🏻

アクセシビリティって大変じゃね?

え〜〜、こういうの細かくやってかないとスコア上がらないの?
大変そうすぎない?

そして自分はHTMLやCSSについてまだまだ何も知らないんだなぁと。。

saneatsusaneatsu

お〜〜便利なものが提供されてますね!
ありがとうございます🙇🏻‍♂️

こっち使ってみます。

saneatsusaneatsu

【2020-05-31】jsonじゃなくてdeferもいるよ

最近ZennのRemixのタグをちょくちょく見るんだけど以下の記事を見つけた。

https://zenn.dev/apple_yagi/articles/1b5dd876b3c5e5

loaderで重い処理をするときに、jsonではなくdeferで返すという方法があるのか。
deferを使うBefore/Afterの速度計測したいな。

誰でも叩けるめっちゃ重い処理するエンドポイントとか探せばありそうだけど。

この例では<Suspense>で囲む必要がなくなったという書き方をしているけど、defer側と同じようにfallbackの処理書きたければいるのでは...?

https://react.dev/reference/react/use#streaming-data-from-server-to-client

まだ全然理解してないけど公式もそんな感じの書き方。

無駄にスケルトンとか実装してみようかな。

ちゃんと理解したい記事

https://zenn.dev/uhyo/articles/react-use-rfc
https://zenn.dev/uhyo/articles/react-use-rfc-2
https://zenn.dev/uhyo/books/react-concurrent-handson
https://zenn.dev/uhyo/books/react-19-new/viewer/use

useフックを解説してくれてるすごいボリュームの記事、理解が追いついていないのでちゃんとわかるようになりたい。
ChatGPTに聞いてみたけど、まだReact 19というものを知らないらしい。

その他

https://qiita.com/taisei-13046/items/9a35c8d969954211f0ed

調べてるときに見つかったHydrogenのテンプレートも見てみようかな。

saneatsusaneatsu

【2024-06-02】h1 タグは1ページに複数でもいいのか

疑問

Markdown形式で文章を書いたら#h1に変換してたけどh1が複数になってしまう。
h1 タグって1ページに1個じゃないとHTMLの本来の使い方(?)じゃなかったり、SEO的にダメみたいなのなかったっけか?

https://developer.mozilla.org/ja/docs/Web/HTML/Element/Heading_Elements#1_つのページに複数の_h1_要素を使用しない

1 つのページに複数の <h1> 要素を使用することは HTML 標準では認められていますが(入れ子でない限り)、これはよい習慣とはみなされません。

結論

HTMLの構造的な意味でも、SEO的な意味でも、複数あってもOKっぽい。

HTMLの構造

ちゃんと区切ってたらいいっぽい。

<main>
  <section>
    <h1>Section 1 Title</h1>
    <p>Content for section 1.</p>
  </section>

  <section>
    <h1>Section 2 Title</h1>
    <p>Content for section 2.</p>
  </section>

  <article>
    <h1>Article Title</h1>
    <p>Content for the article.</p>
  </article>
</main>

SEO的

自分がSEOに詳しくない、かつソースが正しくない場合があるかもだがまとめるとこんな感じだった。
どこまでほんとなんだ。

  • h1タグは検索順位への直接的な影響はない(全く関係ないわけでもないが)
    • 数年前までは検索順位として直接的な効果はあった
  • h1タグは32文字以内、狙っているキーワードを入れるとSEO的に良い

参考

Zennではどうなってる?

ZennはMarkdownで#を書くと表示するときにはh1に変換してる。

例1

https://zenn.dev/b1essk/articles/remix-spa-mode#spa-mode-の概要

記事の見出しで#を使っているためh1が複数回登場する。
目次は「◯」がh1、「・」がh2になっている。

例2

https://zenn.dev/socialplus/articles/2c2fa9c34acb7e

記事の見出しで##を使っているためh1が登場せず、h2の見出しになっている
この場合、目次は「◯」がh2、「・」がh3になっている。

section

h1を複数回使用していてもちゃんとsectionで囲んでいる。
articleではない理由ってなんかるのかな。
次のScrapで違いを調べてみよう。

このスクラップは6ヶ月前にクローズされました