モバイルファースト

この記事では、モバイルファーストの原則に従ったウェブサイトのレイアウトを実装するためのガイドを提供します。これは、既定の構成が狭い画面/モバイル端末用であり、広いビューポート用のレイアウト機能がその上に重ねられているレイアウトを作成することを意味します。

最初にやるべきこと - モバイルを既定に

私たちはデスク先頭サイトに慣れ親しんでいるので、モバイルでの使い勝手を重視することは無意味だと思うかもしれません。そのためには、デスク先頭とモバイルの両方で、あらゆる機能を考慮した上で、より単純で合理的なモバイル体験を提供する必要があります。しかし、私たちの経験では、モバイルファーストとは、モバイルの実装を既定のレイヤーとしてその上に構築することなのです。

企画段階では、全体的な体験を考慮し、どのような機能をモバイルやデスク先頭などで同時に提供するか、またそれらをどのように実装するかを検討します。そして実装段階では、モバイルのレイアウトと機能を既定の構成として提示し、必要に応じてその上に追加情報をロードします。これにより、モバイル(多くの場合、メモリー、帯域、処理能力が最も低い対象端末)に、できるだけ早く、できるだけ余計な情報を排除して、その端末に適した体験を提供することができます。例えば、以下のようなことです。

  • ビューポートの大きさなどに応じて異なる整形・レイアウト情報を提供している場合、デスク先頭/広い画面用の整形を最初に設定するのではなく、メディアクエリーが適用される前に狭い画面/モバイル用の整形を既定の整形として設定する方が理にかなっています。こうすることで、モバイル端末が資産やその他の情報を再び読み込む必要がなくなります。
  • 機能検出や matchMedia のような仕組みを使って、ビューポートの大きさや機能の対応状況などに応じてスクリプト機能を条件付きで読み込む場合は、ほとんどすべてのブラウザーが必要とする基本的なものだけを最初にロードし、その後、食物連鎖の上位にあるブラウザーを徐々に強化していくべきです。

Note: ほとんど何もせずに始めて、必要に応じて作業を進めていく方が、すべてを始めて必要のないものを蓋をしていくよりも、通常は理にかなっています。

モバイルの制約

すでに述べたように、モバイルは他の端末に比べて一般的にメモリー、処理能力、帯域幅が少なく(スマートテレビも一般的にかなり低消費電力であることに留意してください)、利用可能なビューポートも小さくなります。したがって、コンテンツを複数のビューに分割し、モバイル用アプリケーションの各ビューのインターフェイスとコンテンツをできる限り簡素化することに加えて、影、アニメーション、グラデーションなどの視覚効果を含めないことも良いアイデアです。特に、モバイルでアプリケーションを実行したときにパフォーマンスが低下したり、ラグが発生したりする場合には、少なくとも選択肢の一つとして検討すべきでしょう。

制御機構

制御機構もまた、モバイル機器の大きな制約となっています。モバイル端末でフォームにデータを入力しようとしたことがある人や、複雑なサイトを操作したことがある人は、このことをよく知っています。そのため、モバイル端末では、可能な限り各ビューを単一の単純な目的のために切り詰め、ユーザーに期待される入力の量を減らすなど、物事を単純化するように努めるべきです。後者は、モバイルユーザーだけでなく、デスク先頭ユーザーにも喜ばれるでしょう。

使用する場面

さらに、モバイル機器がどのような場面で使われるのか、ユーザーがモバイルでどのような作業をしたいと考えているのかを考慮する必要があります。いくつかの場所で目にする言葉に「目玉一つ、親指一本」というものがありますが、これはユーザーがどれだけ注意を払っているかを意味しています。もちろん、ユーザーは自分がしていることに集中しているはずですが、照明の悪い車の中や、テレビで放送されているスポーツを背景にした騒がしいバーの中にいる可能性もあるのです。この点を考慮し、コンテンツや機能が単純で読みやすく、できる限り気が散らないようにする必要があります。

モバイルナビゲーション

モバイルアプリのレイアウトを開発する際、ナビゲーションメニューの問題に直面することがよくあります。ユーザーが検索したり、アプリケーションの別のビューやページに移動するための仕組みを提供するという概念は、対象となる端末に関係なく同じです。しかし、モバイルの画面はとても小さいため、デスク先頭用の合理的なナビゲーションは、アプリの最初のビューのほとんどを埋め尽くし、コンテンツを覆い隠してしまうことで、使い勝手を台無しにしてしまいます。

モバイルでナビゲーションが邪魔になるという問題を解決する方法はいくつかありますが、ここではそのうちのいくつかをご紹介します。主な目的は、コンテンツを優先し、ユーザーが本当に必要とするまでナビゲーションを隠すことです。

まず、モバイルでは別のナビゲーションの仕組みを考えることができます。例えば、デスク先頭で縦型のナビゲーションメニューを用意していた場合、モバイルではこれをオプションを含むセレクトメニューに変更したり、ボタンを押すとナビゲーションオプションが重ねて表示されるようにしたりすることができます。

2 つ目は、ナビゲーションメニューを通常の上部ではなく、ページの下部に配置するという一般的なオプションです。これにより、コンテンツがページの一番上に表示され、ユーザーがページの最後に到達したときに、次にどこに行けばいいのかを示す道しるべとなります。

3 つ目は、この 2 つを組み合わせることです。ページ上部にボタンを 1 つ設置し、ページ下部のナビメニューのアンカーにリンクさせてみてはいかがでしょうか。そして、記事の先頭に戻るためのリンクを提供することもできます。

条件付きのリソースの読み込み

レスポンシブ/アダプティブデザインを実際に実装するには、リソースの読み込みをある程度の条件付で行う必要があります。これは、様々な端末が必要のない多くのリソースの負担を負うことなく、最適な操作感を得られるようにするためです。詳しくは以下をご覧ください。

単純な例

この記事で紹介したい概念を示すために、ナビメニュー、見出し、1 列のテキストを含むとても単純なアプリを作成しました。私のモバイルファーストの実例をご覧になるか、 Github で一緒に遊ぶためのコードを入手することができます。この単純な例を作るために、 Mozilla Mortar のテンプレートからサンプルアプリの構造を作成しました。コマンドラインで次のように実行して、 Volo 自動化ツールをインストールしました。

sudo npm install -g volo

(まだないのであれば、 Node.js も入手する必要があります)

サンプルプロジェクトを作成するにはこのようにします。

volo create myapp mozilla/mortar-app-stub

これにより、 myapp というディレクトリー内にサンプルプロジェクトが作成されます。アプリのコードファイルは www フォルダー内にあります。 Volo には便利なコマンドがたくさんありますが、ここではそのうちのいくつかをご紹介します。

  • volo server: localhost:8080 にローカルのウェブサーバーを起動し、アプリを実行します。これは簡単なテストに最適です。
  • volo build: アプリの最小化されたコードの版を、 www-built フォルダーにビルドします。
  • volo build base=www-built: 開発バージョンではなく、ビルドされたバージョンをサーバーで実行します。

Mortar テンプレートの組み込み機能

Mortar のテンプレートには、さまざまな機能が組み込まれています。今回のサンプルアプリでは、いくつかの組み込み機能を使ってみました。

  • Firefox OS、Firefox Aurora、Chrome、iOS アプリのインストールに対応したインストールボタンを搭載しています(GitHub の Install ページで説明しています)。インストールボタンを動作させるには、ページ上に <button> を ID を install-btn にして配置するだけでよいのです。マジックですね。
  • メディアクエリーや機能テストに応じて、JavaScript ライブラリーを選択的にインクルードする (require.jsが組み込まれているので、便利でとても使いやすいです)。

HTML の構造

このアプリの例では、 HTML 構造はとてもシンプルなものにします。見出し、ナビゲーションメニュー、そして狭い画面の端末では記事がとても長くなってしまうという事実を強調するためのフィラーテキストを入れているだけです。 HTML は以下のようになります。

<article>
  <nav>
    <ul>
      <li><a href="#">Home</a></li>
      <li><a href="#">Articles</a></li>
      <li><a href="#">Videos</a></li>
      <li><a href="#">Work</a></li>
      <li><a href="#">About</a></li>
      <li><a href="#">Contact</a></li>
    </ul>
  </nav>

  <header>
    <a id="top" href="#bottom">Jump to menu</a>
    <h1>My article</h1>
  </header>

  <div class="main">
    <p>Lorem ipsum … </p>
    <a id="bottom" href="#top">Back to top</a>
  </div>

</article>

<button id="install-btn">Install</button>

既定のモバイル CSS

CSS については、まず app.css スタイルシートにいくつかのスタイルを追加して、合理的な狭い画面用のレイアウトを実現しました。ここではほとんど何もしていません。 CSS の基本的な知識があれば、 app.css のソースコードを見るだけで、ほとんどのことが理解できるはずです。特に注目すべき点は以下の通りです。

article {
  display: table;
}

nav {
  display: table-caption;
  caption-side: bottom;
}

これは、ナビゲーションメニューがソース順では一番上にあるにもかかわらず、一番下に表示させるために使える、ちょっと素敵なハックの CSS です。これは IE8 以上で動作します。 display: table は、<article> とその子を、テーブルマークアップを使用せずに、テーブルレイアウトで表示します。 display: table-caption<nav> 要素をテーブルのキャプションだと思わせ、 caption-side: bottom はテーブルの一番下までジャンプさせます。

しかし、このテクニックについて一つ注意があります。 display: table が設定されている要素では、位置指定が期待通りに行われません。このマークアップには 2 つのリンクが含まれています。

<a id="top" href="#bottom">Jump to menu</a><a id="bottom" href="#top">Back to top</a>

最初のものは、記事の先頭からナビゲーションメニューにジャンプダウンするもので、 2 番目のものは、再び記事の先頭にジャンプアップするものです。これらが <article> の直接の子ではないことを確認しなければなりませんでした。そうでなければ次のように動作しません。

#bottom, #top {
  font-size: 0.8em;
  position:absolute;
  right: 1em;
  text-decoration: none;
}

#top {
  color: white;
  top: 0.5em;
}

#bottom {
  bottom: 0.5em;
}

また、親を相対的に配置するように設定し、絶対的に配置された要素の配置コンテキストになるようにしました(<body> 要素に対して相対的に配置されないようにします)。

モバイルファーストレイアウトの追加

上記のレイアウトは、幅の狭いレイアウトでは問題ありませんが、幅が 480px 程度以上になると、あまりうまくいきません。デスクトップに適したものを作るために、以下のようなメディアクエリーを入れました。

@media (min-width: 480px) {
  #bottom, #top {
    display: none;
  }

  article, nav {
    display: block;
  }

  nav ul {
    text-align: center;
  }

  nav li {
    display: inline;
  }

  nav li a {
    border-right: 1px solid #AD66D5;
    border-bottom: none;
    display: inline-block;
    padding: 0 5px;
    font-size: 1.6em;
  }

  nav li:last-child a {
    border-right: none;
  }

}

@media (min-width: 600px) {
  html {
    background: #eee;
    height: 100%;
  }

  body {
    width: 600px;
    height: inherit;
    margin: 0 auto;
    background: url(../img/firefox-os.png) bottom left no-repeat, linear-gradient(to bottom, #fff, #eee);
  }

  .main > p {
    background: rgba(255,255,255,0.3);
  }

  nav li a {
    padding: 0 10px;
    font-size: 2em;
  }
}

最初のものは、 CSS の display: table の動作を無効にし、ナビゲーションへのジャンプやナビゲーションからのジャンプのためのリンクは、広いレイアウトではもう必要ないので非表示にし、垂直メニューを水平メニューに変更して、利用可能な水平スペースを有効に利用しています。

2 つ目は、コンテンツの幅を 600px に設定し、空いているスペースの中央に配置し、広いレイアウトのためにグラデーションと素敵な背景画像を追加しています。ここがポイントです。背景画像は 126KB あり、幅の狭いレイアウトには適していません。この画像を「600 ピクセル以上」のメディアクエリーに含めることで、狭い画面の端末はメディアクエリーを読まなくなるので、その画像をダウンロードするために時間と帯域幅を無駄にすることがなくなります。

Note: Firefox のレスポンシブデザインビューは、メディアクエリーがどのように動作しているかを簡単に把握するのに最適な方法です。ツール → ウェブ開発ツール → レスポンシブデザインビューで試してみてください。

機能検出

機能検出とは、あるブラウザーが特定の機能に対応しているかどうかを(通常は JavaScript で)テストし、その状況に合わせて CSS や JavaScript を提供することです。これはモバイルファーストの場合に非常に便利です。「モバイル版」ではコードを隠し、「デスクトップ版」でのみコードを入れたい場合や、その逆の場合もあるでしょう。

独自の機能検出を書くこともできますが(Mark Pilgrim氏の All-In-One Almost-Alphabetical Guide to Detecting Everything が良いスタートとなります)、実際には Modernizr のような既存の専用ソリューションを使用する方がはるかに良いでしょう。 Modernizr は、ほぼすべての機能(CSS、HTML5、その他いくつかの機能)の検出が含まれているだけでなく、信頼性が高く、 Modernizr Download Builder を使用して、必要な機能の検出のみを含む独自のカスタムバージョンを作成することができるので、良い選択です。圧縮されていない完全な Modernizr ライブラリーは 42KB ですが、このデモで使用しているバージョンはわずか 8KB です。

私は Modernizr を js/lib ディレクトリーに置き、 HTML ファイルの中に次のような構造を入れて、 Modernizr をインクルードしました。

<script type="text/javascript" src="js/lib/modernizr.js"></script>

Modernizr を導入すると、次の JS ブロックを使ってメディアクエリーに対応しているかどうかを検査し、対応していない場合は、Scott Jehl 氏の matchMedia とメディアクエリーのポリフィルである respond.js を読み込むようにすることができます。

if(!Modernizr.mq('only all')) {
  require('respond');
}

また、matchMediaは他にも様々な場面で活躍します。例えば、デスクトップ版のサイトでは Three のような WebGL ライブラリを必要とする WebGL チャートを掲載したいが、モバイル版には掲載したくないとします。画面の広い端末の場合にのみライブラリーを読み込むブロックを作ることができます。

if(window.matchMedia("(min-width: 481px)").matches) {
  require('three');
}

そのため、必要のないブラウザーでは帯域を節約することができます。

Modernizr の CSS と JS

Modernizr に戻ります。便利なのは、CSS と JavaScript の両方を選択的に提供する仕組みを提供しているからです。 Modernizr は、すべての機能テストの結果を HTML 要素のクラスとして保存しています。例えば、サンプルアプリの Modernizr では、複数の背景画像と rgba の対応状況を検査しています。対応していない場合、<html>タグは次のようになります。

<html class=" js no-rgba no-multiplebgs">

存在する場合、子孫セレクターを使用して、適切な代替手段を提供するために、代替のスタイル付けルールを提供することができます。以下のコードを参照してください。

.no-multiplebgs body {
  background: white;
}

.no-rgba .main > p {
  background: white;
}

これは非常に美しいものではありませんが、これらの機能のいずれかまたは両方に対応していないブラウザーで、メインコンテンツ領域をより読みやすくします。

また、 Modernizr は機能検出の結果を JavaScript の Modenizr オブジェクトに格納するので、機能の対応状況に応じて選択的に JavaScript コードを実行することができます。たとえば、次のようになります。

if(Modernizr.rgba) {

  // RGBA カラーに対応していることに依存するコードを実行します。

}

Google 検索とモバイル優先

2015 年 4 月 21 日以降、 Google のアルゴリズムでは、モバイル端末からの検索において、モバイル端末でよく表示されるページが、そうでないページよりも優先的に表示されるようになりました。