1. ホーム
  2. Web制作
  3. html5

もしかしたら、これらがあなたの欲しいH5ソフトキーボード対応ソリューションかもしれません(要約)。

2022-02-06 18:28:36

プリアンブル

ここしばらくH5チャットのプロジェクトをやっていて、入力ボックスにフォーカスが当たる、ソフトキーボードがポップアップする、入力メソッドボックスにアタッチ(トッピング)することが要求される、という大穴を踏んでしまったんだ。この要件は非常に明確で、とてもシンプルに見えますが、そうではありません。いくつかのモデルで実験した結果、主な問題点は以下の通りでした。

  • AndroidとIOSでは、ソフトキーボードのポップアップ状態と収納状態の違いや、ページのウェブビューの挙動が異なることが分かっています。
  • IOS12、WeChat バージョン v6.7.4 以上では、入力ボックスにフォーカスが当たり、キーボードがポップアップし、ページ(ウェブビュー)が全体的にスクロールアップし、キーボードがしまわれると、元の位置に戻らず、キーボードがあった場所が空白になってしまいます。
  • IOSで、サードパーティ製の入力メソッドを使用すると、高さの計算がずれて、一部の入力メソッドが飛び出し、入力ボックスが一部ふさがれることがある。
  • いくつかのブラウザでいくつかのトリックを使用すると、入力ボックスが入力メソッドによってブロックされたままです。

上記で見つかった問題の解決策を、以下から一つずつ探っていきましょう。

ソフトキーボードの飛び出し、しまい込み状態を知る

ソフトキーボードがポップアップしているのか、収納されているのかを把握することは、後の互換性処理の前提条件となるため重要です。しかし、H5はソフトキーボードのネイティブイベントを直接は聞かないので、ソフトキーボードがポップアップされたときや収納されたときに、ページのパフォーマンスの他の側面をトリガーすることで間接的に聞くことしかできません。また、IOSとAndroidでは挙動が異なります。

IOSソフトキーボードのポップアップパフォーマンス

IOSでは、入力ボックス(input、textarea、リッチテキスト)にフォーカスが当たり、キーボードがポップアップし、ページ(webview)が圧縮されない、あるいは高さが変わらないのに、ページ(webview)全体がスクロールアップし、最大 scrollTop がソフトキーボードの高さになることがあります。

Androidソフトキーボードのポップアップ性能

繰り返しますが、Android では、入力ボックスにフォーカスが当たってキーボードがポップアップしますが、ページ(ウェブビュー)の高さは、一般に表示領域の高さ(元の高さからソフトキーボードの高さを引いたもの)に変わり、ウェブビュー自体は、ページのコンテンツがスクロールを作り出すために立てられているため、スクロールできない状態になっています。

IOSソフトキーボードの収納性能

ソフトキーボードのquot;Tuck"ボタンがキーボード上または入力ボックス以外のページ領域でトリガーされると、入力ボックスはフォーカスを失い、ソフトキーボードは収納されます。

Androidソフトキーボード寝かせの動作

入力ボックスの外側の領域をトリガーすると、入力ボックスはフォーカスを失い、ソフトキーボードが収納されます。しかし、キーボードのタックボタンをトリガーすると、入力ボックスはフォーカスを失わず、ソフトキーボードがタックされます。

ソフトキーボードのポップアップとリトラクタブルの聞き取り

上記のIOSとAndroidでキーボードのポップアップとタックの動作が異なることを考慮し、以下のようにソフトキーボードのポップアップとタックを別々にリスニングすることができます。

  • IOSでは、入力ボックスのfocusイベントを聞いてソフトキーボードがポップアップしたことを知り、入力ボックスのblurイベントを聞いてソフトキーボードがしまわれたことを知ることができます。
  • Androidでは、Webビューの高さが変化し、高さが小さくなるのを待ち、ソフトキーボードがポップアップされたことを知らせます。
// judge device type
var judgeDeviceType = function () {
  var ua = window.navigator.userAgent.toLocaleLowerCase();
  var isIOS = /iphone|ipad|ipod/.test(ua);
  var isAndroid = /android/.test(ua);

  return {
    isIOS: isIOS,
    isAndroid: isAndroid
  }
}()

// Listen to the soft keyboard pop-up and pop-down events of the input box
function listenKeybord($input) {
  if (judgeDeviceType.isIOS) {
    // IOS keyboard popup: IOS and Android input boxes get focus on keyboard popup
    $input.addEventListener('focus', function () {
      console.log('IOS keyboard is popping up!') ;
      // IOS keyboard pops up and then operates
    }, false)

    // IOS keyboard is tucked away: If IOS clicks outside the input box or clicks the tuck button, the input box will lose focus and the keyboard will be tucked away.
    $input.addEventListener('blur', () => {
      console.log('IOS keyboard is stowed!') ;
      // IOS keyboard is put away and operated
    })
  }

  // Andriod keyboard put away: Andriod keyboard popped up or put away the page height will change, as a basis to know the keyboard put away
  if (judgeDeviceType.isAndroid) {
    var originHeight = document.documentElement.clientHeight || document.body.clientHeight;

    window.addEventListener('resize', function () {
      var resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
      if (originHeight < resizeHeight) {
        console.log('Android keyboard put away!') ;
        // Android keyboard is put away and operated
      } else {
        console.log('Android keyboard popped up!') ;
        // Android keyboard pops up and then operates
      }

      originHeight = resizeHeight;
    }, false)
  }
}

var $inputs = document.querySelectorAll('.input');

for (var i = 0; i < $inputs.length; i++) {
  listenKeybord($inputs[i]);
}



ソフトキーボードをポップアップして、入力ボックスを常に可視領域までスクロールさせるようにする

入力項目が多い入力フォームを作って、入力ボックスにフォーカスが当たってソフトキーボードがポップアップすることがあります。入力ボックスがページの下部にある場合、IOSでは、フォーカスを得た入力ボックスが自動的に可視エリアに入るように、ウェブビューをある程度上にスクロールしますが、Androidではそうではなく、ページの高さを変更するだけで、現在のフォーカス要素を可視エリアまでスクロールさせることはしません。

上記はすでにIOSとAndroidのキーボードがポップアップするのをリッスンしているので、ここではAndroidのキーボードがポップアップした後、フォーカス要素を表示可能領域までスクロール(scrollIntoView())させるだけにしています。その効果を確認するために、以下のように ここで .

// Get the focus element to scroll to the viewable area
function activeElementScrollIntoView(activeElement, delay) {
  var editable = activeElement.getAttribute('contenteditable')

  // The input box, textarea or rich text does not scroll the element to the viewable area after getting focus
  if (activeElement.tagName == 'INPUT' || activeElement.tagName == 'TEXTAREA' || editable === '' || editable) {
    setTimeout(function () {
      activeElement.scrollIntoView();
    }, delay)
  }
}

// ...
// Android keyboard operation after popup
activeElementScrollIntoView($input, 1000);
// ...



数字のみのソフトキーボードを呼び出す

上のフォーム入力ボックスには電話番号の入力要求がありますが、こんな感じで数字のソフトキーボードが出てくるので、ソフトキーボード対応ということで、ここに設置しましょう。よりよい解決策は以下の通りです。

<p>Please enter a cell phone number</p>
<input type="tel" novalidate="novalidate" pattern="[0-9]*" class="input">


  • type="tel" は、入力ボックスのタイプが電話番号であることを示す HTML5 属性で、Android と IOS で同様の動作をし、テンキーを使用しますが、若干冗長になりますが、文字も使用することができます。
  • pattern="[0-9]", patternはフォーム入力の検証に使用されます。通常HTML5タイプの属性、例えばemail, tel, number, data class, urlなどはすでに簡単なデータ形式の検証機能が付いていますが、patternを追加した後は、フロントエンド部分の検証がよりシンプルで効率的になります。IOSの場合、9パターンのテンキーを呼び出せるのは[0-9] \* のみで、 \d は効果がありません。Android 4.4 以下(X5 カーネル含む)では、どちらもテンキーを呼び出すことができます。
  • novalidate="novalidate", novalidate属性は、フォーム送信時にバリデーションを行わないことを指定します。パターンバリデーションには対応していないので、チェックを外したまま、jsによるバリデーションで、素のテンキーを起動させることも可能です。

IOS12 + V6.7.4+に対応

IOS12とV6.7.4+のWeChatブラウザで上記のフォーム入力デモを開くと、キーボードがしまわれた時、スクロールアップされたページが下の位置に戻らず、元のキーボードポップアップが" empty"のままであることに驚かされるでしょう。

これは実はIOSのAppleのバグで、Xcode10にパッケージされたIOS12を搭載したすべてのデバイスで表示されます。WeChatは公式に 解決策 ソフトキーボードをしまった後に、ページ(webview)をスクロールしてウィンドウの一番下(clientHeightの位置)まで戻すだけです。上の固定フォーム入力のデモは、次のようにつっこむことができます。 こちら

console.log('IOS keyboard is put away!') ;

// WeChat browser version 6.7.4 + IOS12 will appear after the keyboard is put away, the view is topped up and not down
var wechatInfo = window.navigator.userAgent.match(/MicroMessenger\/([\d\.] +)/i);
if (!wechatInfo) return;

var wechatVersion = wechatInfo[1];
var version = (navigator.appVersion).match(/OS (\d+)_(\d+)_? (\d+)? /);

if (+wechatVersion.replace(/\. /g, '') >= 674 && +version[1] >= 12) {
  window.scrollTo(0, Math.max(document.body.clientHeight, document.documentElement.clientHeight));
}



サードパーティーの入力メソッドに対応

以上、H5チャット入力ボックスの穴の大部分を埋めることができたので、チャット入力ボックスの基本的なHTML構造を見てみましょう。

<div class="chat__content">
  <div>
    <p> Some chat content1</p>
  </div>
  <! -- omitting several thousand lines of chat -- >
</div>
<div class="input__content">
  <div class="input" contenteditable="true"></div>
  <button>send</button>
</div>


スタイル

/* Omit some styles */
.chat__content {
  height: calc(100% - 40px);
  margin-bottom: 40px;
  overflow-y: auto;
  overflow-x: hidden;
}

.input__content {
  display: flex;
  height: 40px;
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  align-items: center;
}
/* Omit some styles */



これは、コンテンツエリアと入力エリアを分割することは非常に簡単です、入力領域は、上記のフォーム入力デモによると、絶対位置決めされて、確かにAndroidブラウザのほとんどは問題ありませんが、IOS、ネイティブ入力方式とサードパーティ製の入力方式(Sogou入力方式など)とUCブラウザ上でテスト、入力ボックスが完全にブロックされ、QQブラウザまたはWeChatブラウザ、第三者とBaiduブラウザで第三者入力方式も完全に入力ボックスにブロックされることになる。効果を確認するには、アクセスするために、対応するブラウザを使用することができます。 ここで .

UCブラウザでは、ソフトキーボードがポップアップすると、ブラウザ上部のタイトルバーの高さが高さ遅延の動的効果を持つため、ウェブビューが少しスクロールし、下部の入力ボックスが非可視領域までスクロールしてしまうのです。

サードパーティ製の入力メソッドについては、入力メソッドパネルがポップアップした後の高さの計算ミスにより、ウェブビューの初期スクロールの位置がおかしくなっているのではないかと推測しています。この2つは、実はウェブビューが正しくスクロールしないことが原因です。ソフトキーボードがポップアップした後、フォーカス要素を再び可視領域までスクロールさせることで、強制的にwebviewを所定の位置にスクロールさせることができます。

console.log('Android keyboard is popping up!') ;
activeElementScrollIntoView($input, 1000);


Android Xiaomiブラウザに対応したハッキングスキーム

上記の解決策をAndroidのXiaomiのブラウザに適用してみると、やはりチャットの入力ボックスが見えなくなり、scrollIntoView()が全く動かなくなることが判明しました。ということは、実は下まで転がっていて、ソフトキーボードがポップアップし、ページの高さが可視領域の高さより大きいので、ソフトキーボードがポップアップしてからページの高さを強制的に上げて、入力ボックスが表示できるようにするしかないのでしょう。サードパーティの入力メソッドと互換性のある上記の包括的な、効果がここで突くことができる参照してください。

// Andriod keyboard tucked away: The Andriod keyboard will change in height when it is popped up or tucked away, and this is the basis for knowing that the keyboard is tucked away
if (judgeDeviceType.isAndroid) {
  var originHeight = document.documentElement.clientHeight || document.body.clientHeight;

  window.addEventListener('resize', function () {
    var resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
    if (originHeight < resizeHeight) {
      console.log('Android keyboard put away!') ;

      // Fix the problem that the input box is still blocked by the input method under Xiaomi browser
      if (judgeDeviceType.isMiuiBrowser) {
        document.body.style.marginBottom = '0px';
      }
    } else {
      console.log('Android keyboard is popping up!') ;

      // Fix the problem that the input box is still blocked by the input method in Xiaomi browser
      if (judgeDeviceType.isMiuiBrowser) {
        document.body.style.marginBottom = '40px';
      }
      activeElementScrollIntoView($input, 1000);
    }

    originHeight = resizeHeight;
  }, false)
}



概要

H5側の前途は長く、穴だらけで、常に実験が必要です。IOSとAndroidにおけるソフトキーボードのポップアップページの動作の違いを理解することが前提で、次に、サードパーティの入力方法の違いや一部のブラウザでの動作を考慮して、フォーカス要素を可視領域までスクロールさせることが必要です。

今回は以上です。皆様の学習のお役に立てれば幸いです。また、Scripting Houseを応援していただければ幸いです。