Microsoft Edge最新情報
Windows 10 Creators UpdateのJavaScript/CSS関連の新機能
Windows 10 Creators UpdateでEdgeはどのように進化したのか? CSS/JavaScriptに関する新機能や新搭載のAPIを、開発者目線で紹介する。
2017年4月にWindows 10の三度目の大幅アップデートであるCreators Update(1703:ビルド番号15063)が提供された。数カ月たっているので、すでに多くの読者のWindows 10にはアップデートが適用されているはずである。
前回のAnniversary Update(1607:ビルド番号14393)からの変更点は、Changelogのページ(英語)で確認できる。そのページの冒頭にある「New Microsoft Edge features(新しいMicrosoft Edgeの機能)」は、Microsoft Edge(以下Edge)のUIや機能に関する変更点だが本稿では省略するので、マイクロソフトの物江さんが解説している記事を参考にしてほしい。
ページの中盤にある「New web platform features(新しいWebプラットフォーム機能)」に記載されているのが、CSSやHTML(JavaScriptや新搭載のAPI)に関する新機能である。本稿ではこの内容を掘り下げて紹介する。本稿のサンプルコードはこちら(GitHub - yoshioms/edge15samples)で参照・ダウンロードできる。
CSSに関する新機能
EdgeでサポートされるようになったCSSの新機能についてコードを見ていこう。
CSSカスタムプロパティ
CSSは開発者から見ると不便な言語だ。依存関係が分かりにくいし、階層や適用範囲も設計者に委ねられている。そんな数多くある不満の一つである「変数が使えない」という問題が解消する。
これまではCSSで変数が使えないために同じ記述を何カ所かでする必要があり、デザイン変更時に苦労することがあった。CSSカスタムプロパティがサポートされたことで、変更する可能性がある値を変数にして容易に変更することが可能になった。この機能は、以前はCSS変数(CSS Variables)と呼ばれていたが、最終的にはCSSカスタムプロパティ(CSS Custom Properties)という名称になった。
これにより、CSSの値を変数化して一括管理できるようになった。変数は、SCSSやSASSなどのプリプロセッサー言語でも使えていたが、CSSカスタムプロパティは事前にコンパイルすることなく、ブラウザーが直接解釈するため、レスポンシブで値が変わる場合にも対応できるし、JavaScriptで変数の値を変更することもできる。
CSSカスタムプロパティの記述方法を見ていこう。まずは変数宣言を行う。
:root {
--full-width: 300px;
--accent-color: lightgreen;
--text-padding: 10px 15px 20px 10px;
}
|
変数の宣言は--
をプレフィックスとして記述する。リスト1では--accent-color
などの変数が宣言されている。
さらに、その変数の値を上書きすることもできる。
div {
--accent-color: yellow;
}
span {
display: block;
/* --accent-colorプロパティの指定なし */
}
|
リスト2では、<div>
タグだけ--accent-color
変数の値を上書きしている。
リスト1とリスト2で宣言した変数を使ってみよう(リスト3)。
.box-full {
width: var(--full-width);
padding: var(--text-padding);
background-color: var(--accent-color);
}
|
変数の展開にはvar
関数を使う。リスト2に示したとおり、--text-padding
のように複合値も展開できる。
background-color
プロパティに設定されている--accent-color
変数は<div>
タグだけ上書きしたため、<div>
タグかそれ以外かで違う値が指定されることになる。
値だけではなくcalc
関数を使って計算も可能だ。リスト4は、--full-width
変数と数値によるさまざまな計算の結果値を、calc
関数を使ってプロパティに指定している例である。
.box {
position: absolute;
}
.box1 {
width: calc(var(--full-width) / 3);
left: calc(var(--full-width) / 3 * 1);
background-color: pink;
}
.box2 {
width: calc(var(--full-width) / 3);
left: calc(var(--full-width) / 3 * 2);
background-color: green;
}
|
以上のCSSコードを以下のHTMLソースに適用してみよう(リスト5)。
<div class="box-full">Full</div>
<span class="box-full">Full Span</span>
<div id="boxes">
<div class="box box1">box1</div>
<div class="box box2">box2</div>
</div>
|
box-full
クラスを指定した<div>
タグと<span>
タグがある。また、box1
クラスとbox2
クラスはcalc
関数で計算された幅と位置が指定されている。
表示した結果を見てみよう(図1)。
box-full
クラスを適用した<div>
要素は上書きされた「yellow」により黄色が適用されているが、<span>
はroot
で定義された「lightgreen」が適用されている。box1
とbox2
のwidth
とleft
は、calc
関数の計算結果が適用されている。
変数の値は、JavaScriptで変更もできる。例えばリスト7では、JavaScriptで--accent-color
変数の値を「red」に変更している。
document.documentElement.style.setProperty('--accent-color', 'red');
|
この結果を表示してみよう。
図2ではroot
の色を変更しているため、全体の--accent-color
変数に影響する。しかし<div>
タグの--accent-color
変数は前述のとおり上書きされるので、<span>
タグのみが変更されている。
なお、EdgeのTest DriveにCSSカスタムプロパティのデモ(図3)が提供されているので併せて確認してみてほしい。
CSS outline-offset
outlineはborder
とほぼ同じ機能だが、border
は枠の広さでスペースが取られるが、outline
はレイアウトを変えることなく線を引けるという違いがある。
例えば、Windowsエクスプローラーのツリービューを、Webページ上で作るのを想像してみてほしい。選択された階層が枠で囲まれるが、border
を使ってしまうと、枠の分のスペースが必要になるため、レイアウトの変更が発生する。一方、outline
を使うとレイアウトが変更されることなく線が引けるので、レイアウト崩れがない。outline
はこういった利用目的に向いている。
outline
自体はIE11からサポートされているが、今回は線を引く位置をオフセットで指定できるoutline-offset
が新たにサポートされた。まずはサンプルのCSSコードを見ていこう。
body {
font-size: 24px;
}
.large {
font-size: 30px;
}
.outline {
outline: dotted 2px green;
outline-offset: -7px;
}
.border {
border: 1px solid pink;
}
.border-and-outline {
outline: dotted 2px green;
outline-offset: 5px;
border: 1px solid pink;
}
|
outline
とborder
の両方を指定したborder-and-outline
クラスでは、outline-offset
で5pxを指定した。outline
だけを指定したoutline
クラスでは、レイアウトに影響しないことを確認するために-7pxを指定した。また、比較のためにborder
だけを指定したborder
クラスも定義している。
これらのクラスを指定したHTMLソースを見ていこう。
<span class="border-and-outline">borderとou<span class="large">tli</span>ne</span>を
<span class="border">つかって</span>
<span class="outline">outline</span>で装飾します。
|
border-and-outline
クラスを指定した<span>
タグの中にlarge
クラスを指定してフォントサイズを大きくした文字列を指定した。また、比較のためにborder
クラスを指定した<span>
タグとoutline
クラスを指定した<span>
タグを記述した。
リスト8のCSSコードを読み込んだHTMLソースのページ表示結果を表示してみる(図4)。
border
は枠線の幅でレイアウトがずれるが、outline
はレイアウトに影響を与えずに枠を表示できる。
このようにoutline
では、レイアウトに影響を与えることなく枠線を表示でき、outline-offset
を使うと、境界領域からのオフセット値を指定して線を描画できる。オフセット値としてマイナス値も指定できる。
ただしEdgeにおける現在の実装では、文字の周りを囲って枠を作っているようで、図4を見て気付いたと思うが、アルファベットとひらがなのように高さの違う文字が混ざると枠がガタガタになってしまうという問題がある。ChromeやFirefoxでは、きれいな矩形になっているので、同じような表示になるように修正されることを期待したい。
JavaScriptに関する新機能
JavaScriptコードから呼び出せるAPIにもいくつかの機能が追加されている。
Element.closest
Element.closest
メソッドを使うと、ある要素の上位にある要素を取得できる。具体的なサンプルで説明しよう。
<article id="article1">
<div id="div-1"></div>
</article>
<article id="article2">
<div id="div-2"></div>
</article>
|
リスト10では、<article>
の下位階層にdiv-1とdiv-2のid
が指定された<div>
タグが定義されている。
このHTMLソースに対して、以下のJavaScriptコードを実行してみる。
// article1が取得される
var div_1 = document.getElementById('div-1');
var article1 = div_1.closest("article");
console.log(article1);
// article2が取得される
var div_2 = document.getElementById('div-2');
var article2 = div_2.closest("article");
console.log(article2);
|
リスト11では、どちらもarticleを取得しているが、それぞれ取得元の要素の上位にある<article>
要素が取得される。結果の内容表示は割愛するので試してみてほしい(※結果はF12開発者ツールの[コンソール]タブで確認する)。
なお、ここではarticle
という要素名を指定したが、セレクター記述で.クラス名
/#ID
/要素名 > 要素名
などの指定も可能だ。
Navigator.hardwareConcurrency
新しく追加されたhardwareConcurrency
読み取り専用プロパティでは、ブラウザーが実行されているPCのコア数を取得できる。
JavaScriptは、Web Workerなどマルチスレッドで処理できるようになっているが、スレッド数が多ければ多いほど動作が速くなるかというと、そういうわけではなくコンテキストスイッチが発生して、逆に遅くなることもある。そのような課題がある場合には、hardwareConcurrency
プロパティを活用して、PCごとに適切な数のスレッドを起動して処理するとよい。
Intersection Observer
ここ数年、Webページのパフォーマンスは以前にもまして強く求められるようになった。画像の遅延読み込みやJavaScriptコードの遅延読み込みは実現できるようになったが、HTMLレンダリング部分については最適な手段が提供されていなかった。新しく搭載されたIntersection Observerは要素を指定して、表示されている領域を取得できるので、表示領域に応じてコンテンツの遅延読み込みを実装できる。
Intersection Observerという名前はいまひとつ分かりにくいが、要素が交差(Intersection)するのを監視(Observe)するAPIだ。対象として指定した要素が、指定した要素と、指定した割合で交差したときに、コールバック処理を実行できる。具体例を示そう(リスト13/14/15/16)。
<div id="box"></div>
|
#box {
background-color: skyblue;
top: 500px;
height: 500px;
width: 500px;
position: relative;
}
|
var options = {
threshold: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
}
|
let observer = new IntersectionObserver((entries) => {
for (let entry of entries) {
var time = entry.time;
var intersectionRatio = entry.intersectionRatio;
var rootBounds = entry.rootBounds;
var boundingClientRect = entry.boundingClientRect;
var intersectionRect = entry.intersectionRect;
}
}, options);
var target = document.getElementById("box");
observer.observe(target);
|
上記のコードは説明を簡単にするため表示部分を省略しているので、完全なコードはCodePenのサンプルを参照してほしい。
このコードの実行結果を見ていこう(図5)。
intersectionRatio
は、およそ60%である0.6044が返されている。
rootBounds
は、root
を指定していないためdocument
になり、ウィンドウサイズと一緒になる。
boundingClientRect
は、対象として指定したid=box
だ。背景が青の要素でスクロールするごとにtop
とbottom
の位置が変わることが分かる。
intersectionRect
は、bindingClientRect
の中で表示されている領域である。
box
の上部を500pxにしているため、スクロールしないと<div id="box">
要素が表示できない。そのため、ページをスクロールして表示すると、表示割合に応じてIntersection Observerからコールバック関数が呼び出される。
リスト16のコールバック関数の中身を見ると、いくつかのプロパティが返されているのが分かると思う。time
プロパティはイベント発生時のタイムスタンプなので省略するが、それ以外のプロパティは図で説明しよう。
rootBounds
は、交差のルートになる矩形(Rect
)。
boundingClientRect
は、監視対象の要素の矩形(Rect
)。
intersectionRect
は、交差した矩形(Rect
)。
intersectionRatio
は、intersectionRectの交差している比率(小数値)。
このように、指定した要素の表示イベントがコールバックで返されるため、実際にブラウザーで表示が必要になった時に動的に読み込むことが可能になる。
Async関数
非同期処理を、async
(await
)を使って容易に記述できる言語が増えているが、JavaScriptでも使えるようになった(リスト17)。
async function asyncFunc(url) {
console.log("asyncFunc Start");
console.log("First Start");
await wait2Sec();
console.log("First End");
console.log("Second Start");
await wait2Sec();
console.log("Second End");
console.log("asyncFunc End");
}
function wait2Sec() {
return new Promise(resolve => setTimeout(() => resolve(), 2000));
}
asyncFunc();
console.log("asyncFunc Called");
|
await
が書かれた処理の完了を待たずに呼び出し元に処理が返されるが、関数内の処理は継続される。
このコードの実行結果を見てみよう(リスト18)。
asyncFunc Start
First Start
asyncFunc Called
First End
Second Start
Second End
asyncFunc End
|
リスト18を見ると、asyncFunc
関数が呼び出されて、await
が記述されているwait2Sec
関数が呼び出された後、処理の終了を待たずに関数を抜けて「asyncFunc Called」が出力されている。その後もasync
関数内の処理は継続していて、「First End」「Second Start」と続いている。
新しく追加されたWeb API
WebRTC
マイクロソフトは、これまでWebRTCには乗り気ではなく、より良い実装としてORTC(Object RTC)を推進してきた。だが実際にはWebRTCがすでに多くのブラウザーに実装され、Webチャットなどで使われていたため、ORTCに移行させるのは難しかったようだ。
Edgeがサポートしたことで、サポートされていない残りのメジャーなモダンブラウザーはSafariとIEだけだが、Safariは次期バージョンの11でサポートされる予定なので、もうすぐ全てのブラウザーで利用可能になる。
WebVR
WebVRは、WebGL上に実装されたVRの仕様だが、現時点では安定した仕様ではない。マイクロソフトはWindowsでVRおよびMR(Mixed Reality)の実装を進めているため、Edgeでもサポートされたのだろう。
執筆時点(2017年7月)ではEdgeとAndroid版のChromeのみが対応している。ネイティブアプリと比較すると、URLを開くだけで気軽にVR体験ができるのが魅力だ。BabylonJSのようなWebGLライブラリでアプリを開発できる。
A-FrameやSketchfabにデモが公開されているので、体験してみてほしい。
Payment Request API
商品購入時のフォームは、クレジットカード番号や住所など、入力する内容がほとんど同じにもかかわらず、これまでサイトごとに開発が必要だった。Payment Request APIが実装されると購入フォームはブラウザーによって提供され、クレジットカードや住所の入力は不要になる。執筆時点(2017年7月)では、EdgeとAndroid版のChrome、デスクトップ版のChromeベータ(バージョン60)でしかサポートされていないため、このAPIに頼らず、従来のフォームを開発する必要がある。
さっそくコードを見ていこう(リスト19/20/21/22/23/24)。
<button onclick="buy()">購入</button>
|
function buy(){
// Payment Request APIをサポートしているかどうかを判定
if (!window.PaymentRequest) {
// 従来のフォームにリダイレクト
location.href='payment.html';
return;
}
// リスト21~24のJavaScriptコードはここに記述する
}
|
payment.htmlファイルはPayment Request APIとは関係がないので説明を割愛。
// 支払い方法を定義
var methodData = [{
supportedMethods: ['basic-card'],
data: {
supportedNetworks: ['visa', 'mastercard', 'jcb'],
supportedTypes: ['credit']
}
}];
|
ここでは、クレジットカードでVISA、MasterCard、JCBを指定している。
// 購入の詳細
var details = {
displayItems: [
{
label: "マンガ",
amount: { currency: "JPY", value : "400" }
},
{
label: "雑誌",
amount: { currency: "JPY", value : "300" }
},
{
label: "消費税",
amount: { currency: "JPY", value : "56" }
}],
total: {
label: "合計",
amount: { currency: "JPY", value : "756" }
}
};
|
支払い通貨(currency
)に日本円(JPY)を指定して、明細に表示する商品と消費税の名称(label
)や金額(value
)を指定。さらにtotal
に税込みの支払額を指定している。もちろん実際はサーバーからJSONデータを返して使用することも可能だ。
// 支払い情報の他に必要な項目を指定
var options = {
requestShipping: true, // 住所
requestPayername: true, // 名前
requestPayerEmail: true, // Email
requestPayerPhone: true // 電話番号
};
|
// 支払いフォームを表示する
var payment = new PaymentRequest(methodData, details, options);
payment.show()
// 支払いフォームの結果をPromiseで受けて、サーバーの処理を呼び出す
.then(result => {
return process(result).then(response => {
if (response.status === 200) {
// 支払い成功のUIを表示する
return result.complete('成功');
} else {
// 支払い失敗のUIを表示する
return result.complete('失敗');
}
}).catch((err) => {
console.error('要求が拒否されました', err.message)
});
});
|
show
メソッドで表示して、入力が完了すると、Promiseの処理が呼び出される。ここでは省略しているが、process
関数でサーバーに支払い情報を送信して、HTTPステータスとして200(成功)が返されたら、成功のUIが表示される。
このコードを実行すると、Microsoftアカウントのログインダイアログが表示される(図8)。Edgeでは、Microsoft Walletと呼ばれる支払いサービスを利用して支払いができるようになるようだが、現時点ではアメリカのみで利用可能なため、住所や電話番号は、USのものしか受け付けてくれないようだ。
ちなみにChromeベータ(バージョン60)では、Googleアカウントに関連付けられている住所やクレジットカードが表示された(図8)。
このように、これまでサイトごとに作成していた支払いフォームを共通化して、Microsoft Walletのような信頼できるサービスで管理することで、入力を簡略化して商品を購入してくれるユーザーの離脱を減らせるだろう。
Content Security Policy Level 2
クロスサイトの脆弱性を突いた攻撃は、昔から続く典型的な手法だが、利便性とセキュリティの適切な落としどころが見つかっていない領域の一つであろう。Content Security Policy(以下CSP)は、開発者がホワイトリストを指定することにより、悪意のある第三者に想定外のデータが送られるのを回避する技術だ。
例えば以下のHTMLソース内には、3種類のJavaScriptコードが書かれている。
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="local.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
</head>
<body>
<script>
function inline(){
alert('inline');
}
</script>
CSP2.0
</body>
</html>
|
同一オリジンから読み込まれるlocal.js、外部サイトから読み込まれるjQueryファイル、そしてインラインに書かれたJavaScriptコードという3種類のJavaScriptコードがある。
このコードはこのままでも問題なく動作するが、HTTPヘッダーに「Content-Security-Policy」を指定すると、指定したサイトからのみダウンロード可能になる。HTTPヘッダーは、IISでは図9のように設定する。
スクリプトのソースとして利用可能なものをscript-srcに指定する。
ここでは、「Content-Security-Policy」ヘッダーに「script-src 'self' https://code.jquery.com/ 'unsafe-inline'」を指定している。これは、コンテンツのオリジンと同じ場所('self')、ダウンロード可能なURL(https://code.jquery.com)、インライン('unsafe-inline')を指定している。
試しに「script-src 'self'」だけにしてみるとコンソールにエラーログが表示されて(図10)、ファイルがダウンロードされず、インラインコードが実行されない。
同一オリジン('self')のJavaScriptコードのみが利用可能で、外部サイトとインラインのJavaScriptコードはブロックされている。
ホワイトリストに含まれていないJavaScriptコードはブロックされることになる。これにより、想定外のサイトからJavaScriptファイルが読み込まれて実行されないように設定できる。
ここでは、JavaScriptコードの読み込み元である「script-src」を説明したが、画像の読み込み元(img-src)やフォームの送信先(form-action)など詳細に指定可能なため、ページをより安全にするために指定することを検討してほしい。
まとめ
Edgeは比較的保守的に機能を追加しているため、Edgeへの搭載が待ち望まれていた機能も少なくなかっただろう。今回のアップデートで機能が追加されたおかげで、ほとんどのモダンブラウザーで使用可能になった機能も多い。また、WebRTCやPayment Request APIなど、そして一部で大きな期待を持って待たれているWebAssemblyの一部が実験的に実装されている。さらに、Web技術の中で最も期待されているサービスワーカーは、まだフラグ(about:flags
)で指定する必要がある。
すでにWindows Insider ProgramのPreviewリリースでは次期アップデートに向けて機能追加が進められている。次期Edgeのアップデートをいち早く知りたい場合は、Changelogを監視・確認してほしい。
1. Microsoft Edgeの進化 ~Windows標準ブラウザーの最新機能と使い方
Windows 10 Anniversary Updateで、ようやく日常使用に耐えられる機能性と安定性が備わってきたEdge。その最新機能をパワーユーザー向けに概説する。
2. Microsoft Edge: HTML5/JavaScript最新標準仕様への新応とF12開発者ツールの新機能
Windows 10 Anniversary Updateでアップデートされた最新Edgeの「JavaScript標準仕様への対応状況/オープンソース化/追加されたHTML5標準/F12開発ツールの新機能」をWeb開発者向けに概説する。