前回までに横スライドを実現できたのですが、横幅が固定のためwidth: 100%を基本とするスマートフォンサイトなどには不向きだという問題がありました。今回はスマートフォンで横幅100%な横スライドに挑戦したいと思います。

左からiPhone4S、Android htc001HT、Firefox OS(デベロッパープレビュー)

写真は各端末に標準で備わっているブラウザで動かしたときの様子。一通り動作をしています。

横幅にフィットさせる

まず、CSSの限界という部分ですが、現在の横幅が「何ピクセル」かを調べることができず、それを調べるにはJavaScriptの力を借りないと厳しいです。

というわけで、JavaScriptで横幅を取得して、スマートフォンのような異なる横幅のサイズにもフレキシブルに対応させます。

前回のソースコードに以下のようなCSSがありました。

CSS(前回のCSS一部をおさらい)

#wrapper { // ===> タブもコンテンツも両方囲っている親コンテナ 
  width: 600px;
  overflow: hidden;
}
#tabs { // ===> 3つのコンテンツ(社会・経済・スポーツ)を両方囲っているコンテナ
  width: 1800px;
  …中略…
}
.tab_1 #tabs { // ===> 社会が選択中の#tabsは600px左へ移動
  left: 0;
}
.tab_2 #tabs { // ===> 経済が選択中の#tabsは600px左へ移動
  left: -600px;
}
.tab_3 #tabs { // ===> スポーツが選択中の#tabsは1200px左へ移動
  left: -1200px;
}
.archives { // ===> コンテンツ1つに対するボックスのスタイル
  float: left;
  width: 600px;
}

つまり、横幅600pxのコンテンツが3個横並びなので、#tabsの幅は600px×3個で1800px。タブが押されたとき、#tabsのleft値が0→マイナス600px→マイナス1200pxと移動し、それがCSS Transitionsによってアニメーション移動する、という仕組みでした。今回はこの決めうちにしていた幅「600px」が端末ごとに違ってくるわけですね。

下図ではiPhoneを例に、前回width:600pxだったところが320pxになっている状態を図解しています。

では、この図をもとに考え、はじめに以下のような関数を書いてみましょう。

JavaScript

var windowWidth; // 画面横幅のサイズが代入される


function resized () {
  windowWidth = window.innerWidth; // ===> (1)
  $(".archives").width(windowWidth); // ===> (2) 
  $("#tabs").width(windowWidth*3); // ===> (3)
}
  • (1)変数windowWidthに、ブラウザのウインドウ幅の数値が代入されます。
  • (2)div.archivesはコンテンツの1つずつの幅なので、これはブラウザ幅と同じwindowWidthの値を横幅にして事実上ブラウザ幅いっぱいに見えています。(iPhoneだと縦置きで320、横置きで480(iPhone5では568)がwindowWidthに代入されます)
  • (3)#tabsはその3倍の横幅を持ちつつ、3個のdiv.archivesが入るようにしています。(つまりiPhoneの縦置き状態だと320×3で960)

そしてこのページが読み込まれた(load)最初の1回、そしてユーザによってスマホが傾けられたときやPCブラウザの幅が変更されたとき(resize)にwindowWidthを入れ直さないといけないので、以下のスクリプトで対応させます。

JavaScript

$(window).bind("load resize", resized);

ほぼ準備は完了です。

CSSの修正

前回のCSSとの差分だけ解説します。

CSS(変更)

.tab_nav li { 
  float: left;
  /*width: 200px;*/ // ===> 削除
width: 33%; // ===> 追加
…中略…
}

#wrapper { 
  /*width: 600px;*/ // ===> 削除
  overflow: hidden;
}
#tabs {
  /*width: 1800px;*/ // ===> 削除
  …中略…
}

今回widthの値(px単位)は明示的に指定しませんのでwidthの行だけ削除します。

.tab_nav liのwidth: 33%への変更は単純に3つのタブで分割したかっただけなので、割り切れない部分は割愛します。

CSS(削除)

.tab_1 #tabs { // ===> 社会が選択中の#tabsは600px左へ移動
  left: 0;
}
.tab_2 #tabs { // ===> 経済が選択中の#tabsは600px左へ移動
  left: -600px;
}
.tab_3 #tabs { // ===> スポーツが選択中の#tabsは1200px左へ移動
  left: -1200px;
}

今回不要になるので削除します。(明示的に600px…をJavaScriptで行うため)

そのかわり、タブクリックごとにJavaScriptで#tabsのleft値を指定する必要があります。

JavaScriptの完成

ここで前回のJavaScriptを見てみましょう。

JavaScript(前回)

$(".tab_nav a").click( tabClicked ); 


function tabClicked (e) {
     e.preventDefault();
     var id_name = $(e.target).attr("href");
     id_name = id_name.replace("#", "");
     $("#wrapper").removeClass().addClass(id_name);
}

これが前回の全コードですね、タブクリックしたら変数id_nameに「#tab_1」などが入ってくるので、#が抜かれた「tab_1」などの文字列を#wrapperにクラスとして付ける、ということでした。

(例)タブ「社会」がクリックされたら…<div id="wrapper"> → <div id="wrapper" class="tab_1">

実際の完成まであと2行、追加します。

まずは今回の完成版JavaScriptと以下の解説をご覧ください。

JavaScript(今回の完成版)

var windowWidth; 


$(".tab_nav a").click( tabClicked );


function tabClicked (e) {
  e.preventDefault();
  var id_name = $(e.target).attr("href");
  id_name = id_name.replace("#", "");
  $("#wrapper").removeClass().addClass(id_name);
  var leftValue = - ( windowWidth * parseInt(id_name.replace("tab_", "") -1) ); // ===> (4)
   $("#tabs").css("left", leftValue); // ===> (5)
}


function resized () {
  windowWidth = window.innerWidth;
  $("#tabs").width(windowWidth*3);
  $(".archives").width(windowWidth);
}


$(window).bind("load resize", resized);
  • (4) ちょっと複雑になりましたが、これはタブクリック時のleftの移動量を計算しています。
    parseInt(id_name.replace("tab_", "")で「tab_1」を「1」にします、つまり数字だけに文字列を変換してしまいます。
    これによってタブクリックごとに1~3の数値が得られ、それをwindowWidthにかけているので移動量が得られるというわけです。
    ただしこのままだと一番左の「社会」は0pxでないといけません、しかしwindowWidth×1だとゼロにはなりません。
    なので移動量にマイナス1で補正して0~2の数値を得るようにします。
    例えばiPhoneの縦置き横幅320pxの場合、社会のタブは320×0 = 0、経済のタブは320×1 = 320、スポーツのタブは320×2=640と計算され、それがマイナスの値にして変数leftValueに代入しています。
  • (5) div#tabsのCSSのleft値をJavaScriptで変更しています。

HTML側ではviewportの指定によりスマホ対応しましょう。詳しくはサンプルファイルで確認してみてください。

以上、完成です。

サンプルプログラム : ex04.zip

さて、6回に渡って入門者、未経験者に向けたこの連載もいよいよ次回が最終回! 何をお伝えするか、それは最終回のお楽しみということでどうぞご期待ください!

執筆者紹介

秋葉秀樹(AKIBA Hideki)
- 株式会社ツクロア(tuqulore) 代表取締役

DTP/グラフィックデザイン/Webフロントエンド全般/Flashゲーム開発/3DCGモデリング/Webディレクターを経て現職。主な作品としては、海遊館やサンシャイン水族館に公認されたAndroid/iPhoneアプリ「Ikesu」がある。

「Ikesu」は、NFC技術を水族館で利用した世界初の事例。魚をスマートフォン内に持ち帰られる体験を提供し、2ヶ月足らずで1万人が利用した。

現在はデザイナー向けの講演活動やトレーナー活動、また執筆活動などを行っている。

近著に『10倍ラクするIllustrator仕事術』(技術評論社)や『すべての人に知っておいてほしい HTML5+CSS3の基本原則』(MdN)などがある。

HTML5を使ったデザイナー向けのWebアプリ「Grad3」の作者。2013年4月より株式会社ツクロアを設立した。