はじめに
本投稿は、2015/8/28に行われた、CSS・Bootstrapによるデザイン - connpassの内容についてまとめた資料です。
今後の予定
AWS上で構築するRESTfulアプリ勉強会~Web開発ワークショップ~ - connpass
今回は、Bootstrapを使用して画面をキレイにしていきます。
2015/8/31 追記
サンプルソースで一部typoおよびレイアウトが崩れる間違いが有りましたので修正しました。
Bootstrapとは?
一言で言うと、CSSフレームワークです。
Bootstrap側で用意されたCSSを使用することで、統一的なデザインを適用することが出来ます。
- よくあるデザインのパーツが揃っているので、自分で頑張ってCSSを書かなくて良い
- レスポンシブデザイン対応なので、PC、モバイルにワンソースで対応可能
といったあたりで非常に恩恵を受けられます。
Bootstrapだけで対応できない場合はもちろん独自CSSを書きますが、Bootstrapで用意されているスタイルを上書きすることもできるので、うまくやれば自力でCSSを書く必要を最小限に抑えることが出来ます。
使い方
基本的には、HTMLエレメントに対しclass="bootstrapで用意されているクラス名"
と設定するだけでいい感じに統一性のあるデザインにできます。
中には、HTMLを規定通りに書けばナビゲーションバーを表示したり、モーダル画面をポップアップしたりする機能もありますが、
全ての機能を紹介することは出来ないので、全体のレイアウトを決める上で重要かつレスポンシブデザインを行う上で核となる機能である
グリッドシステム
について説明します。
グリッドシステム
container
の中に複数のrow(行)
、row
の中に複数のcol(列)
が含まれる構造を取ります。
で、col
の詳細を設定することで、1つのrow
内に横に並べるcol
の数をコントロールすることが出来ます。
col
は、col-{size}-{列数制御値}
というフォーマットで記述します。
この時、「sizeで指定したサイズ以上の画面の横幅がある場合、列数制御値で指定した値の合計が12になるようにcolを指定したエレメントを配置する」、という動きをします。
...わかりにくいですね(笑)
もう少し噛み砕きます。
まず、画面の横幅をbootstrapでは下記に分類しています。
size |sizeに指定する文字|ざっくり分類
-------------+--------------+----------
〜767px |xs(xtra small) | スマホ
768px〜991px |sm(small) | タブレット
992px〜1199px|md(medium) | ノートパソコン
1200px〜 |lg(large) | デスクトップパソコン
例えば、一つのrow内に6個のcolを作ったとします。下記のような感じ
<div class="container">
<div class="row">
<div class="col-sm-4 bg-info">success</div>
<div class="col-sm-4 bg-danger">danger</div>
<div class="col-sm-4 bg-info">success</div>
<div class="col-sm-4 bg-danger">danger</div>
<div class="col-sm-4 bg-info">success</div>
<div class="col-sm-4 bg-danger">danger</div>
</div>
</div>
※bg-info
, bg-danger
はバック色を指定するclassです。後ほどボタンの説明でもsuccess
, danger
等が出てきます。
colは、col-sm-4
としていますので、
- 画面幅 = sm(タブレット以上)
- colのサイズ = 全て4
を指定しています。つまり、
- タブレット以上の横幅がある場合、3列表示する。
- スマホの場合は1列で表示する
となるわけです。
...まだちょっとわかりにくいですね(笑)
実際に動かしてみましょう!
bootstrapをテストできるサービス
これ。ログインしなくても使えます。
Bootply - The Bootstrap Playground
これで上のサンプルを入力し、試してみた結果です。
横幅768px以上(808px)
横幅768px未満(765px)
col設定を複数入れる
col設定を複数入れることで、
- スマホの場合は1列
- タブレットは2列
- パソコンなら3列
- 画面が大きいパソコンは4列
という制御もできます。
下記サンプルを実際に試してみましょう!
<br><br>
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-2 bg-info">success</div>
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-2 bg-danger">danger</div>
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-2 bg-info">success</div>
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-2 bg-danger">danger</div>
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-2 bg-info">success</div>
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-2 bg-danger">danger</div>
</div>
</div>
その他、サンプルを幾つか
class設定のサンプルをいつくか紹介します。
下記サンプルは公式サイトからの引用です。
これらのソースを実際に動かしてみましょう。
※他にもたくさんあります。公式サイトを活用しましょう。
英語ですが、ソースとサンプルが載ってるので全然問題ありません!
ボタンの形と色
<!-- Standard button -->
<button type="button" class="btn btn-default">Default</button>
<!-- Provides extra visual weight and identifies the primary action in a set of buttons -->
<button type="button" class="btn btn-primary">Primary</button>
<!-- Indicates a successful or positive action -->
<button type="button" class="btn btn-success">Success</button>
<!-- Contextual button for informational alert messages -->
<button type="button" class="btn btn-info">Info</button>
<!-- Indicates caution should be taken with this action -->
<button type="button" class="btn btn-warning">Warning</button>
<!-- Indicates a dangerous or potentially negative action -->
<button type="button" class="btn btn-danger">Danger</button>
<!-- Deemphasize a button by making it look like a link while maintaining button behavior -->
<button type="button" class="btn btn-link">Link</button>
-
btn
でボタンの形 - `btn-XXXX(primary, success, info, warning, danger)で色
が決まります。
実行結果
テーブル
<table class="table">
<thead>
<tr>
<th>#</th>
<th>First Name</th>
<th>Last Name</th>
<th>Username</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">1</th>
<td>Mark</td>
<td>Otto</td>
<td>@mdo</td>
</tr>
<tr>
<th scope="row">2</th>
<td>Jacob</td>
<td>Thornton</td>
<td>@fat</td>
</tr>
<tr>
<th scope="row">3</th>
<td>Larry</td>
<td>the Bird</td>
<td>@twitter</td>
</tr>
</tbody>
</table>
-
class=table
でデフォルトのスタイル設定
後は、例えば下記を追加すれば簡単にスタイルを変えられます。試してみましょう!
class | 効果
------+-----
table-striped|行ごとに色を変える
table-bordered|枠線を入れる
table-hover|マウスオーバ時に行を強調
今回の内容
こんな感じにします。
ワークショップメニュー
- 事前準備
- Lesson1 実験
- Lesson2 実装
という感じですすめます。
事前準備
事前準備は毎回同じなので、別エントリにまとめています。
全12回の勉強会でやっているGitの使い方 - AWS上で構築するRESTfulアプリ勉強会~Web開発ワークショップ~ - Qiitaを参照してください。
やることは、
- gitのブランチを整えて今回用ブランチ
vol/08
を作成する
です。まずこれをやりましょう。
それと、第5回と第6回に不参加の方は、テーブルの修正が必要です。
- 第5回
- ユーザ登録用のテーブル作成(ログイン機能実装のため)
- 第6回
- TODO一覧テーブルへの列追加(owner列とassignee列。担当者アサイン機能実装のため)
をやってますので、それぞれ下記リンク先を参照して実施して下さい。
ユーザ登録用のテーブル作成
TODO一覧テーブルへの列追加
Bootstrapのダウンロードと配備
Bootstrap公式サイト(version3)はここです。
v4-alpha版も出てますが今回は安定版の3を使用します。
公式サイトからダウンロードします。
https://github.com/twbs/bootstrap/releases/download/v3.3.5/bootstrap-3.3.5-dist.zip
をwgetコマンドで。
zipファイルをダウンロード後、/var/www/study/rest-study/app/webroot/
上にファイルを展開します。
SSHで開発サーバにログイン後、下記の通りコマンドを実行します。
cd /var/www/study/rest-study/app/webroot
wget https://github.com/twbs/bootstrap/releases/download/v3.3.5/bootstrap-3.3.5-dist.zip
unzip bootstrap-3.3.5-dist.zip
mv bootstrap-3.3.5-dist bootstrap
rm bootstrap-3.3.5-dist.zip
上記実行すると、下記のようなディレクトリツリーになります。
元のファイルとミニファイされたファイルが混在していますのでミニファイ版を使うことにしてそれ以外の不要なものは消してしまいましょう。
※このまま置いておいても問題ありません。
app/webroot/bootstrap
├── css
│ ├── bootstrap-theme.css #消す
│ ├── bootstrap-theme.css.map #消す
│ ├── bootstrap-theme.min.css
│ ├── bootstrap.css #消す
│ ├── bootstrap.css.map #消す
│ └── bootstrap.min.css
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.svg
│ ├── glyphicons-halflings-regular.ttf
│ ├── glyphicons-halflings-regular.woff
│ └── glyphicons-halflings-regular.woff2
└── js
├── bootstrap.js #消す
├── bootstrap.min.js
└── npm.js #消す
app/webroot/bootstrap
├── css
│ ├── bootstrap-theme.min.css
│ └── bootstrap.min.css
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.svg
│ ├── glyphicons-halflings-regular.ttf
│ ├── glyphicons-halflings-regular.woff
│ └── glyphicons-halflings-regular.woff2
└── js
└── bootstrap.min.js
-
Gitのブランチを整えて、
vol/08
ブランチを作成。 - テーブル修正がまだの方は修正する。
- Bootstrap関連ファイルをダウンロード&展開
準備ができたら、Lesson1です!
Lesson1 実験
Bootstrap Editor and Playground for JavaScript, CSS, HTML5 and jQuery.
でいろいろ実験してみましょう。
まずは上で示したいくつかのサンプル。
興味あるものを好きなだけ試してみてください。
Lesson2 実装
まずはbootstrapのCSS、Javascriptファイルを使えるようにします。
その後はデザインです!
CSS, Javascriptの設定
CSSはdefault.ctpに追記、javascriptはrequire-configに追記です。
編集するファイル一覧
編集 | file | 編集概要 |
---|---|---|
修正 | app/webroot/js/require-config.js | 読み込み設定 |
修正 | app/webroot/js/main.js | 読み込み |
修正 | app/View/Layouts/default.ctp | デザイン修正 |
追加 | app/webroot/css/app.css | カスタムCSS |
require-config.js
bootstrapのjavascriptを読み込む設定をします。
// require設定
var require = {
// キャッシュ防止
urlArgs: "v=" + (new Date()).getTime(),
// モジュール読み込みのbaseUrlを指定
baseUrl: '/rest-study/js/',
// ファイルのpathを指定
paths : {
'jquery' : 'lib/jquery-2.1.3.min',
'underscore' : 'lib/underscore-min',
'backbone' : 'lib/backbone-min',
'marionette' : 'lib/backbone.marionette.min',
+ 'bootstrap' : '../bootstrap/js/bootstrap.min'
},
// ファイルの依存関係を指定
shim : {
'jquery' : {
exports : '$'
},
'underscore' : {
deps : ['jquery'],
exports : '_'
},
'backbone' : {
deps : ['jquery', 'underscore'],
exports : 'Backbone'
},
'marionette' : {
deps : ['backbone'],
exports : 'Marionette'
},
+ 'bootstrap' : {
+ deps : ['jquery']
+ }
}
};
-
paths
にbootstrapをインストールしたパスを指定-
baseUrl: '/rest-study/js/'
の指定があるので注意
-
-
shim
にbootstrapがjqueryに依存している設定を追加
main.js
require-confis.jsの設定だけだと読み込まれないので、読み込みます。
//開始
console.log('load main');
require([
'marionette',
+ 'bootstrap'
],
function(){
console.log('run main');
require(['app'], function(Application){
console.log('run main2');
window.application = new Application();
});
});
- require関数の引数に、require-configで指定した名前
bootstrap
を指定して読み込みます。
まずはここまでやってみましょう。
-
app/webroot/js/require-config.js
を上記の通り修正。 -
app/webroot/js/main.js
を上記の通り修正。 - 動作確認(まだ何も変わりません。変わらず動くことを確認しましょう)!
HTMLを再デザイン
前回までのhtml(default.ctp)は、「とりあえず表示できれば良い」という最低限のものしか書いていません。
今回、グリッドシステム等を使用するために、HTMLの構造も少し修正します。
そしてメインとなるclassの設定をします。
また、bootstrapのみでなく、自作のスタイルも設定しています。
下記はあくまで一例です。好きなようにデザインしてみましょう!
※一度このままやってみて後で修正するといいかもしれません。
まず、下記default.ctp
内でbootstrap.min.css
の読み込み部分だけ追記してみてください。
これだけですでにデザインが変わっているはずです!
ボタンの見た目が少し変わっている程度ですが、確認しましょう。
default.ctp
今回の修正のメインとなるファイルです。
修正量が多いので、diffでなく全量載せています。
diffはこちらからどうぞ 第8回 実装 · app/View/Layouts/default.ctp
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<!-- Bootstrap CSS -->
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
<!-- Application CSS -->
<link href="css/app.css" rel="stylesheet">
<title>シンプルTODOアプリ</title>
</head>
<body>
<!-- ヘッダ -->
<div id="header" class="container"></div>
<!-- コンテンツ -->
<div id="main" class="container"></div>
<!-- ヘッダのテンプレート -->
<script type="text/template" id="header-template">
<div>
<div class="row header">
<div class="form-group col-xs-12">
<form class="form-inline pull-right">
<label for="logout"><%- username %>(<%- name %>)</label>
<input type="button" class="btn btn-default btn-sm" id="logout" value="ログアウト">
</form>
</div>
</div>
</div>
</script>
<!-- TODO一覧表示のレイアウトテンプレート -->
<script type="text/template" id="todo-layout-template">
<div>
<h1>TODOリスト</h1>
<div id="todo-lists"></div>
</div>
</script>
<!-- TODO一覧表示のテンプレート -->
<script type="text/template" id="todo-composite-template">
<div class="row">
<div class="col-xs-12">
<span class="row form-inline">
<div class="input-group col-sm-6 col-xs-12">
<label for="new-todo" class="visible-xs">Todo</label>
<textarea class="form-control todo-item-text" rows="3" id="new-todo" placeholder="Todo?" autofocus></textarea>
</div>
<div class="input-group col-sm-3 col-xs-12">
<label for="user-list" class="visible-xs">担当者</label>
<select class="form-control" name="assignee" id="user-list"></select>
</div>
<div class="input-group col-sm-3 col-xs-12">
<label class="visible-xs"></label>
<input type="button" id="addTodo" class="btn btn-primary btn-md todo-action-button" value="追加">
</div>
</span>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<table class="table table-striped table-bordered table-hover">
<thead>
<tr class="success">
<th class="col-sm-6" colspan="2">ToDo</th>
<th class="col-sm-2">オーナ</th>
<th class="col-sm-2">担当</th>
<th class="col-sm-2" colspan="2"></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</script>
<!-- TODO一行分のテンプレート(上のtbody部分に挿入される) -->
<script type="text/template" id="todo-item-template">
<td colspan="2">
<div class="checkbox">
<label class="todo-item-text">
<input type="checkbox" class="toggle" <%- status === '1' ? 'checked' : '' %>><%- todo %>
</label>
</div>
</td>
<td>
<span><%- Owner.name %></span>
</td>
<td>
<span><%- Assignee.name %></span>
</td>
<td class="text-center">
<div class="btn-group">
<a class="btn btn-danger remove-link todo-item-button" href="#">削除</a>
</div>
</td>
<td>
<div class="btn-group">
<a class="btn btn-success detail-link todo-item-button" href="#todo-lists/<%- id %>">詳細</a>
</div>
</td>
</script>
<!-- 詳細画面のレイアウトテンプレート -->
<script type="text/template" id="todo-detail-layout-template">
<div id="todo-item" class="container"></div>
</script>
<!-- 詳細画面の表示内容テンプレート -->
<script type="text/template" id="todo-detail-item-template">
<div class="row">
<div class="col-xs-12">
<h2>Todo #<%- id %></h2>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div>
<form role="form">
<div class="row">
<div class="form-group col-sm-6">
<label for="edit-todo">Todo</label>
<textarea class="form-control todo-item-text" rows="6" id="edit-todo" autofocus placeholder="Todo?"><%- todo %></textarea>
</div>
</div>
<div class="row">
<div class="form-group col-sm-3">
<label for="user-list">担当者</label>
<select class="form-control" name="assignee" id="user-list">
</select>
</div>
</div>
<div class="row">
<div class="form-group col-xs-12">
<input type="button" class="btn btn-primary todo-action-button" id="updateTodo" value="更新"></input>
<input type="button" class="btn btn-default todo-action-button" id="updateCancel" value="キャンセル"></input>
</div>
</div>
</form>
</div>
</div>
</div>
</script>
<!-- ログイン画面テンプレート -->
<script type="text/template" id="login-layout-template">
<form role="form">
<h2>ログイン</h2>
<div class="row">
<div class="col-sm-1">
</div>
<div class="form-group col-sm-5">
<label for="username">ユーザ名</label>
<input class="form-control" type="text" id="username" placeholder="username" autofocus></input>
</div>
</div>
<div class="row">
<div class="col-sm-1">
</div>
<div class="form-group col-sm-5">
<label for="password">パスワード</label>
<input class="form-control" type="password" id="password" placeholder="password"></input>
</div>
</div>
<div class="row">
<div class="col-sm-1">
</div>
<div class="form-group col-sm-12">
<input type="button" class="btn btn-success todo-action-button" id="login" value="ログイン"></input>
</div>
</div>
</form>
<form role="form">
<h2>ユーザ登録</h2>
<div class="row">
<div class="col-sm-1">
</div>
<div class="form-group col-sm-5">
<label for="username">ユーザ名</label>
<input class="form-control" type="text" id="signup-username" placeholder="username"></input>
</div>
</div>
<div class="row">
<div class="col-sm-1">
</div>
<div class="form-group col-sm-5">
<label for="password">氏名</label>
<input class="form-control" type="text" id="signup-name" placeholder="name"></input>
</div>
</div>
<div class="row">
<div class="col-sm-1">
</div>
<div class="form-group col-sm-5">
<label for="password">パスワード</label>
<input class="form-control" type="password" id="signup-password" placeholder="password"></input>
</div>
</div>
<div class="row">
<div class="col-sm-1">
</div>
<div class="form-group col-sm-12">
<input type="button" class="btn btn-warning todo-action-button" id="signup" value="登録"></input>
</div>
</div>
</form>
</script>
<!-- require -->
<script type="text/javascript" src="js/require-config.js"></script>
<script type="text/javascript" src="js/lib/require.js" data-main="main.js"></script>
</body>
</html>
- ポイント
-
bootstrap.min.css
を読み込んだ後にapp.css
(独自CSS)を読み込んでいます。- bootstrapで定義されているCSSを一部
app.css
上書きしているため、後で読み込みます。
- bootstrapで定義されているCSSを一部
-
app.css
ではボタンの横幅など、独自CSSを定義しています。 - 随所で「グリッドシステム」を使っています。
-
- 部分的にコピペして、Bootplyで試しながら確認してみましょう。
app.css
/* インラインフォーム内を下寄せ(bootstrap設定上書き) */
@media (min-width: 768px) {
.form-inline .input-group {
display: inline-block;
vertical-align: bottom;
}
}
/* Todo一覧内のボタンの幅 */
.todo-item-button {
width: 70px;
}
/* その他のボタンの幅 */
.todo-action-button {
width: 120px;
}
/* テーブル内全て改行、縦中央寄せ */
.table > tbody > tr > td {
word-break: break-all;
vertical-align: middle;
}
/* Todoのフォントサイズを大きく */
.todo-item-text {
font-size: large;
}
/* ヘッダ部分のレイアウト */
.header {
margin: 5px;
padding: 10px 10px 0px 10px;
background-color: darkslategray;
color: lightcyan;
}
- すべてコメントにあるとおりです
実装
では、実際に修正して画面のデザインを確認をしてみましょう。
-
app/View/Layouts/default.ctp
を上記の通り修正。 -
app/webroot/css/app.css
を上記の通り作成して追加。 - 動作確認!
- Gitにコミット
GitHubでのdiff表示へのリンク
第8回 実装 · suzukishouten-study/rest-study@190c35c
以上です!
次回予告
ダウンロード・アップロード機能の実装 - connpassです。
CSVファイルのアップロードなんかは業務アプリケーションではよく有りますね。
ダウンロードも単なるリンクでなくサーバで生成してダウンロードできるようにします。
次回はサーバ、クライアント両方さわるので結構大変かな!がんばりましょー!
コメント/フィードバックお待ちしております。
参加者の方も、そうでない方もお気づきの点があればお願い致します。