タグ「CSS」が付けられているもの

以前の記事で書いたように、しばらくAngularUIのui-calendarを使っていたのですが、依存ライブラリが多い割りにあまり機能を使ってないので不満でした。

また、昨日の記事で書いたように、jQuery依存はやめたいと思ってました。

他にもいいライブラリはないのかと思って調べたのですが、見つかりません。というのも、どれもUI(CSS)とロジック(JS)がセットになっていてリッチなのです。もっと手軽にできないものでしょうか。

そこで、まずはカレンダーを表示するだけでいいと思って、以前紹介したinkを使って自力でやってみることにしました。

ロジックは、moment.jsを使います。このライブラリは単機能でAPIがきれいでいいです。

最初に完成系のスクリーンショットがこちら。

calscn.png

続いて、コードスニペットを貼り付けておきます。 まず、jadeファイルは次のような感じです。

.ink-grid(ng-controller="CalendarCtrl")
  .column-group.top-space.horizontal-space
    .large-20.content-left
      a(ng-click="updateCalendar(calTable.prevMonth)")
        i.icon-caret-left.icon-large
    .large-60.content-center
      .calendar-title {{calTable.title}}
    .large-20.content-right
      a(ng-click="updateCalendar(calTable.nextMonth)")
        i.icon-caret-right.icon-large
  .column-group.content-center.horizontal-space
    .large-100
      table.ink-table.bordered
        tr
          th æ—¥
          th 月
          th 火
          th æ°´
          th 木
          th 金
          th 土
        tr(ng-repeat="row in calTable.data")
          td(ng-repeat="cell in row", ng-class="{selected: cell.selected}", ng-click="selectCalendar(cell)") {{cell.display}}

ちょっと長いですね。HTMLに変換してなくてすみません。

次にコントローラです、下記。

angular.module('MyApp', []).controller('CalendarCtrl',function($scope, CalendarUtil) {
  $scope.updateCalendar = function(date) {
    $scope.calTable = CalendarUtil.getTableData(date);
  };
  $scope.updateCalendar(new Date());
  $scope.selectCalendar = function(cell) {
    if (cell.date) {
      $scope.calTable.selectedCell.selected = false;
      $scope.calTable.selectedCell = cell;
      $scope.calTable.selectedCell.selected = true;
    }
  };
});

最後に、CalendarUtilです。これも長い。もっと機能が充実したらモジュールとして切り出してもいいかもしれません。

angular.module('MyApp', []).factory('CalendarUtil', function() {
  var dowList = [0, 1, 2, 3, 4, 5, 6];
  function getTableData(selectedDate) {
    var selected = moment(selectedDate);
    var start = selected.clone().startOf('month');
    var end = selected.clone().endOf('month');
    var curr = null;  
    var selectedCell; 
    var data = [];
    for (var j = 0; j < 5; j++) {
      var row = [];   
      for (var i = 0; i < dowList.length; i++) {
        var dow = dowList[i];
        if (end) {
          if (!curr && dow === start.day()) {
            curr = start;
          }
          if (curr) { 
            var cell = {
              display: curr.date(),
              date: curr.clone().toDate(),
              selected: curr.isSame(selected, 'day')
            };
            row.push(cell);
            if (cell.selected) {
              selectedCell = cell;
            }
            if (curr.isSame(end, 'day')) {
              end = null;
            } else {  
              curr.add(1, 'days');
            }
          } else {
            row.push({});
          }
        } else {
          row.push({});
        }
      }
      data.push(row); 
    }
    return {
      title: selected.format('YYYY年MM月'),
      data: data,
      selectedCell: selectedCell,
      nextMonth: selected.clone().startOf('month').add(1, 'months').toDate(),
      prevMonth: selected.clone().startOf('month').subtract(1, 'months').toDate()
    };
  }
  return {
    getTableData: getTableData
  };
});

なんか読みにくいコードですね。もっとシンプルにしたいです。条件分岐が多すぎるような気がします。

こんな感じでできました。同様の機能をjQueryでやったらどうなるのかはちょっと気になります。あまりコード量は変わらないような気もしますね。でも、全体をangularで作るならこの方がいろいろ拡張しやすいと思います。

普段、Webアプリを開発するときはPCでChromeやFirefoxを使うのですが、その後iPhoneのMobile Safariで表示させると、Chromeと比べてレイアウトがずれることがありました。

ボックスの高さをemで指定してもそれに収まる行数が変わってしまうのでなぜかと思っていたのですが、やっと分かりました。

行間のデフォルト値が違うんですね。まあ、当たり前というかなんと言うか。 というわけで、CSSでline-heightを指定することで解決しました。

以前紹介した、 InkというCSSフレームワークを使ってたのですが、<p>を使うとline-heightが指定されるので、気付くまでに時間がかかりました。<div>で書いていたところだけサイズが違っていたので。

それだけですが、備忘メモとして残しておきます。

Bootstrapもいいのですが、ちょっと巨大すぎるので、代替品がないかなと思って探しました。

要件は、

  • スマホでも使えるようにレスポンシブ対応
  • あまりできることは多くなくてよい、ボタンとかフォームとかの見た目がきれいになればよい
  • できれば、CSSだけでJavaScript不要のフレームワークがよい

といったところです。

色々探しましたが、有名どころでJavaScript不要と言う要件を満たすものはあまりなく、結局見つけたのがこれです。

レスポンシブ対応のサイトをサクッと作れるフレームワーク『InK』

http://ink.sapo.pt/

この「InK」というネーミングですが、何が困るって、検索キーワードとして使えないことです。Google検索すると、"do you mean link?"とかなってしまう。そんなわけで、使用感などのレポートが見つからなかったです。どれだけ有名なのかもよく分かりません。

また、日本だと、

http://d.hatena.ne.jp/keyword/InK

と混同しそうです。

さて、話を戻すと、Inkは要件を満たしています。全体的な設計がシンプルで、CSSだけで構成されていていい感じです。早速ちょっと使ってみて感じたのは、レイアウトの指定が面白いということです。Bootstrapだと12 spanでfixedとfluidがありますが、Inkだとパーセント指定です。また、fixedはなくてfluidだけのようです(未確認)。fixedも使いたいケースがあるので、それは残念なところです。で、面白いのは、「Multiple Layouts」というレイアウトの指定方法です。これは、CSSのメディアクエリを3通り用意して、それぞれのレイアウトをCSSのクラス指定で定義するのです。

うまく説明できないので、サンプルを。

<div class="ink-l50 ink-m50 ink-s100">
  エリア1
</div>
<div class="ink-l50 ink-m50 ink-s100">
  エリア2
</div>

このようにすると、大画面と中画面では、エリア1とエリア2が横に並んで2カラムのレイアウトになり、スマホなどの小画面では、エリア1とエリア2が縦に並んで1カラムのレイアウトになります。ちなみに、大画面、中画面、小画面が、それぞれ、"l", "m", "s"に対応します。

あと、Bootstrapで困っていたレイアウト時のスペース追加も、Inkではink-vspaceとink-gutterで解決しそうです。もっとも、細かい制御をするときは結局CSSを書くことになりそうですが。

とりあえずは、レイアウトだけ試して満足しました。