$30 off During Our Annual Pro Sale. View Details »

「え?!それ今ではHTMLだけでできるの!?」驚きの進化を遂げたモダンHTML

Avatar for Riya Amemiya Riya Amemiya
November 29, 2025

 「え?!それ今ではHTMLだけでできるの!?」驚きの進化を遂げたモダンHTML

このスライドはSlidevで作られており、以下のレポジトリで公開しています
https://github.com/riya-amemiya/amemiya_riya_slide_data/tree/main/frontend_conf_kansai_2025

Avatar for Riya Amemiya

Riya Amemiya

November 29, 2025
Tweet

More Decks by Riya Amemiya

Other Decks in Technology

Transcript

  1. HTML Living Standard の時代へ 2019 年5 月、W3C とWHATWG はHTML とDOM

    標準の開発を WHATWG が主導することで合意しました これにより、HTML は「HTML5 」のようなバージョン番号を持つ仕様から、 継続的に更新される「HTML Living Standard 」へと移行しました
  2. 今日紹介する機能 1. Popover API (Baseline 2024) 2. Dialog 要素 (Baseline

    2022) 3. details 要素のname 属性 (Baseline 2024) 4. inert 属性 (Baseline 2023) 5. search 要素 (Baseline 2023) 6. loading 属性 (Baseline 2020) 7. fetchpriority 属性 (Baseline 2023) 8. blocking 属性 (Baseline 2024) 9. inputmode 属性 (Baseline 2018) 10. enterkeyhint 属性 (Baseline 2021) 11. rel 属性のSEO 対応値 (2019)
  3. 今はHTML だけで解決 popovertarget 属性 + popover 属性を指定するだけ → z-index 管理、外側クリック/ESC

    キーで閉じる、フォーカス管理を自動処理 <button popovertarget="menu"> メニューを開く</button> <div popover="auto" id="menu"> ポップアップの内容</div>
  4. 従来の実装 vs Popover API 従来の実装 管理が複雑 Popover API トップレイヤーで独立 +

    自動イベント管理 <button onclick="togglePopup()"> メニュー </button> <div id="popup" class="popup hidden"> ... </div> <script> function togglePopup() { // 色々な処理が必要 } </script> <button popovertarget="menu"> メニュー </button> <div popover id="menu"> ... </div>
  5. popovertarget 属性による宣言的関係性 属性で関係性を宣言 → 自動的に紐づけ 適切なイベントハンドリング + アクセシビリティ属性の自動設定 <!-- 複数のボタンで同じポップオーバーを制御

    --> <button popovertarget="settings"> 設定を開く</button> <button popovertarget="settings" popovertargetaction="hide"> 設定を閉じる</button> <button popovertarget="settings" popovertargetaction="toggle"> 設定の切り替え</button> <div popover="auto" id="settings"> <h2> 設定</h2> <p> ここに設定内容が入ります。</p> </div>
  6. モーダルダイアログの実装 <dialog id="my-dialog"> <h2> ダイアログタイトル</h2> <p> ダイアログの内容がここに入ります。</p> <button id="close-dialog"> 閉じる</button>

    </dialog> <button id="open-dialog"> ダイアログを開く</button> <script> const dialog = document.getElementById('my-dialog'); document.getElementById('open-dialog').addEventListener('click', () => { dialog.showModal(); // モーダルダイアログとして表示 }); document.getElementById('close-dialog').addEventListener('click', () => { dialog.close(); }); </script>
  7. showModal() とshow() の違い showModal() → モーダル表示 + ::backdrop で背景を覆う +

    フォーカストラップ自動実装 show() → 非モーダル表示、背景の要素も操作可能
  8. form 要素との統合 method="dialog" 指定 → 送信時にダイアログを自動で閉じる + ボタンのvalue を dialog.returnValue

    に設 定 <dialog id="confirm-dialog"> <form method="dialog"> <h2> 削除の確認</h2> <p> この操作は取り消せません。</p> <button value="cancel"> キャンセル</button> <button value="confirm"> 削除</button> </form> </dialog>
  9. Dialog とPopover の使い分け 特性 Dialog Popover フォーカストラップ ✅ 自動(モーダル時) ❌

    なし 背景の無効化 ✅ ::backdrop 擬似要素 ❌ 手動実装必要 ESC キーで閉じる ✅ 自動 ✅ 自動 form 統合 ✅ method="dialog" ❌ なし 用途 確認、入力が必要 情報表示、メニュー
  10. アコーディオンの実装例 JavaScript ゼロ行 <!-- FAQ セクション:一度に1 つの質問だけ開く --> <details name="faq">

    <summary> 返品は可能ですか?</summary> <p> 商品到着後14 日以内であれば返品可能です。</p> </details> <details name="faq"> <summary> 送料はいくらですか?</summary> <p>5,000 円以上のご購入で送料無料です。</p> </details> <details name="faq"> <summary> 支払い方法は?</summary> <p> クレジットカード、銀行振込、代金引換をご利用いただけます。</p> </details>
  11. 非表示スライド内のリンクを無効化したい時 カルーセルUI で前後のスライドも操作可能になってし まう 従来の disabled 属性はフォーム要素のみ → inert 属性でリンクやコンテンツも含めて無効化可

    能 無効化される範囲: フォーカス クリック/ タップ アクセシビリティツリー スライド2 (メイン) リンク → 詳細 スライ リンク 詳細 前後のリンクもフォーカス可能
  12. 各無効化手法の比較 特性 aria-hidden inert disabled 対象範囲 アクセシビリティツリーのみ 視覚・操作・アクセシビリティ フォーム要素のみ マウス操作

    操作可能 操作不可 操作不可(フォーム要素) フォーカス 可能 不可 不可(フォーム要素) 適用可能要素 すべて すべて フォーム要素のみ 従来の disabled 属性はフォーム要素にしか使えませんでしたが、 inert 属性はあらゆるHTML 要素に適用で きるので、より柔軟に無効化できます
  13. 使用例 アクセシビリティツリーで search ランドマークとして認識 → スクリーンリーダーユーザーが検索機能を素早 く発見 <!-- サイト内検索 -->

    <search> <form action="/search" method="get"> <label for="site-search"> サイト内を検索:</label> <input type="search" id="site-search" name="q" required> <button type="submit"> 検索</button> </form> </search>
  14. 画像の遅延読み込み 従来:Intersection Observer API でゴリゴリ実装 今は: loading="lazy" を付けるだけ → 最適なタイミングで自動読み込み

    <!-- ファーストビューの重要な画像 --> <img src="hero-image.jpg" loading="eager" alt=" メインビジュアル"> <!-- スクロール後に表示される画像 --> <img src="product-1.jpg" loading="lazy" alt=" 商品画像1"> <img src="product-2.jpg" loading="lazy" alt=" 商品画像2"> <!-- 外部コンテンツの遅延読み込み --> <iframe src="video-player.html" loading="lazy" title=" 動画プレイヤー"></iframe>
  15. 使用例 <!-- LCP 要素となるヒーロー画像を最優先 --> <img src="hero-banner.jpg" fetchpriority="high" alt=" メインビジュアル">

    <!-- 重要なスタイルシート --> <link rel="stylesheet" href="critical.css" fetchpriority="high"> <!-- 優先度の低い装飾画像 --> <img src="decoration.png" fetchpriority="low" loading="lazy" alt=" 装飾"> <!-- 分析スクリプトは低優先度 --> <script src="analytics.js" fetchpriority="low" async></script>
  16. 優先度の使い分け 優先度 対象リソース 効果 high LCP 画像、クリティカルCSS 、重要なフォント より早く読み込まれる low

    装飾画像、分析スクリプト、非表示コンテンツ 他のリソースを優先 auto その他の一般的なリソース ブラウザのデフォルト動作
  17. 使用例 初期表示に必要不可欠なリソース vs 後から適用可能なリソースを明確に区別 <!-- 通常のスクリプトはレンダリングを停止 --> <script src="library.js"></script> <!--

    defer はDOM 構築完了後に実行 --> <script src="framework.js" defer></script> <!-- preload + blocking="render" でレンダリングを停止 --> <link rel="preload" href="critical-font.woff2" as="font" blocking="render" crossorigin>
  18. 仮想キーボードの最適化 郵便番号入力で数値専用キーボードを出したいのに文 字キーボードが表示されてしまう → inputmode 属性で数値専用キーボードを表示可能 郵便番号 Q W E

    R T Y U I O P 文字キーボード... <!-- 数値専用キーボード --> <input type="text" inputmode="numeric" pattern="[0-9]*" placeholder=" 郵便番号(ハイフンなし)"> <!-- 電話番号用キーボード --> <input type="tel" inputmode="tel" placeholder="090-1234-5678"> <!-- URL 入力用キーボード --> <input type="url" inputmode="url" placeholder="https://example.com"> <!-- メールアドレス用キーボード --> <input type="email" inputmode="email" placeholder="[email protected]">
  19. inputmode の種類 inputmode 表示されるキーボード 適した用途 numeric 0-9 の数字のみ 認証コード、郵便番号 tel

    電話番号用(+ や- を含む) 電話番号 decimal 数字と小数点 価格、数量 email @ や.com キーを含む メールアドレス url / や.com キーを含む URL 入力 search 検索ボタン付き 検索フィールド
  20. Enter キー表示の最適化 検索フィールドなのにEnter キーが「改行」と表示さ れてしまう → enterkeyhint 属性でユーザーに次のアクションを直 感的に示せる 検索...

    1 2 3 スペース 改行 「検索」ではなく「改行」... <!-- 検索フィールド --> <input type="search" enterkeyhint="search" placeholder=" サイト内を検索"> <!-- 複数ステップフォーム --> <input type="text" enterkeyhint="next" placeholder=" お名前"> <!-- フォームの最終項目 --> <textarea enterkeyhint="done" placeholder=" コメント"></textarea> <!-- チャットアプリ --> <input type="text" enterkeyhint="send" placeholder=" メッセージを入力">
  21. enterkeyhint の種類 値 Enter キー表示 使用場面 search 検索 検索フィールド next

    次へ フォームの途中フィールド done 完了 フォームの最終フィールド go 移動 URL 入力フィールド send 送信 メッセージ入力フィールド
  22. 広告リンクとユーザー投稿リンクの区別 全部 nofollow で一括りにしてませんか? 2019 年9 月にGoogle が発表した新しい rel 属性値でリンクの性質を詳細に伝達

    sponsored :広告やアフィリエイトリンク ugc :ユーザー生成コンテンツ内のリンク 検索エンジンがリンクの文脈を正確に理解 → PageRank の評価を適切に調整
  23. 使用例 <!-- 有料広告やスポンサーリンク --> <a href="https://sponsor.com" rel="sponsored"> スポンサーリンク</a> <!-- ユーザー生成コンテンツ内のリンク

    --> <a href="https://user-content.com" rel="ugc"> ユーザー投稿のリンク</a> <!-- 複数の値を組み合わせる --> <a href="https://untrusted-site.com" rel="nofollow sponsored"> 有料の外部リンク </a>
  24. rel 属性の値 値 説明 使用場面 sponsored 広告、スポンサーシップ、金銭的対価のあるリン ク アフィリエイトリンク、記事広告など ugc

    ユーザー生成コンテンツ内のリンク ブログコメント欄、フォーラム投稿内のリン ク 検索エンジンがリンクの文脈を正確に理解 → PageRank 評価を適切に調整
  25. パフォーマンス最適化:loading 属性、fetchpriority 属性、blocking 属性 モバイルUX :inputmode 属性、enterkeyhint 属性 Popover API

    やdetails 要素のname 属性などでJavaScript 依存から脱却、HTML だけで多くのUI パターンを実現
  26. ご清聴ありがとうございました 本日のスライドは下記のリポジトリで公開しています。 内容の修正・改善など、お気軽にPull Request をお送りください。 https://github.com/riya-amemiya/amemiya_riya_slide_data/tree/main/frontend_conf_kansai_2025 X やGitHub など: https://riya-amemiya-links.tokidux.com/

    このスライドは CC BY-SA 4.0 でライセンスされています。 より自由な翻訳を可能にするため、翻訳は例外的に CC BY 4.0 での配布が許可されています。 Required Attribution: Riya Amemiya (https://github.com/riya-amemiya)