クイック スタート: アプリ レイアウトの定義 (HTML)
この記事は、Windows ランタイム アプリを作成する Windows 8.x および Windows Phone 8.x 開発者を対象としています。Windows 10 向けの開発を行っている場合は、 「最新のドキュメント」をご覧ください]
アプリのレイアウトを定義して、ウィンドウのサイズや方向を自由に調整することができます。
この機能の実際の使い方については「アプリの機能の概要」シリーズの次のトピックをご覧ください: Windows ストア アプリ UI の概要
目標: この記事を読むと、HTML、カスケード スタイル シート (CSS)、JavaScript を使って、適切に表示され正しく機能する滑らかな UI を作る方法について詳しく理解できるようになります。
必要条件
アプリの設計を検討する。
Windows ランタイム アプリの計画と設計については、「視覚の定義」をご覧ください。
Windows 8.1 の "サイズ変更できるウィンドウ" について十分理解する。
ビュー状態について詳しくは、「レイアウトとスケーリングの UX ガイドライン」をご覧ください。
CSS メディア クエリを理解する。
メディア クエリは、World Wide Web コンソーシアム (W3C) の メディア クエリの仕様に関するページで定義されています。実際のメディア クエリについては、CSS メディア クエリのサンプルをご覧ください。
カスケード スタイル シート レベル 3 (CSS3) の高度なレイアウト機能、特に CSS3 グリッド配置の使い方を覚える。
CSS3 の高度なレイアウト機能とグリッド配置については、「CSS」をご覧ください。
CSS サンプルを使ったアダプティブ レイアウト
この記事では、CSS サンプルを使ったアダプティブ レイアウトでレイアウトがどのように実装されるかを説明することで、アプリ レイアウトの定義に関する基本概念を説明します。このサンプルは、本日の天気と 10 日間の予報を表示するシミュレートされた天気アプリです。ここでは、CSS と HTML、CSS グリッド、ListView コントロール、CSS メディア クエリを使って柔軟なアプリ レイアウトを作る方法を説明します。
詳しい説明の前に、CSS サンプルを使ったアダプティブ レイアウトの構造を見てみましょう。このアプリは 3 ページの HTML ページで構成されます。最初のページは、アプリの UI 項目のメイン サーフェスを定義する App.html というトップ レベルのページです。このページには、戻るボタン、タイトルとサブタイトル、アプリ メニュー、アプリ バー ボタン、コンテンツを表示する領域 (次の画像の白い領域) が含まれます。
他の 2 つの HTML ページ、Current.html と TenDay.html は、メイン ページのコンテンツ領域に表示されるコンテンツの構造を定義します。Current.html ページは、本日の天気の詳細を表示します。
TenDay.html ページは、10 日間の予報の詳細を表示します。
アプリのメイン ページのレイアウトと 10 日間の予報のレイアウトを定義する CSS サンプルを使ったアダプティブ レイアウトの部分について詳しく見ていきます。
以下は、解像度 1366 x 768 の 10.6 インチ ディスプレイに 10 日間の予報を、縦方向の全画面表示、横方向の全画面表示、他のアプリと一緒に左右に並べた状態 (幅狭と幅広のレイアウトに合わせてサイズを調整) で表示した場合のアプリのメイン ページの見え方を示しています。
アプリが使用可能な画面領域に表示されることを確認する
適切に設計されたアプリは、UI サーフェスが使用可能な画面領域すべてを占めます。これは、アプリが対応する必要のあるデバイスのさまざまなフォーム ファクター、解像度、方向を考えると最初は難しい課題に見えることもあります。これは、CSS を使えば簡単にできます。
アプリが使用可能なすべての画面領域に表示されるようにするには、以下のようにします。
ページの他のすべての UI 要素の最上位レベル コンテナーとして div 要素を使います。
<body> <div class="win-ui-dark appGrid"> <!-- TODO: Define page structure here. --> </div> </body>
CSS プロパティの vw と vh を使って、div の width と height プロパティをビューポートを基準として設定します。たとえば、以下に示すように、
100vw
(ビューポートの幅) と100vh
(ビューポートの高さ) を使うと、ビューポートと同じ大きさになります。.appGrid { width: 100vw; height: 100vh; /* TODO: Add other styles here. */ }
vw と vh は、階層内のどの深さの要素にも指定できます。ビューポートのサイズのコンテキストは変わらないため、継承されたサイズについて対処する必要がありません。
注 サンプルでは、width と height プロパティを 100% に設定しています。
メイン ページの基本レイアウトを定義する
アプリの UI をレイアウトする際は、横向きから始めることをお勧めします。横向きのレイアウトを定義すると、それを他のレイアウト (縦方向、幅広、幅狭) に簡単に適応できます。
HTML を使ってページの UI 項目を定義する
アプリの UI には通常、ナビゲーション ボタン、見出し、メニュー、コントロールなどの項目が含まれます。これらの UI 項目をページの最上位の div 要素の子 HTML 要素として追加します。
次の HTML は、CSS サンプルを使ったアダプティブ レイアウト アプリのトップ レベル ページの UI 項目を定義しています。これらの項目には、戻るボタン、タイトルとサブタイトル、アプリ メニュー、メイン コンテンツ領域、アプリ バー ボタンが含まれます。
<body>
<div class="win-ui-dark appGrid">
<header aria-label="Header content" role="banner">
<button class="win-backbutton" aria-label="Back"></button>
<h1 class="titlearea win-type-ellipsis">
<span class="win-type-xx-large titlecontainer" tabindex="0"><span class="pagetitle">Mountains</span><span class="win-type-x-large chevron"></span></span>
<span class="win-type-x-large pagesubtitle">Rainer</span>
</h1>
</header>
<div id="headerFlyout" data-win-control="WinJS.UI.Menu">
<button data-win-control="WinJS.UI.MenuCommand" data-win-options="{id:'rainierMenuItem', label:'Rainier'}"></button>
<button data-win-control="WinJS.UI.MenuCommand" data-win-options="{id:'stHelensMenuItem', label:'St. Helens'}"></button>
<button data-win-control="WinJS.UI.MenuCommand" data-win-options="{id:'olympusMenuItem', label:'Olympus'}"></button>
<button data-win-control="WinJS.UI.MenuCommand" data-win-options="{id:'bakerMenuItem', label:'Baker'}"></button>
<button data-win-control="WinJS.UI.MenuCommand" data-win-options="{id:'adamsMenuItem', label:'Adams'}"></button>
</div>
<div class="appViewContentMask">
<div class="appViewContent">
<div id="current-page" class="page" data-win-control="WinJS.UI.HtmlControl" data-win-options="{uri: '/html/current.html', data: FluidAppLayout.Data.mountains[0].weatherData[0]}"></div>
<div id="ten-day-page" class="page" data-win-control="WinJS.UI.HtmlControl" data-win-options="{uri: '/html/tenDay.html', data: FluidAppLayout.Data.mountains[0].weatherData}"></div>
</div>
</div>
</div>
<div id="appbar" class="win-ui-dark appbar" data-win-control="WinJS.UI.AppBar">
<button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id: 'current', label: 'Current', icon: 'calendarday', type: 'toggle', onclick: FluidAppLayout.transitionPivot, selected: 'false', tooltip: 'Get the current report'}"></button>
<button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id: 'tenDay', label: 'Ten day', icon: 'calendarweek', type: 'toggle', onclick: FluidAppLayout.transitionPivot, selected: 'false', tooltip: 'Get the ten day report'}"></button>
</div>
</body>
CSS グリッドを使って HTML ページに UI 項目を配置する
滑らかで適応性に優れた UI レイアウトは、CSS グリッドを使うことによっても最良に実現できます。これは、グリッドは自動的に拡張して、与えられたスペースに表示することができるほか、さまざまなウィンドウ サイズの UI レイアウト調整を簡単に行うことができる多様なプロパティのセットが用意されているためです。また、グリッド内の要素の位置は要素が指定された順序と関係がないため、つまり要素の位置は、HTML マークアップ内での順序ではなく CSS によって指定されるため、異なる画面サイズまたは異なる向きに対して要素の配置を簡単に変えることができ、さらには特定のレイアウトで要素を非表示にすることさえできます。
メイン ページのレイアウト
CSS サンプルを使ったアダプティブ レイアウト アプリでは、div
-ms-grid
の display プロパティを設定することで、App.html ページの最上位の div に CSS グリッドを適用します。この最上位のグリッドは、アプリのメイン ページに UI 項目を配置するための構造全体を定義します。次に、サンプル アプリは -ms-grid-columns プロパティと -ms-grid-rows プロパティの値を設定してグリッドの列と行を定義します。
次の CSS コードはサンプルのメイン ページの最上位の div にグリッドを適用します。 このグリッドは、アプリのヘッダー ("戻る" ボタン、タイトルとサブタイトル、アプリ メニュー) を構成する項目を配置したり、メイン コンテンツ領域の位置を設定したりするために使います。
.appGrid { display: -ms-grid; -ms-grid-columns: 120px 1fr; -ms-grid-rows: 120px 1fr; /* Other properties omitted for clarity. */ }
上の CSS コードは、2 列、2 行のグリッドを作っています。1 列目は幅 120 ピクセル、2 列目は幅 1 "補助単位" です。 つまり、列幅が自動的に拡張して、1 列目には表示されない使用可能なスペースが表示されるようにします。行も同様に定義されます。
次の図は、グリッドがアプリのメイン ページを分割する方法を示しています。
次に、CSS サンプルを使ったアダプティブ レイアウトは、グリッドの特定のセルを各項目に割り当てることで UI 項目の位置を設定します。サンプルはこれを行うために、-ms-grid-column プロパティと -ms-grid-row プロパティをページの要素に適用します。CSS グリッドでは、セルの境界に対して項目を配置する他のプロパティをいくつかサポートしており、項目が複数の列または行にまたがることができます。詳しくは、「グリッド レイアウト」をご覧ください。
次の CSS コードはサンプル アプリのメイン ページの header 要素を最上位のグリッドの列 1、行 1 に配置し、この要素がグリッドの両方の列にまたがることができるようにしています。 また、このコードは最上位のグリッドの列 1、行 1 内に "子" グリッドを作っています。この子グリッドは、ヘッダー (戻るボタン、タイトルとサブタイトル、アプリ メニュー) を構成する個々の項目の配置に使います。
header[role=banner] { -ms-grid-column: 1; -ms-grid-row: 1; -ms-grid-column-span: 2; /* Child grid for positioning header items.*/ display: -ms-grid; -ms-grid-columns: 120px 1fr; -ms-grid-rows: 1fr; }
上のコードは、次の画像で青色で強調表示されている領域にグリッドを作ります。
CSS サンプルを使ったアダプティブ レイアウトは、入れ子になった div 要素を使って本日の予報と 10 日間の予報が表示されるメイン コンテンツ領域を定義します。
<div class="appViewContentMask"> <div class="appViewContent"> <div id="current-page" class="page" data-win-control="WinJS.UI.HtmlControl" data-win-options="{uri: '/html/current.html', data: FluidAppLayout.Data.mountains[0].weatherData[0]}"></div> <div id="ten-day-page" class="page" data-win-control="WinJS.UI.HtmlControl" data-win-options="{uri: '/html/tenDay.html', data: FluidAppLayout.Data.mountains[0].weatherData}"></div> </div> </div>
上の例では、JavaScript 用 Windows ライブラリ HtmlControl コントロールを使って、本日の予報と 10 日間の予報の HTML ページを動的に含めています。WinJS コントロールについて詳しくは、「クイック スタート: WinJS コントロールとスタイルの追加」をご覧ください。
次の CSS コードは最上位のグリッドの列 2、行 2 内に
appViewContentMask
div を配置しています。また、グリッド セル全体にコンテンツが確実に表示されるようにし、セルに入りきらないコンテンツを非表示にするようにプロパティを設定しています。.appViewContentMask { -ms-grid-column: 2; -ms-grid-row: 2; width: 100%; height: 100%; overflow: hidden; /* Other properties omitted for clarity. */ }
次の CSS コードは
appViewContent
div をappViewContentMask
div で定義された領域に表示する 1 つのセルを含む子グリッドに変えています。子グリッドを使うと、ビュー状態でアプリのサイズや向きが変わったときにコンテンツを再配置することが容易になります。.appViewContent { width: 100%; height: 100%; display: -ms-grid; -ms-grid-columns: 1fr; -ms-grid-rows: 1fr; }
この CSS コードは、次の画像で青色で強調表示されている領域にコンテンツ領域のためのグリッドを割り当てます。
10 日間の予報の基本レイアウトを定義する
10 日間の予報は、WinJS の ListView コントロールを使って管理および表示される項目のコレクションです。 各項目は、画像と、日付、最高/最低気温、"体感" 気温、雪の確率を含む文字列のセットで構成されます。
次の HTML ページは、10 日間の予報の項目の UI を定義しています。CSS を使ったアダプティブ レイアウトのサンプルでは、WinJS テンプレートとデータ バインディングを使ってデータを ListView コントロールに提供します。このトピックは、UI のレイアウトについての説明のため、テンプレートとデータ バインディングについては説明しません。テンプレートとデータ バインディングについて詳しくは、「テンプレートを使ってデータをバインドする方法」をご覧ください。
<body>
<div class="tenDayPage">
<div id="tenDayTemplate" class="tenDayTemplate" data-win-control="WinJS.Binding.Template">
<div class="tenDayGrid">
<div class="win-type-x-large tenDayDate" data-win-bind="innerHTML: date">
</div>
<div class="tenDayImg">
<img data-win-bind="src: imgSrc" />
</div>
<div class="win-type-x-large tenDayHighLow">
<span class="tenDayHigh" data-win-bind="innerHTML: hi"></span>
<span>/</span>
<span class="tenDayLow" data-win-bind="innerHTML: low"></span>
</div>
<div class="tenDayFeelsLike">
<span>Feels like </span>
<span data-win-bind="innerHTML: feelsLike"></span>
</div>
<div class="tenDayChanceOfSnow">
<span>Chance of snow is </span>
<span data-win-bind="innerHTML: chanceOfSnow"></span>
</div>
</div>
</div>
<div id="tenDayListView" class="tenDayListView" data-win-control="WinJS.UI.ListView" data-win-options="{layout: {type: WinJS.UI.GridLayout}}"></div>
</div>
</body>
上の例では、特別な WinJS CSS classes for typographyを使って、日付と最高/最低気温の文字列用の特大フォント サイズを設定しています。これは、tenDayDate
と tenDayHighLow
の div 要素の class="win-type-x-large"
で表されています。
サンプル アプリでは、次の CSS コードを使って、TenDay.html ページとその ListView コントロールが親コンテナー (アプリのメイン ページのコンテンツ エリア) に表示されるようにしています。
/* Size Page to full size of parent container */
.tenDayPage
{
height: 100%;
}
/* List View Control */
.tenDayListView
{
width: 100%;
height: 100%;
}
CSS メディア クエリを使ってビュー固有のレイアウトとスタイルを適用する
CSS メディア クエリを使うと、ウィンドウ サイズに応じてアプリの HTML 項目に適用するさまざまなスタイルを簡単に定義することができます。それぞれのレイアウトに対して個別にメディア クエリを使うことも、メディア クエリを組み合わせて複数のレイアウトに同じスタイルのセットを適用することもできます。ここでは、CSS サンプルを使ったアダプティブ レイアウトがメイン ページと 10 日間の予報の項目のレイアウトに使うメディア クエリについて説明します。
幅の狭いレイアウトに対するメイン ページのレイアウト
サンプル アプリを使ってみると、縦方向、横方向、拡大幅のいずれのレイアウトも、UI 項目のサイズとレイアウトはほとんど変化しないことがわかります。しかし、アプリの幅を 500 ピクセル未満に縮小すると、次の変化が生じます。
- アプリ ヘッダーの UI 項目が小さくなる。
- レイアウトが 2 列 2 行から 1 列に変わり、ヘッダーが 1 行目、メイン コンテンツ領域が 2 行目になる。
これらの変化は、幅の狭いレイアウトに対して異なったスタイルのセットを特に定義する CSS メディア クエリから適用されます。
@media (max-width:499px) {
.appGrid {
display: -ms-grid;
-ms-grid-columns: 1fr;
-ms-grid-rows: 120px 1fr;
width: 100%;
height: 100%;
}
header[role=banner] {
-ms-grid-column: 1;
-ms-grid-row: 1;
-ms-grid-columns: 60px 1fr;
-ms-grid-rows: 1fr;
display: -ms-grid;
}
header[role=banner] .win-backbutton {
-ms-grid-column: 1;
-ms-grid-row: 1;
margin-left: 20px;
margin-top: 75px;
}
header[role=banner] .titlearea {
-ms-grid-column: 2;
-ms-grid-row: 1;
margin-top: 69px;
max-width: 260px;
}
.appViewContentMask {
-ms-grid-column: 1;
-ms-grid-row: 2;
}
上の CSS コードでは、–ms-grid-columns
プロパティの新しい値がアプリのメイン グリッド (appGrid
) を 2 列から 1 列に変えています。また、この CSS コードではアプリのヘッダーの項目用の新しい子グリッドを定義し、新しいグリッドにヘッダー項目を配置しています。最後に、コンテンツ領域 (appViewContentMask
) を以前のグリッドの列 2、行 2 から新しいグリッドの列 1、行 2 へ移動させています。
幅の狭いレイアウト用に 10 日間の予報をレイアウトする
アプリの幅を 500 ピクセル未満に変更した場合、10 日間の予報の個々の項目のレイアウトが変わります。 幅が 500 ピクセルを超えると、項目は 1 列のグリッドを使って縦方向にレイアウトされます。幅が 500 ピクセル未満になると、項目は 2 列のグリッドを使って横方向に切り替わります。
次の画像は、10 日間の予報が異なるレイアウトでどのように表示されるかを示しています。
各種レイアウトを実現するために、サンプルは CSS メディア クエリを使って現在のビュー状態に基づいてスタイルを適用します。サンプルでは、すべてのビュー状態に共通のスタイルのほかに、幅が 500px 未満になったときのレイアウト専用のスタイルを定義しています。
/* Styles that are common across all view states */
.tenDayGrid
{
width: 190px;
height: 250px;
overflow: hidden;
padding: 10px;
display: -ms-grid;
-ms-grid-columns: 1fr;
-ms-grid-rows: (auto)[5];
}
.tenDayDate
{
-ms-grid-column: 1;
-ms-grid-row: 1;
}
.tenDayImg
{
-ms-grid-column: 1;
-ms-grid-row: 2;
}
.tenDayHighLow
{
-ms-grid-column: 1;
-ms-grid-row: 3;
}
.tenDayFeelsLike
{
-ms-grid-column: 1;
-ms-grid-row: 4;
}
.tenDayChanceOfSnow
{
-ms-grid-column: 1;
-ms-grid-row: 5;
}
}
/* Define the template for the width less than 500px */
@media (max-width:499px)
{
.tenDayDate
{
font-weight: 600;
}
.tenDayDate > .day
{
font-weight: 200;
}
.tenDayHighLow
{
font-weight: 300;
}
.tenDayFeelsLike, .tenDayChanceOfSnow
{
font-weight: 300;
}
.tenDayGrid
{
width: 250px;
height: 150px;
overflow: hidden;
padding: 10px;
display: -ms-grid;
-ms-grid-columns: auto 1fr;
-ms-grid-rows: (auto)[4];
}
.tenDayDate
{
-ms-grid-column: 1;
-ms-grid-row: 1;
-ms-grid-column-span: 2;
}
.tenDayImg
{
-ms-grid-column: 1;
-ms-grid-row: 2;
-ms-grid-row-span: 3;
}
.tenDayHighLow
{
-ms-grid-column: 2;
-ms-grid-row: 2;
}
.tenDayFeelsLike
{
-ms-grid-column: 2;
-ms-grid-row: 3;
}
.tenDayChanceOfSnow
{
-ms-grid-column: 2;
-ms-grid-row: 4;
}
}
JavaScript を使ってウィンドウのサイズ変更イベントを必要に応じて処理する
CSS とメディア クエリを使ってアプリのレイアウトをできるだけ多く定義することをお勧めしますが、CSS で対応できないレイアウトの問題を JavaScript で対処する必要があることもあります。
たとえば、サンプル アプリは WinJS ListView コントロールを使って 10 日間の予報の項目を表示し、アプリの幅に応じて ListView をリストとグリッド間で切り替えます。サンプル アプリの幅が 500 ピクセルを超えたとき、ListView はグリッド モードを使って項目を縦方向に配置し、親コンテナーを横方向に表示します。 アプリが 500 ピクセル未満のときは、ListView はリスト モードを使って項目を縦一覧に並べます。
ビュー固有のレイアウトを JavaScript で作成するには、ウィンドウのサイズ変更イベントのイベント リスナーを登録します。イベント リスナーのコードで、clientWidth プロパティを照会し、それに従ってレイアウトを構成します。
次の例は、CSS を使ったアダプティブ レイアウトのサンプルの中で、ListView をグリッド モードに設定する部分を抜粋したものです。ウィンドウの幅が 500 ピクセル未満の場合、ListView がリスト モードに変化します。アプリのイベント リスナーがサイズ変更イベントをリッスンし、clientWidth プロパティを照会して、その結果に応じて ListView を変化させます。
function ready(element, options) {
element.winControl = this;
var that = this;
WinJS.UI.process(element).done(function () {
that.listView = element.querySelector(".tenDayListView").winControl;
var itemTemplate = element.querySelector(".tenDayTemplate");
var listViewLayout = new WinJS.UI.GridLayout();
if (document.body.clientWidth <= 499) {
listViewLayout = new WinJS.UI.ListLayout();
}
else {
element.style.opacity = "0";
}
// ...
window.addEventListener("resize", tenDayResize, false);
});
}
function tenDayResize(e) {
var listview = document.querySelector(".tenDayListView").winControl;
if (document.body.clientWidth <= 499) {
if (!(listview.layout instanceof WinJS.UI.ListLayout)) {
listview.layout = new WinJS.UI.ListLayout();
}
}
else {
if (listview.layout instanceof WinJS.UI.ListLayout) {
listview.layout = new WinJS.UI.GridLayout();
}
}
}
要約
HTML、CSS、JavaScript を使って、すべてのウィンドウ サイズにおいて適切に表示され正しく機能する滑らかなアプリの UI を作成する方法について説明しました。