質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
CSS3

CSS(Cascading Style Sheet)の第3版です。CSS3と略されることが多いです。色やデザインを柔軟に変更することが可能になります。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

CSS

CSSはXMLやHTMLで表現した色・レイアウト・フォントなどの要素を指示する仕様の1つです。

Q&A

解決済

2回答

565閲覧

矢印キーでフォーカスの左右上下移動

skillUp

総合スコア25

CSS3

CSS(Cascading Style Sheet)の第3版です。CSS3と略されることが多いです。色やデザインを柔軟に変更することが可能になります。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

CSS

CSSはXMLやHTMLで表現した色・レイアウト・フォントなどの要素を指示する仕様の1つです。

0グッド

1クリップ

投稿2022/10/28 09:51

編集2022/10/28 10:09

前提

3カラムの中にボタンとリンク、文言があります。
tabキーでフォーカスを移動します。

実現したいこと

tabキーを押してフォーカスを下へ、またはshift + tabで上に移動することはできますが、
矢印キーの上下左右でフォーカス移動したいです。
ボタン1 → ボタン2 → ボタン6 → ボタン6_2 → ボタン7_2 → ボタン8_2 → サブリンク2_2 → サブリンク4 → ボタン12 → ボタン11
というように矢印キーでカラム間を跨いで、好きな方向へ行ったり戻ったりするにはどのようにすればよろしいでしょうか。

該当のソースコード

HTML

1<div id="wrapper"> 2 <div class="inner_left"> 3 <div class="frame_button"> 4 <button><span>ボタン1</span></button> 5 <button><span>ボタン2</span></button> 6 <button><span>ボタン3</span></button> 7 <button><span>ボタン4</span></button> 8 <a href="">サブリンク</a> 9 <div tabindex="0">………</div> 10 </div> 11 </div> 12 <div class="inner_right main_content"> 13 <div class="main_inner"><button><span>ボタン5</span></button> 14 <button><span>ボタン6</span></button> 15 <button><span>ボタン7</span></button> 16 <button><span>ボタン8</span></button> 17 <a href="">サブリンク2</a> 18 <div tabindex="0">リンク3</div> 19 </div> 20 <div class="main_inner"><button><span>ボタン5_2</span></button> 21 <button><span>ボタン6_2</span></button> 22 <button><span>ボタン7_2</span></button> 23 <button><span>ボタン8_2</span></button> 24 <a href="">サブリンク2_2</a> 25 <div tabindex="0">リンク3_2</div> 26 </div> 27 </div> 28 <div class="inner_right"> 29 <button><span>ボタン9</span></button> 30 <button><span>ボタン10</span></button> 31 <button><span>ボタン11</span></button> 32 <button><span>ボタン12</span></button> 33 <a href="">サブリンク4</a> 34 <div tabindex="0">リンク5</div> 35 </div> 36 </div> 37 </div> 38 </div> 39 </div> 40</div> 41

CSS

1#wrapper{ 2 align-items:center; 3 display:flex; 4 justify-content:space-around; 5 width:80%; 6 margin:0 auto; 7 padding:10px; 8} 9 10button{ 11 display:block; 12 margin-bottom:10px; 13} 14 15.inner_left{ 16 background:#F6E3CE; 17 padding:10px; 18} 19 20.inner_right{ 21 background:#D0F5A9; 22 padding:10px; 23} 24.inner_right.main_content{ 25 align-items:center; 26 display:flex; 27 justify-content:space-around; 28 width:80%; 29 margin:0 auto; 30 padding:10px; 31}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ボタンにidを振ってカスタムデータで上下左右行きたいボタンのidを指定してやるとよいのでは?

javascript

1<style> 2#btns{ 3display:flex; 4flex-wrap:wrap; 5width:100px; 6} 7#btns button{ 8width:33%; 9} 10</style> 11<script> 12document.addEventListener('keydown',e=>{ 13 Object.entries({d:"Down",u:"Up",r:"Right",l:"Left"}).forEach(x=>{ 14 if(e.code==`Arrow${x[1]}` && e.target.matches(`[data-${x[0]}`)){ 15 document.querySelector(e.target.dataset[x[0]]).focus(); 16 } 17 }); 18}); 19</script> 20<div id="btns"> 21<button id="b1" data-r="#b2" data-d="#b4">1</button> 22<button id="b2" data-l="#b1" data-r="#b3" data-d="#b5">2</button> 23<button id="b3" data-l="#b2" data-d="#b6">3</button> 24<button id="b4" data-r="#b5" data-u="#b1" data-d="#b7">4</button> 25<button id="b5" data-l="#b4" data-r="#b6" data-u="#b2" data-d="#b8">5</button> 26<button id="b6" data-l="#b5" data-u="#b3" data-d="#b9">6</button> 27<button id="b7" data-r="#b8" data-u="#b4">7</button> 28<button id="b8" data-l="#b7" data-r="#b9" data-u="#b5">8</button> 29<button id="b9" data-l="#b8" data-u="#b6">9</button> 30</div>

投稿2022/10/28 10:30

yambejp

総合スコア114806

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

skillUp

2022/10/30 08:17

方向性を示していただき ありがとうございます。
guest

0

ベストアンサー

⭐️ 動作確認用サンプル: https://jsfiddle.net/2ub63Lto/

処理の概要

  • まずは、フォーカス可能な要素に座標番号のデータ属性をJSで動的に付与します。
    • 例えば、data-coord="0-0"を付与
    • <button data-coord="0-0"><span>ボタン1</span></button>
    • JSにより自動で付与されますので、自分で考えながらHTMLに座標番号を書かなくてもいいです。
  • 左上を起点として(x=0, y=0)とすると、各要素の座標は以下の画像の通りとなります。

画面上の配置

  • JavaScriptでフォーカス可能な要素を全て取得し、2次元配列に格納して、繰り返し処理で座標番号を付与しています。

JSの二次元配列

  • 矢印キーを押下したら現在の座標番号を取得し、移動先の座標番号を計算します。
座標計算の例
  • 例えば、現在フォーカスしている要素が「ボタン7」の場合 → 座標番号は1-2
  • 矢印キー押下時の座標の増減値と、計算結果(=移動先の座標)は以下の表の通り。
'1-2' 基準の例
座標の増減値[-1,0][1,0][0,-1][0,1]
移動先の座標'0-2''2-2''1-1''1-3'
  • あとは、例えばキーの場合、data-coord="0-2"の要素にフォーカスしてやるだけです。

完成コード例

htmlに.focusable-containerfocusable-itemというclassを追加

html

1<div id="wrapper"> 2 <div class="inner_left"> 3 <div class="frame_button focusable-container"> <!-- class追加 --> 4 <button class="focusable-item"><span>ボタン1</span></button> <!-- class追加 --> 5 <button class="focusable-item"><span>ボタン2</span></button> <!-- class追加 --> 6 <button class="focusable-item"><span>ボタン3</span></button> <!-- class追加 --> 7 <button class="focusable-item"><span>ボタン4</span></button> <!-- class追加 --> 8 <a href="" class="focusable-item">サブリンク</a> <!-- class追加 --> 9 <div class="focusable-item" tabindex="0">………</div> <!-- class追加 --> 10 </div> 11 </div> 12 <div class="inner_right main_content"> 13 <div class="main_inner focusable-container"> <!-- class追加 --> 14 <button class="focusable-item"><span>ボタン5</span></button> <!-- class追加 --> 15 <button class="focusable-item"><span>ボタン6</span></button> <!-- class追加 --> 16 <button class="focusable-item"><span>ボタン7</span></button> <!-- class追加 --> 17 <button class="focusable-item"><span>ボタン8</span></button> <!-- class追加 --> 18 <a class="focusable-item" href="">サブリンク2</a> <!-- class追加 --> 19 <div class="focusable-item" tabindex="0">リンク3</div> <!-- class追加 --> 20 </div> 21 <div class="main_inner focusable-container"> <!-- class追加 --> 22 <button class="focusable-item"><span>ボタン5_2</span></button> <!-- class追加 --> 23 <button class="focusable-item"><span>ボタン6_2</span></button> <!-- class追加 --> 24 <button class="focusable-item"><span>ボタン7_2</span></button> <!-- class追加 --> 25 <button class="focusable-item"><span>ボタン8_2</span></button> <!-- class追加 --> 26 <a class="focusable-item" href="">サブリンク2_2</a> <!-- class追加 --> 27 <div class="focusable-item" tabindex="0">リンク3_2</div> <!-- class追加 --> 28 </div> 29 </div> 30 <div class="inner_right focusable-container"> <!-- class追加 --> 31 <button class="focusable-item"><span>ボタン9</span></button> <!-- class追加 --> 32 <button class="focusable-item"><span>ボタン10</span></button> <!-- class追加 --> 33 <button class="focusable-item"><span>ボタン11</span></button> <!-- class追加 --> 34 <button class="focusable-item"><span>ボタン12</span></button> <!-- class追加 --> 35 <a class="focusable-item" href="">サブリンク4</a> <!-- class追加 --> 36 <div class="focusable-item" tabindex="0">リンク5</div> <!-- class追加 --> 37 </div> 38</div>

cssに以下を追加

css

1*:focus { 2 border: 1px solid blue; 3 border-radius: 0.2em; 4}

javascript

1const wrapper = document.querySelector('#wrapper'); 2const focusableContainers = document.querySelectorAll('.focusable-container'); 3const focusableItemsMap = [...focusableContainers].map(fc => [...fc.querySelectorAll('.focusable-item')]); 4const focusableItems = focusableItemsMap.flatMap(elems => elems); 5 6window.addEventListener('DOMContentLoaded', setDataCoord, false); 7wrapper.addEventListener('keydown', manipulateFocus, false); 8 9function setDataCoord() { 10 const coords = [...focusableItemsMap].flatMap((elems, x) => elems.map((_, y) => `${x}-${y}`)); 11 focusableItems.forEach((elem, i) => elem.dataset.coord = coords[i]); 12} 13 14function manipulateFocus(event) { 15 const keys = {'ArrowLeft': [-1, 0], 'ArrowRight': [1, 0], 'ArrowUp': [0, -1], 'ArrowDown': [0, 1]}; 16 17 for (const [key, [x, y]] of Object.entries(keys)) { 18 if (event.key === key) { 19 event.preventDefault(); 20 const currentCoord = event.target.dataset.coord; 21 const targetCoord = currentCoord ? currentCoord.replace(/(\d+)-(\d+)/, (_, px, py) => [Number(px) + x, Number(py) + y].join('-')) : '0-0'; 22 const [targetElem] = document.querySelectorAll(`[data-coord="${targetCoord}"]`); 23 if (targetElem) targetElem.focus(); 24 return; 25 } 26 } 27}

コメントによる解説付きJavaScriptコード

処理の内容をわかりやすくするために、コメントで解説を書きました。
コードの内容は上記のものと全く同じです。

javascript

1/** 2 * 要素の取得 3 */ 4// #wrapper要素を取得 5const wrapper = document.querySelector('#wrapper'); 6 7// .focusable-container要素を取得 8const focusableContainers = document.querySelectorAll('.focusable-container'); 9 10// それぞれの.focusable-containerの中身の要素を取得し、containerごとに2次元配列に格納する 11const focusableItemsMap = [...focusableContainers].map(fc => [...fc.querySelectorAll('.focusable-item')]); 12 13// ↑を一次元配列化する 14const focusableItems = focusableItemsMap.flatMap(elems => elems); 15 16/** 17 * イベントリスナー設定 18 */ 19window.addEventListener('DOMContentLoaded', setDataCoord, false); // ページロード時 20wrapper.addEventListener('keydown', manipulateFocus, false); // キーを押している間 21 22/** 23 * 座標番号(data-coord属性)を要素に付与する関数 24 */ 25function setDataCoord() { 26 // 座標を生成 27 const coords = [...focusableItemsMap].flatMap((elems, x) => elems.map((_, y) => `${x}-${y}`)); 28 29 // 一旦こういう形の2次元配列を生成してから 30 // [ 31 // ['0-0', '0-1', '0-2', '0-3', '0-4', '0-5'] 32 // ['1-0', '1-1', '1-2', '1-3', '1-4', '1-5'] 33 // ['2-0', '2-1', '2-2', '2-3', '2-4', '2-5'] 34 // ['3-0', '3-1', '3-2', '3-3', '3-4', '3-5'] 35 // ] 36 37 // 1次元配列化しています 38 // ['0-0', '0-1', '0-2', '0-3', '0-4', '0-5', '1-0', '1-1', '1-2', '1-3', '1-4', '1-5', '2-0', '2-1', '2-2', '2-3', '2-4', '2-5', '3-0', '3-1', '3-2', '3-3', '3-4', '3-5'] 39 40 // 生成した座標をデータ属性として、.focusable-itemに付与していく 41 focusableItems.forEach((elem, i) => elem.dataset.coord = coords[i]); 42} 43 44/** 45 * 矢印キーでフォーカスを操作する関数 46 */ 47function manipulateFocus(event) { 48 49 // 矢印キーによって加算される座標値 50 const keys = {'ArrowLeft': [-1, 0], 'ArrowRight': [1, 0], 'ArrowUp': [0, -1], 'ArrowDown': [0, 1]}; 51 52 // オブジェクトkeysの中身を一つずつ確認 53 for (const [key, [x, y]] of Object.entries(keys)) { 54 55 // 押したキーとオブジェクトkeysのプロパティ名が一致するとき、 56 if (event.key === key) { 57 58 // デフォルトの矢印キーの動きを停止 59 event.preventDefault(); 60 61 // 現在フォーカスしている操作ボタンの座標番号を取得 62 const currentCoord = event.target.dataset.coord; 63 64 // 移動先の座標番号を計算(矢印キー押下時、何もフォーカスしていなかったら移動先の座標は'0-0') 65 const targetCoord = currentCoord ? currentCoord.replace(/(\d+)-(\d+)/, (_, px, py) => [Number(px) + x, Number(py) + y].join('-')) : '0-0'; 66 67 // 移動先の要素を取得する 68 const [targetElem] = document.querySelectorAll(`[data-coord="${targetCoord}"]`); 69 70 // その座標番号を持つ要素が存在していたら、その要素をフォーカスする 71 if (targetElem) targetElem.focus(); 72 73 // ここで繰り返し処理を完全に終了(残りのオブジェクトの中身はチェックされないので無駄な処理を少なく!) 74 return; 75 } 76 } 77}

投稿2022/10/28 22:38

編集2022/10/28 23:43
Cocode

総合スコア2314

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

skillUp

2022/10/30 08:18

丁寧に説明していただきありがとうございます。 色々な画面に対応できそうですね。 勉強になります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問