時間ではなくお金を使う
はじめに
ウェブが好きです。全体として、これは良いアイデアだと思います。そのため、ウェブかネイティブかについてはよく議論されます。相手がネイティブ システムによる決済のしやすさについて話し始めるまで、それほど時間はかかりません。私のいつもの反応は、ばいばん爆弾を投げて部屋から駆け出して、まともな笑いを放つようなものです。なぜなら、勝てる議論ではないからです。モバイルウェブでのショッピング カートの放棄率は、97%に達する場合があります。現実の世界で想像してみてください。スーパーマーケットにいる人々の 97% が、欲しいものでいっぱいのカートを置いて出て行く様子を想像してみてください。 現在、値上げして購入するつもりのなかった人々もいますが、ウェブで購入するという恐ろしいユーザー エクスペリエンスが大きな原因となっています。ユーザーの健全性に負担がかかります。 ウェブ、特にモバイルでの支払い時の快適さについて思い浮かべてください。アプリストアですね。または、すでに支払い情報が登録されている類似のクローズド システム。 これは問題です。ユーザーがすでにアカウントを持ってログインしている特定の決済機関にコミットすることや、特定の決済機関にユーザーがログインする必要があるプラットフォーム(そのプラットフォーム専用のコーディングが必要なアプリストアなど)にサイトがコミットすることが必要です。これらの操作を行わないと、ユーザーは画面やキーボードをタップして、指の皮膚がすべて消えるか、あきらめるまで、タップしてしまうことになります。 これを修正する必要があります。
requestAutocomplete
「Web」で始まる WebGL や WebRTC などの高度なウェブ API の世界では、requestAutocomplete
はむしろ非現実的です。しかし、ベージュの服を着たスーパーヒーローです。小さな、退屈な API であり、ウェブ決済のコア 部分を占拠できます。
サイトは特定の決済機関に依存するのではなく、ブラウザから支払いの詳細をリクエストし、ユーザーに代わって支払いの詳細を保存します。Chrome バージョンの requestAutocomplete() は、米国のユーザーのみ(現在)専用の Google ウォレットとも統合されています。テストサイトでぜひお試しください。
form.requestAutocomplete
フォーム要素には、ブラウザにフォームに入力するよう求める新しいメソッド requestAutocomplete が 1 つあります。ブラウザで、ユーザーに権限を求めるダイアログが表示され、ユーザーはどの詳細情報を提供するかを選択できるようになります。 このメソッドはいつでも呼び出すことはできず、マウスの上下イベント、クリックイベント、キーイベント、タッチイベントなどの特定の操作イベントの実行中に呼び出す必要があります。これは、意図的なセキュリティ制限です。
button.addEventListener('click', function(event) {
form.requestAutocomplete();
event.preventDefault();
});
// TODO: listen for autocomplete events on the form
イベントを確認する前に、ブラウザがフォーム フィールドを認識できるようにする必要があります。
フォームの要件
モノクロのインターネットだった頃、Internet Explorer 5 ではフォームの入力要素に新しい属性 autocomplete
を採用しました。「オフ」に設定すれば、ブラウザによる候補表示を停止できます。この API は拡張されたため、「name」属性を変更せずにフィールドの想定される内容を指定できます。requestAutocomplete
はこの API を使用してフォーム フィールドをユーザーデータにリンクします。
<input name="fullname" autocomplete="name">
仕様上、requestAutocomplete
は支払いに固有のものではありませんが、Chrome の現在の実装はほぼ同じです。将来的には、ブラウザで他の種類のデータ(ログイン情報、パスワード生成ツール、パスポート情報など)を処理したり、アバターをアップロードしたりできるようになる予定です。
現在 Chrome では、requestAutocomplete
は次のものを認識します。
支払い
- メール
- Cc-name - カード名義
- cc-number - カード番号
- cc-exp-month - カードの有効期限の月(2 桁)
- cc-exp-year - カードの有効期限の年(4 桁)
- cc-csc - 3 ~ 4 桁のカード セキュリティ コード
<input type="email" autocomplete="email" name="email">
<input type="text" autocomplete="cc-name" name="card-name">
<input type="text" autocomplete="cc-number" name="card-num">
<input type="text" autocomplete="cc-exp-month" name="card-exp-month">
<input type="text" autocomplete="cc-exp-year" name="card-exp-year">
<input type="text" autocomplete="cc-csc" name="card-csc">
上記で使用した「name」属性はあくまで例であり、特定の値を使用する必要はありません。requestAutocomplete
のないユーザーにこのフォームを再利用する場合は(理想的です)、ラベル、レイアウト、基本的な HTML5 検証を追加します。
入力要素にも制限されず、任意のフォーム入力タイプを使用できます。たとえば、カードの有効期限フィールドに <select>
を使用できます。
住所
name - 氏名。複数のフィールドよりもフルネームを単一のフィールドとして扱う方がはるかに効率的です。姓や名などの複数の項目は西洋の偏見を示し、他の文化には通用しない可能性があります。また、1 つの項目に入力する方が簡単です。
tel - 国コードを含む完全な電話番号。または、次のように分割することもできます。
- tel-country-code - 例: +44
- Tel-national - その他
street-address - 各コンポーネントをカンマで区切った完全な住所。次のように分割可能
- address-line1
- address-line2 - 空でもかまいません
locality - 市区町村
region - 州コード、郡、州
postal-code - 郵便番号、郵便番号
country
上記は以下と組み合わせて使用する必要があります。 - 請求 - 送料
<input type="text" autocomplete="billing name" required name="billing-name">
<input type="tel" autocomplete="billing tel" required name="billling-tel">
<input type="text" autocomplete="billing address-line1" required name="billing-address1">
<input type="text" autocomplete="billing address-line2" required name="billing-address2">
<input type="text" autocomplete="billing locality" required name="billing-locality">
<input type="text" autocomplete="billing region" required name="billing-region">
<input type="text" autocomplete="billing postal-code" required name="billing-postal-code">
<select autocomplete="billing country" required name="billing-country">
<option value="US">United States</option>
…
</select>
<input type="text" autocomplete="shipping name" name="shipping-name">
…
name 属性は例であり、自由に使用できます。すべてのフォームで配送先住所をリクエストする必要はありません。たとえば、ホテルの部屋をどこに届けたいか尋ねてはいけません。多くの場合、現在地がセールス ポイントになります。
そうですね、フォームを用意しました。autocompletion
をリクエストする方法はすでに確認できました。ただし...
requestAutocomplete を呼び出すタイミング
購入手続きフォームを表示するページを読み込む代わりに、requestAutocomplete
ダイアログを表示するのが理想的です。問題がなければ、フォームはまったく表示されません。
一般的なパターンとして、カートページに「購入手続き」ボタンを配置して、支払いの詳細フォームに移動できるようにします。この状況では、カートページに請求フォームを読み込み、ユーザーには表示しないようにして、ユーザーが [購入手続き] ボタンを押したときに requestAutocomplete
を呼び出すようにします。Skeletor の警告が表示されないようにするには、カートページは SSL 経由で提供する必要があります。
まず、準備ができるまでユーザーがクリックできないように購入手続きボタンを非表示にします。ただし、これは JavaScript を使用するユーザーに対してのみ行いたいと考えています。したがって、ページの head 内:
<script>document.documentElement.className += ' js';</script>
CSS で次のようにします。
.js #checkout-button,
#checkout-form.for-autocomplete {
display: none;
}
カートページに請求フォームを含める必要があります。これはどこにでも配置できます。上記の CSS により、ユーザーには表示されません。
<form id="checkout-form" class="for-autocomplete" action="/checkout" method="post">
…fields for payment, billing address & shipping if relevant…
</form>
これで、JavaScript ですべての設定を開始できます。
function enhanceForm() {
var button = document.getElementById('checkout-button');
var form = document.getElementById('checkout-form');
// show the checkout button
button.style.display = 'block';
// exit early if there's no requestAutocomplete support
if (!form.requestAutocomplete) {
// be sure to show the checkout button so users can
// access the basic payment form!
return;
}
button.addEventListener('click', function(event) {
form.requestAutocomplete();
event.preventDefault();
});
// TODO: listen for autocomplete events on the form
}
カートページの enhanceForm
は、購入手続きのフォームとボタンの後などに呼び出します。requestAutocomplete
に対応しているブラウザでは、さらに高速になった新しいエクスペリエンスをご利用いただけます。その他のブラウザでは、通常のお支払い方法にフォールバックします。ボーナス ポイントを獲得するには、enhanceForm
の一部として XHR を介してフォームの HTML を読み込むことをおすすめします。つまり、requestAutocomplete
をサポートしているブラウザでのみフォームを読み込めます。enhanceForm
を呼び出す各ページにフォームを追加する必要もありません。以下は、デモサイトの仕組みです。
requestAutocomplete 呼び出しの次のステップ
オートコンプリート プロセスは非同期で、requestAutocomplete
はすぐに返されます。それがうまくいったかを知るために、いくつかの新しいイベントをリッスンします。
form.addEventListener('autocomplete', function() {
// hurrah! You got all the data you needed
});
form.addEventListener('autocompleteerror', function(event) {
if (event.reason == 'invalid') {
// the form was populated, but it failed html5 validation
// eg, the data didn't match one of your pattern attributes
}
else if (event.reason == 'cancel') {
// the user aborted the process
}
else if (event.reason == 'disabled') {
// the browser supports requestAutocomplete, but it's not
// available at this time. Eg, it wasn't called from an
// interaction event or the page is insecure
}
});
問題がなければ、データに対して好きなことを行うことができます。最も簡単なのは、フォームを送信することです。サーバーはデータを検証し、送料を含む確認ページをユーザーに表示します。 データが無効な場合は、フォームを表示し、ユーザーが修正する必要があるフィールドをハイライト表示できます。または、フォームを送信して、通常のサーバーサイド検証に引き継ぐこともできます。 ユーザーがプロセスをキャンセルした場合は、何もする必要はありません。この機能が無効になっている場合は、ユーザーを通常のフォームに誘導します。 ほとんどの場合、リスナーの外観は次のようになります。
form.addEventListener('autocomplete', function() {
form.submit();
});
form.addEventListener('autocompleteerror', function(event) {
if (event.reason == 'invalid') {
form.submit();
}
else if (event.reason != 'cancel') {
window.location = '/checkout-page/';
}
});
ブラウザはどこにデータを保存していますか?
この仕様ではデータの保存場所を指定していないため、ブラウザのイノベーションが可能になります。Chrome にログインしている場合は、Google ウォレットに詳細を保存するオプションが表示され、ログインしている他のデバイスからアクセスできます。ウォレットに詳細を保存すると、requestAutocomplete
によって実際のカード番号が流出されることがないため、セキュリティは強化されます。
Chrome にログインしていない場合や、Google ウォレットを使用しないように選択した場合、お客様の情報は必要に応じてブラウザにローカルに保存され、再利用されます。
現時点ではこれが現状ですが、将来的に Chrome や他のブラウザで追加の決済機関が導入される可能性があります。
お支払いを簡単に
ユーザーが購入するたびにお支払い情報を何度も入力しなければならないなんて、不思議です。支払いの情報が保存されているサイトがあると処理が楽になりますが、私のカード情報をどれだけのサイトが保存しているのかちょっと不安です。これは、ウェブ標準の解決に最適な問題です。requestAutocomplete
では、サービスやプラットフォームにロックインされることなく、ウェブ全体でワンクリック決済を行うことができます。
参考: 複数ページにわたるフォームの処理
requestAutocomplete
を 1 回呼び出して、必要なデータをすべて収集することをおすすめします。すべてのデータを一度に受信するようにサーバーを変更できなくても問題ありません。入力済みのフォームからデータを取り出して、最適な方法で送信してください。
この小さな関数を使用すると、自分でフォームを作成しなくても、現在サポートされているすべてのデータを単純なオブジェクトとしてキャプチャできます。データを取得したら、サーバーに必要な形式に変換し、複数のステップで投稿できます。
checkoutButton.addEventListener('click', function() {
requestUserData({
billing: true,
shipping: true
}, function(response) {
if (response.err == 'cancel') {
// exit silently
return;
}
if (response.err) {
// fall back to normal form
window.location.href = '/normal-checkout-form/';
return;
}
// the rest is just made-up pseudo code as an example
postToServer(data.shipping).then(function() {
return postToServer(data.billing);
}).then(function() {
return postToServer(data.cc);
}).catch(function() {
// handle error
});
});
});