大学生からの Web 開発

会社の人に見つかってぽよぽよしてきた

Masonry を使って要素が重なってしまったときの対処法

f:id:karur4n:20140216172325p:plain

可変のグリッドレイアウトを実現できる JS ライブラリ、 Masonry は非常に便利でお世話になっているのだが、問題が起こって解決したのでメモ。

問題

以下のように、画像をラップしたブロックを Masonry で配置すると画像の高さが反映されずにブロックが重なって表示されてしまう。

<div class="container">
    <div class="item">
        <img src="sample1.jpg">
        <p>hoge</p>
    </div>
    <div class="item">
        <img src="sample2.jpg">
        <p>fuga</p>
    </div>
    <div class="item">
        <img src="sample3.jpg">
        <p>piyo</p>
    </div>
</div>
var container = document.querySelector('.container');
var msnry = new Masonry( container, {
  // options
  columnWidth: 200,
  itemSelector: '.item'
});

解決法

その1 画像の表示サイズが固定の場合

画像の高さを固定して表示する場合は、属性で高さを指定すればよい。

<div class="container">
    <div class="item">
        <img src="sample1.jpg" height="100" width="200">
        <p>hoge</p>
    </div>
    <div class="item">
        <img src="sample2.jpg" height="120" width="200">
        <p>fuga</p>
    </div>
    <div class="item">
        <img src="sample3.jpg" height="500" width="200">
        <p>piyo</p>
    </div>
</div>

だいたいみんな画像にサイズは指定しているのでぶっちゃけこの問題に遭遇することはないと思う。大事なのは次。

その2 画像のサイズを可変にする場合

レスポンシブデザインのために Media Queries で画像のサイズを可変にしたいとする。そうすると上の例のように、属性でサイズを指定することはできない。

この場合は、imagesloaded を使う。これは指定した要素中の画像が読み込み終わったイベントを発火してくれるものだ。

var container = document.querySelector('.container');

imagesLoaded(container, function () {
  var msnry = new Masonry(container, {
    columnWidth: 200,
    itemSelector: '.item'
  });
});

こう書くと Masonry が配置するときには画像のロードが終わっていて高さが取得されているので、要素が重なることはない。

あとはこんな感じで書けば、画像のサイズを可変にできる。

@media screen and (max-width: 1000px) {
  .item img{
    width: 200px;
  }
}
@media screen and (max-width: 760px) {
  .item img{
    width: 150px;
  }
}
@media screen and (max-width: 480px) {
  .item img{
    width: 100px;
  }
}
@media screen and (max-width: 320px) {
  .item img{
    width: 50px;
  }
}

参考

jQuery Masonryを使う際にわりと大事なimagesLoadedプラグイン | WEB SHOWZINE

SlimでAngularJSを扱ってエラーが出たときの対処法

AngularJSが話題になってるのでちょっと触ってみました。で、ruby製のテンプレートエンジン「Slim」を使うと、ちょこっとエラーが出るので対処法を。

ng-app

!DOCTYPE html
html ng-app
head
......

これだとエラーが出ます。slimでng-appと指定するときはng-app=''としましょう。

!DOCTYPE html
html ng-app=''
head
......

{{ }}

データバインディング{{ }}。 これも以下のようにそのまま書いてもエラーが出ます。実装されてる何かしらの{ }とかぶってるんですかね(?)

input type="text" ng-model="name"
{{name}}

これは3つの書き方で回避することができます。まずは

input type="text" ng-model="name"
p
  | {{name}}

|でテキストとして出力することで回避できます。もしくは

input type="text" ng-model="name"
p ng-bind="name"

ng-bindで指定すればOK。

最後に、{ }を区切り文字から外す方法。 Rubyファイルにこう書けばOKっす。

Slim::Engine.default_options[:attr_delims] = {'(' => ')', '[' => ']'}

ただし、slimのもとからの{ }の書き方が使えなくなります。

なので一番いいのは最初の書き方ですかね。

参考

Syntax error when using Angular.js syntax without attributes. · Issue #453 · slim-template/slim · GitHub
GitHub - yuya-matsushima/slim: Slim is a template language whose goal is reduce the syntax to the essential parts without becoming cryptic.

【JavaScript】ユーザ定義関数の引数を省略可能にする

リアルタイム性のあるアプリケーションを作りたいな、と思って「はじめてのNode.js」を読んでます。

で、まあそのへん socket.ioを扱う前の章 「Expressを使ってブログシステムを作ろう」っていう章の一部でつまづいて、そして解決したのでメモ。

つまづいたところ

ユーザ定義関数の引数を省略可能にする記述。

var example = function (count, skip, callback) {
  if ('function' === typeof skip) {
    callback = skip;
    skip = undefined;
  }
  skip = skip | 0;
  ......
  ......
};

定義する関数は、skip番目からcount個分のデータを取り出すっていうもの。省略できるようにする引数はskip

こんなのでつまづくなんて、といったのはまあ察して。

実際に書く時って

この関数使うときはこう書きます。

skipを省略しないとき

example(9, 5, function() {......});

skipを省略するとき

example(9, function() {......});

どういうことかというと

要は省略するとcallbackがskipに入ってるってことです。なので、
if ('function' === typeof skip)
skipの型がfunction、つまり関数のときはskipの内容をcallbackに入れて、skipはundefinedにしておく、と。
もちろん、JavaScriptで型を比較するときは ===(イコール3つ)ですね。

で、skip = skip | 0;ってのがよくわかりません|がビット演算子のORってことは調べたんだけど。
skip = skip || 0; これと同じってことでいいのかな?

まとめ

ともかく

var example = function (count, skip, callback) {
  if ('function' === typeof skip) {
    callback = skip;
    skip = undefined;
  }
  ......
  ......
};

これになぞって書けばユーザ定義関数の引数を省略できますよー、っていう話でした。