新しい日記

新しい日記

デザイン論

この記事は、社内向けに書いたけど、収まりきらなかったので、ブログに載せられるように編集を加えた、私なりのデザイン論についての記事です。

はじめに、私とデザインの関わり

アシスタントエンジニアがなぜこんな話を?と思われるかもしれないのではじめに。
私は大学ではデザイン学科に属しており、また同大学の大学院に進学したためという計6年間のデザイン教育のバックグラウンドがあります。
デザイナーになるつもりで就活をしていましたが、色々あってエンジニアになりました。 今仕事でやっていることはコーディングですが、デザイナーの視点を持って仕事に取り組むように心がけています。(まだまだ未熟ですが)

デザインとは何か

私の考え

先に、私の考えを共有します。 今、私はデザインとは 「統合」 だと考えています。 この単語(または類義語)は近代デザインの歴史を追うにあたり、いくつかの代表的な宣言・定義でも使われており、的を外してはいない観念ではないかと考えています。 いくつか紹介します。

バウハウスの創立宣言

「すべての造形活動の最終目標は建築である!」

これは、バウハウス創立宣言の冒頭文です。 バウハウス初代校長であるグロピウスは、近代化の中でそれぞれ孤立した芸術活動を再び結集し、諸芸術の総合を再建することを理想として掲げました。

トーマス・マルドナードによるインダストリアルデザインの定義

「インダストリアルデザインとは、工業製品の形の質を決定することを究極の目標とするひとつの活動である。ここで形の質というのは、外面的な特徴を指すのではなく、ひとつのモノを生産者並びにユーザから見て、首尾一貫性のある統一体に変えるような、構造的、機能的諸関係のことをいうのである。単なる外面的な特徴というものは、しばしばモノをうわべだけいっそう魅力的にしようとしたり、あるいは、構造上の欠陥を偽り隠そうとする意図の結果であるにすぎず、したがってそれは、モノと共に生まれ、モノと共に成長した現実をあらわすのではなく、偶然的な現実をあらわすにすぎない。これに反して、ここでいうモノの形の質というのは、常になんらかの仕方で形態形成のプロセスに関与する諸要素、つまり機能的、文化的、技術的、経済的諸要素の調整及び統合の結果である。形の質は、内部の組織に対応する現実、つまりモノの共に成長した現実を形作ることなのである。」

デザインすること、デザイナーとは

上述の例などから、私はデザインすることとは 「機能や構造、形態などの統合を設計すること」 であり、デザイナーとはそれを目的としてアウトプットする人のことだと考えています。 それはどんな領域においてもです。 というか、このような統合設計行為のアウトプットが Sketch ファイルだろうが、印刷物だろうが、コードだろうが、物体だろうが、空間だろうが、組織だろうが、なんだろうが(そして優れていれば)、その人は 立派なデザイナーであると私は評価したいと考えます。 そして最初のに帰結しますが、デザイナーが目的としている行動こそがデザイン、つまり 「統合」 だと考えます。

デザイナーと共に働く人々、相互理解

ここからは一旦概念的な話から離れます。

デザイナーのルーツ

ものつくりの中心が手工芸だった時代では、考案する人と作る人が同じであるということが一般的でしたが、産業革命以降では、工業製品の生産は労働者と製品の造形家(プロドゥクトゲシュタルター・今でいうインダストリアルデザイナー)に分業されるようになりました。 これは、ドイツ工作連盟創立当初に建築家のフリッツ・シューマッハが指摘したことですが、現状の Web /アプリデザインでも同じですね。 現代におけるデザイナーのルーツは、ここからでしょう。

皆さんにとっては当たり前だと思いますが、この分業体制においては、それぞれの領域の相互理解、コミュニケーションが非常に重要です。

分業体制を作曲家・演奏家で例えると

かなり噛み砕いた分業体制の例として、作曲家、演奏家の関係を挙げます。 もちろん作曲と演奏を一人でこなす人もいますが、それぞれを別の人が担当するのはごく一般的なことです。

作曲家は上手に演奏できなくてもいいですが、演奏のことを理解した上で楽曲を設計し、楽譜に落とし込むことを求められます。 演奏家は素晴らしい作曲はできなくてもいいですが、楽譜から作曲家の意図を存分に拾い、美しい音色を奏でることを求められます。

例えば、あなたが作曲家だとして、ピアノ作曲の依頼をされたとします。 このとき、もしあなたがピアノという楽器のことや、演奏家がどのように演奏するのかを知らずに作曲はできますでしょうか? ピアノのことをわからずに、演奏者に無理を強いるかもしれない曲を書くことがプロの仕事だと言えますでしょうか?

例えば、あなたが演奏家だとして、ピアノ演奏の依頼をされたとします。 このとき、もしあなたが楽譜をほとんど読めないとしたら、どのように演奏しますか? とりあえずわかる部分だけ弾いて、あとは適当にごまかしておくとしたら、聴衆にその曲は魅力的に伝わるのでしょうか?

勘のいい人はこの例え話を我々の実務に置き換えて想像できると思います。

仕事をする上で、至らない部分があるのは当たり前です。その都度、お互いの足りない部分、間違っている部分を指摘、補い合うことで、統合を作り上げるような関係が、大切なのではないでしょうか。そして、そのようなことができるチームが理想ではないでしょうか。

結論

工業生産が一般化して以来、仕事が分業体制になったため生まれたデザイナーという職業は、機能や構造、形態を統合する力を必要とする。 そのため、デザインとは統合だと私は考える。 実務上、デザイナーは統合を目的としたアウトプットをするというロールを担うが、そのためにはお互いの領域について理解し合い、補い合う関係が理想となる。

思い

7月から転職して新しい会社に入ったんですが、そこにはデザインが好きな人がたくさんいて、デザインの価値を上げることを目的にも掲げていると聞いて入社しました。 だから社内の皆さんもきっとそれぞれ「デザインとは」という問いに対しての答えを持っているんだろうと思います。このような記事を書いたのは、社内の人がどう思っているのかもっと知りたいからで。

そしてもちろん、デザインを掲げた会社であるならそれなりにもその答えがあるのだと思います。もし会社としての考えと私の考えに一致する部分があれば、「機能や構造、形態を統合する力」を持った優れたメンバーが評価されていればいいなと思います。どうなんでしょう?もしそうじゃなかったら悲しいな。

退職

これやりたかったんだよね

f:id:tttttahiti:20160614205658p:plain

2015年4月から新卒としてお世話になっていた現職ですが、6月末に退職することになりました。色々ありましたが、1月になっても内定が出ずふらふらしていた私を拾って色々チャレンジさせてくださったという点では本当に頭が上がりません。ありがとうございました。

7月からは渋谷の会社に勤める予定です。
その節についてお世話になった方々には改めましてお礼申し上げます。
新しい職場についてはまた慣れた頃に追って報告したいと思ってます!


私の退職そして転職についてもしお祝いをしていただけるという方がいらっしゃいましたら、是非以下の欲しいものリストをご活用ください!!!!

Amazon CAPTCHA

なんと、8月には誕生日も控えてますので!ぜひ!遠慮なく!奮ってお祝いの品を送って下さいね!!!!!!プラダのサングラス買ってくれてもよくってよ?よろしくお願いします!!!

クロージャを理解したような気になっていたが…

先日クロージャの説明を求められて、堂々とスコープのことを説明をしてしまい、ウーン…違う…とさせてしまうという出来事がありました。

その場でクロージャの例についてお教え頂き、そのときは「クロージャってそういう意味なのか!」と納得した気になっていたのですが、もう一度自分で試してみたら自分ではクロージャを始めとして javascript の文法など基本的なことでも理解せずに使っている部分がたくさんあることに気付いてしまった。

例に出されたものを自分で試してみた

以下のように、 html 上に .button というボタンが3つあります。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <a href="#" class="button">button</a>
  <a href="#" class="button">button</a>
  <a href="#" class="button">button</a>
  <script src="./scripts.js"></script>
</body>
</html>

ボタンを押すと何番目のボタンなのかを知らせる alert を出したいとします。
そんなとき以下のように書くと、どのボタンを押しても「3」と出てしまいます。

var buttons = document.getElementsByClassName('button');

for(var i=0;i<buttons.length;i++){
  buttons[i].addEventListener('click', function(){
    alert(i);
  });
}

.button がクリックされるとコールバック関数 function(){ ... }; が実行され、i が alert されるということなのですが、クリックするタイミングでは for を回し終わった後なので、 i の値は3になっている。なので、この段階ではどのボタンを押しても3が alert されてしまいます。

ここで、以下のように alertNumber という関数を作成しxi を閉じ込めるように書き換えます。

function alertNumber(num){
  var x = num;
  return function(){
    alert(x);
  };
}
for(var i=0;i<buttons.length;i++){
  buttons[i].addEventListener('click', alertNumber(i));
}

結果は希望どおり、各ボタンのクリックで、「0」「1」「2」を alert するようになります。

これがクロージャらしい。

クロージャの定義は

自分を囲むスコープにある変数を参照できる関数
(引用元: JavaScriptでクロージャ入門。関数はすべてクロージャ? - Qiita

らしい。
確かに、alertNumber では外の変数 i を参照して処理しているな。なんかざっくりしててイマイチピンとこないな〜…

return って何してるんだろう問題

クロージャの作り方はわかったものの、そもそも関数に return function(){ ... } はなぜいるんだという疑問を持ちました。
以下のように、x を宣言してすぐに alert 出しても同じことできるんじゃないの?と。

function alertNumber(num){
  var x = num;
  alert(x);
}
for(var i=0;i<buttons.length;i++){
  buttons[i].addEventListener('click', alertNumber(i));
}

これだと、 ロード後すぐに「0」「1」「2」と alert され、その後はボタンをクリックしても alert が出ない。
オ?!ていうか return ってそもそも何よ。

return 文は関数の実行を終了して、関数の呼び出し元に返す値を指定します。
構文

return [[expression]];

expression
返す式。もし省略されたなら、undefined が代わりに返ります。
(引用元: return - JavaScript | MDN

「いちいち return ってしなきゃいけないもんなの?」と思ってたが、実際のところ、 return が省略された関数は undefined が返ってくる! というだけなのを知らなかっただけだった…。そりゃ、何も返ってこないわけないよな…。

関数の宣言と実行

前述のと近い話ですが、関数の宣言と実行について、タイミングをよくわかってなかったという話…。
そもそも

function alertNumber(num){
  var x = num;
  alert(x);
}
for(var i=0;i<buttons.length;i++){
  buttons[i].addEventListener('click', alertNumber(i));
}

でロード後にすぐ alert が出るというのは、関数を宣言したタイミングで alert が出てるということなんですよね。
言うなれば、ある働きをするロボを作る(function alertNumber(){ ... })→関数を宣言する
作ったロボを使う(return)→関数を実行する
っていうイメージでしょうか。

関数は()がないと値が返ってこない

あと、 alertNumber(100); とすると、返ってくるのは

function (){
    alert(x);
  }

これだけで、alert は出ない。一方で、 alertNumber(100)(); とすると、 100と書かれた alert が出て、さらに undefined が返ってくる。(さっき調べたやつだ)
「きっとこの () を付けることで、関数内の return を呼び出すことがやっとできるのだな〜!そして return 以外のは一度実行されたらもう二度と繰り返されないのだろうな〜?」という感覚的な咀嚼をした。関数の宣言と実行という項目を追加したので先日の感覚的な咀嚼はちょっと間違っていることがわかった。

addEventListener の第二引数に入れるべきものは?

addEventListener のコールバック関数に alertNumber を内包させても同じ結果になるのでは?と思ったので試してみた。

function alertNumber(num){
  var x = num;
  return function(){
    alert(x);
  };
}
for(var i=0;i<buttons.length;i++){
  buttons[i].addEventListener('click', function(){
    alertNumber(i);
  });
}

でも、上述のコードではボタンをクリックしてもなんにも起きない。 これはきっと感覚的な咀嚼をした () の問題だろう。 alertNumber(3); という意味になっていて、alertNumber(3)(); という処理にはなってないのだろう。

以下のようにすると、クリックするたびに alertNumber(3)(); になる。

function alertNumber(num){
  var x = num;
  return function(){
    alert(x);
  };
}
var f = alertNumber(100);
for(var i=0;i<buttons.length;i++){
  buttons[i].addEventListener('click', function(){
    alertNumber(i)();
  });
}

これは想定どおりだな。でも、 addEventListener の第二引数に無名関数っぽいものを入れても返り値がないのはなぜなんだ?!もしかしてこれは関数ではない?!お前は何なのか?!

一方、絶対こいつは関数なんだからなという強い意思を持ち以下のように異常に冗長な書き方をすると希望通りの結果が得られました。

function alertNumber(num){
  var x = num;
  return function(){
    alert(x);
  };
}
for(var i=0;i<buttons.length;i++){
  buttons[i].addEventListener('click', ( function(){
      return alertNumber(i);
    }())
  );
}

絶対こんな書き方したくないな〜

俺の考えた最強の仮説

function alertNumber(num){
  var x = num;
  return function(){
    alert(x);
  };
}
for(var i=0;i<buttons.length;i++){
  buttons[i].addEventListener('click', alertNumber(i));
}

このコードでは、まず buttons[i] のクリックイベントに alertNumber(i) が紐付けられる&宣言される。(ので、ローカル変数 x に そのときの i の値が閉じ込められる)
そして、クリックイベントが発生したときは、再度紐付けられた alertNumber(i) が呼び出されるが、その中の var x = num; は宣言時に処理が終わっているので、閉じ込められた i の値を内包した return の値が返ってくる。

どうでしょう?!私の仮説はどこまで合っているんでしょうか?”!?!?!?!?!?!?!?!!?!?!?!???????

それにしても全然 javascript 理解してないのを露わにしてしまう恥ずかしい記事となってしまいました。
javascript はブラウザさえあればすぐに書いた文字を実行できる手軽な言語ですが、
私みたいなよくわかってないけどとりあえず書いたものが動いてプログラミングは楽しいな!私プログラム書けるといっても過言ではないのでは?みたいな人間を生産することができてしまいますね…。
恐ろしいことに私はこんな感じでもお仕事をしてお給料をもらっていて、ヤバイ以外の語彙を失ってしまいました。
小手先な tips やミーハーな技術情報を追うばかりでなく、基礎的な知識を体系づけて身につけねばと大反省しました!たくさん勉強してプログラム書けるようになるぞ!

sass(scss)の&と変数を利用して親の親であるセレクタを参照する

sass の &(アンパサンド) はとっても便利。
特に BEM やるときは、いちいち block や element を書かずに & で書き足していけばいいのでやりやすい。
例えば以下のようなコードをコンパイルすると

.block{
  display: block;
  &__element{
    display: inline-block;
    &--modifier{
      color: #f00;
    }
  }
}

こうなる。

.block{display:block}
.block__element{display:inline-block}
.block__element--modifier{color:red}

んだけど、BEM かつシングルクラス設計にすると、例えば modifier に block や element 要素のスタイルを @extend したい。
例えばさっきのコードだったら、

.block{display:block}
.block__element{display:inline-block}
.block__element--modifier{display:inline-block,color:red}

となってほしかったりする。
そういうとき、以下みたいにセレクタの名前をいちいち調べて @extend するのはちょっとスマートじゃない。

.block{
  display: block;
  &__element{
    display: inline-block;
    &--modifier{
      @extend .block__element;
      color: #f00;
    }
  }
}

&でうまいことやれないかなと思うけど、&は親の名前なので、以下のようなコードだと意味不明になってしまう。

.block{
  display: block;
  &__element{
    display: inline-block;
    &--modifier{
      @extend #{&}; //@extend .block__element--modifer; になってしまう
      color: #f00;
    }
  }
}

そこで親の親の部分で、 &を変数に格納しておけば、そのあと引き継ぐことができる。

.block{
  display: block;
  &__element{
    display: inline-block;
    $element: #{&};
    &--modifier{
      @extend #{$element};
      color: #f00;
    }
  }
}

これをコンパイルすると以下のようになる。

.block{display:block}
.block__element,.block__element--modifier{display:inline-block}
.block__element--modifier{color:red}

これを応用する場面ですが、例えば @for で回してグリッドを作るとしたら、 コード量が少なく済む。
以下はdisplay: table; 前提のグリッドを任意の block の中で作る mixin のサンプルです。
($parent という命名はいかがなものかと思うが…)

@mixin grids($cols: 12){
  $width: 100/$cols;
  @for $i from 1 through $cols {
    &__#{$i}{
      $parent: #{&};
      box-sizing: border-box;
      display: table-cell;
      padding: 0 5px;
      width: $width*$i+0%;
      &:first-child{
        padding-left: 0;
      }
      &:last-child{
        padding-right: 0;
      }
      &--top{
        @extend #{$parent};
        vertical-align: top;
      }
      &--middle{
        @extend #{$parent};
        vertical-align: middle;
      }
      &--bottom{
        @extend #{$parent};
        vertical-align: bottom;
      }
    }
  }
}

これを .grid という block の中で使うとして、コンパイル

.grid__1,.grid__1--bottom,.grid__1--middle,.grid__1--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:8.33333%}
.grid__1--bottom:first-child,.grid__1--middle:first-child,.grid__1--top:first-child,.grid__1:first-child{padding-left:0}
.grid__1--bottom:last-child,.grid__1--middle:last-child,.grid__1--top:last-child,.grid__1:last-child{padding-right:0}
.grid__1--top{vertic.align:top}
.grid__1--middle{vertic.align:middle}
.grid__1--bottom{vertic.align:bottom}
.grid__2,.grid__2--bottom,.grid__2--middle,.grid__2--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:16.66667%}
.grid__2--bottom:first-child,.grid__2--middle:first-child,.grid__2--top:first-child,.grid__2:first-child{padding-left:0}
.grid__2--bottom:last-child,.grid__2--middle:last-child,.grid__2--top:last-child,.grid__2:last-child{padding-right:0}
.grid__2--top{vertic.align:top}
.grid__2--middle{vertic.align:middle}
.grid__2--bottom{vertic.align:bottom}
.grid__3,.grid__3--bottom,.grid__3--middle,.grid__3--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:25%}
.grid__3--bottom:first-child,.grid__3--middle:first-child,.grid__3--top:first-child,.grid__3:first-child{padding-left:0}
.grid__3--bottom:last-child,.grid__3--middle:last-child,.grid__3--top:last-child,.grid__3:last-child{padding-right:0}
.grid__3--top{vertic.align:top}
.grid__3--middle{vertic.align:middle}
.grid__3--bottom{vertic.align:bottom}
.grid__4,.grid__4--bottom,.grid__4--middle,.grid__4--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:33.33333%}
.grid__4--bottom:first-child,.grid__4--middle:first-child,.grid__4--top:first-child,.grid__4:first-child{padding-left:0}
.grid__4--bottom:last-child,.grid__4--middle:last-child,.grid__4--top:last-child,.grid__4:last-child{padding-right:0}
.grid__4--top{vertic.align:top}
.grid__4--middle{vertic.align:middle}
.grid__4--bottom{vertic.align:bottom}
.grid__5,.grid__5--bottom,.grid__5--middle,.grid__5--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:41.66667%}
.grid__5--bottom:first-child,.grid__5--middle:first-child,.grid__5--top:first-child,.grid__5:first-child{padding-left:0}
.grid__5--bottom:last-child,.grid__5--middle:last-child,.grid__5--top:last-child,.grid__5:last-child{padding-right:0}
.grid__5--top{vertic.align:top}
.grid__5--middle{vertic.align:middle}
.grid__5--bottom{vertic.align:bottom}
.grid__6,.grid__6--bottom,.grid__6--middle,.grid__6--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:50%}
.grid__6--bottom:first-child,.grid__6--middle:first-child,.grid__6--top:first-child,.grid__6:first-child{padding-left:0}
.grid__6--bottom:last-child,.grid__6--middle:last-child,.grid__6--top:last-child,.grid__6:last-child{padding-right:0}
.grid__6--top{vertic.align:top}
.grid__6--middle{vertic.align:middle}
.grid__6--bottom{vertic.align:bottom}
.grid__7,.grid__7--bottom,.grid__7--middle,.grid__7--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:58.33333%}
.grid__7--bottom:first-child,.grid__7--middle:first-child,.grid__7--top:first-child,.grid__7:first-child{padding-left:0}
.grid__7--bottom:last-child,.grid__7--middle:last-child,.grid__7--top:last-child,.grid__7:last-child{padding-right:0}
.grid__7--top{vertic.align:top}
.grid__7--middle{vertic.align:middle}
.grid__7--bottom{vertic.align:bottom}
.grid__8,.grid__8--bottom,.grid__8--middle,.grid__8--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:66.66667%}
.grid__8--bottom:first-child,.grid__8--middle:first-child,.grid__8--top:first-child,.grid__8:first-child{padding-left:0}
.grid__8--bottom:last-child,.grid__8--middle:last-child,.grid__8--top:last-child,.grid__8:last-child{padding-right:0}
.grid__8--top{vertic.align:top}
.grid__8--middle{vertic.align:middle}
.grid__8--bottom{vertic.align:bottom}
.grid__9,.grid__9--bottom,.grid__9--middle,.grid__9--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:75%}
.grid__9--bottom:first-child,.grid__9--middle:first-child,.grid__9--top:first-child,.grid__9:first-child{padding-left:0}
.grid__9--bottom:last-child,.grid__9--middle:last-child,.grid__9--top:last-child,.grid__9:last-child{padding-right:0}
.grid__9--top{vertic.align:top}
.grid__9--middle{vertic.align:middle}
.grid__9--bottom{vertic.align:bottom}
.grid__10,.grid__10--bottom,.grid__10--middle,.grid__10--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:83.33333%}
.grid__10--bottom:first-child,.grid__10--middle:first-child,.grid__10--top:first-child,.grid__10:first-child{padding-left:0}
.grid__10--bottom:last-child,.grid__10--middle:last-child,.grid__10--top:last-child,.grid__10:last-child{padding-right:0}
.grid__10--top{vertic.align:top}
.grid__10--middle{vertic.align:middle}
.grid__10--bottom{vertic.align:bottom}
.grid__11,.grid__11--bottom,.grid__11--middle,.grid__11--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:91.66667%}
.grid__11--bottom:first-child,.grid__11--middle:first-child,.grid__11--top:first-child,.grid__11:first-child{padding-left:0}
.grid__11--bottom:last-child,.grid__11--middle:last-child,.grid__11--top:last-child,.grid__11:last-child{padding-right:0}
.grid__11--top{vertic.align:top}
.grid__11--middle{vertic.align:middle}
.grid__11--bottom{vertic.align:bottom}
.grid__12,.grid__12--bottom,.grid__12--middle,.grid__12--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:100%}
.grid__12--bottom:first-child,.grid__12--middle:first-child,.grid__12--top:first-child,.grid__12:first-child{padding-left:0}
.grid__12--bottom:last-child,.grid__12--middle:last-child,.grid__12--top:last-child,.grid__12:last-child{padding-right:0}
.grid__12--top{vertic.align:top}
.grid__12--middle{vertic.align:middle}
.grid__12--bottom{vertic.align:bottom}

まあ flexbox を使えるなら、こんなグリッド今時作ることないと思いますけどね!!!!!!

例はともかく、親の親を参照するのに変数に格納しておけば、万が一セレクタ名をタイポしてたとか変更しなきゃいけないときもエラーがでなくてラクチンなのでいいことです。

jQuery なしでスムーススクロール実装するときのベストプラクティスがわからない

jQuery で便利なのは offset 系の処理だと思うんだけど、 offset 系の処理で最も頻発するのはスムーススクロールだと思ってる。 とりあえず何秒かごとにターゲットの場所までちょっとずつスクロールしていくだけという雑なコードを書いているんですがうまいやり方を知りたい。スムースにすればするほど重くなってしまう。はやく scroll-behavior が全てのブラウザに搭載されてほしい

雑な上に親なき野良エンジニアなのでベストプラクティスがわかりません。 以下に雑コードを掲載しますのでこうしろとかこういう本を読めとかあったら教えて下さい 間違ってもコピペして使ったりしないでくださいネ…。

var insiteLink = document.getElementsByClassName('insiteLink');
for(var i=0;i<insiteLink.length;i++){
  insiteLink[i].addEventListener('click', function(e){
    e.preventDefault();
    var duration = 400; //何秒かけてスクロールするか
    var frame = 10; //何秒に1度スクロールするか、多いほどカクカクする
    var speed = 0; //速さです
    var href = this.getAttribute('href');
    var target = (href==='#' || href==='' ? 'html' : href.replace('#', ''));
    var targetObj = target==='html' ? document.documentElement : document.getElementById(target);
    var targetRect = targetObj.getBoundingClientRect();
    var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
    var targetTop = targetRect.top + scrollTop;
    var distance = scrollTop - targetTop;
    speed = distance/duration*frame;
    smoothScroll = window.setInterval(function(){
      scrollTop = scrollTop-speed;
      window.scrollTo(0,scrollTop);
    }, frame);
    window.setTimeout(function(){
      clearInterval(smoothScroll);
    }, duration+1);
  });
}

gulp+ejs+json その2

ページの情報を json にまとめておいて、そこから情報を取ってきたり、出力場所をそれぞれのページで変えたりする場合、以下のようなやり方でできる。 meta の一部が違うとか、中身で共通する部分はあるけどそれぞれのページでユニークな部分が多いときに便利。 ただし、jsonData[i].name.html という名前のファイルを予め作っておく必要あり。

おおまかな手順説明

  1. テンプレートになる jsonData[i].name.html を作成
  2. ページ内情報を記述しておく package.json を作成
  3. gulp で ejs テンプレートエンジンで jsonData[i].name.html に package.json の内容を挿入して出力するタスクをページ分作って走らせる

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title><%= pageData.title %></title>
  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
  <meta name="keywords" content="<%= pageData.keywords %>" />
  <meta name="description" content="<%= pageData.description %>" />
  <link rel="stylesheet" href="/css/styles.css">
</head>
<body>
  <h1><%= pageData.title %></h1>
  <p>ページの内容です。</p>
</body>
</html>

pages.json

[
  {
    "url": "hoge/index.html",
    "name": "index",
    "title": "愉快なホームページです", 
    "keywords": "愉快,最高,便利",
    "description": "このホームページには愉快なことがたくさん書いてあります。"
  },
...
]

gulpfile.js

var gulp = require('gulp');
var gulp = require('gulp');
var $ = require('gulp-load-plugins')({
  pattern: ['gulp-*', 'gulp.*'],
  replaceString: /\bgulp[\-.]/
});
var jsonData = require('./_src/templates/pages.json');

var buildSet = [];
jsonData.forEach(function(page, i){
  gulp.task(page.name, function(){
    gulp.src('./_src/templates/'+page.name+'.html')
    .pipe($.plumber())
    .pipe($.ejs({
      pageData: page,
    }))
    .pipe($.rename(page.url))
    .pipe(gulp.dest('./'));
  });
  buildSet.push(page.name);
});

gulp.task('default', ['serve'], function(){
  gulp.watch('./_src/templates/**/*', buildSet);
});

index.html とか pages.json は特に何の変哲もないサンプルなのでここではおいといて。キモは gulpfile.js でのタスクの作り方。

まず、 var buildSet=[]; でビルドタスクをまとめるための配列を作成。 この中に、forEachpages.json にある分だけタスクを作成する。 タスク名は jsonData[i].name から取ってくるのと、gulp.src() からは同名のテンプレートを参照。(gulp-ejs が ver 2 になってから、 何が何でも.html で吐き出す仕様じゃなくなり、元の拡張子が引き継がれるようになったので、+.html です) それぞれのタスク内で pageData に 配列の要素を入れる。 gulp-renamejsonData[i].url にファイル名をリネームして出力。 配列 buildSet にタスク名を追加。 タスクのウォッチは buildSet をタスク対象にしてあげればOK(ただしファイルがたくさんあると全部のビルドがそれぞれ走るのでログが大変よく流れる)

こんなかんじでしょうか!中身がユニークすぎなければ、(値を流し込むだけでいけそうなら)いちいち jsonData[i].name という名前のテンプレートを作らなくても自動生成できるが(ネット上にはそのような情報がたくさんありますね)

今回2ヶ月ぶりの更新と、貧弱なメモブログだけど、1日30~50くらいアクセスがある。 なんかみんな gulp+browserify の記事を見に来てるみたい。みんな browserify 好きだね。

近況ですが、 IE8 を切って jQuery を使わなくてもよくなってきたので、以前より js 書くのが楽しくなってきた。 昨年は IE8 対応で今使ってない tips をかなり身につけてしまったのでよくなかった。週五の仕事に疲れて技術書もほとんど読めてない(まともに読んだのパーフェクト PHP くらいかもしれない) 今年は今後も役立つ技術を中心に学んでいきたい。まずは新しい技術を使っていける環境に身を置きたい。 紹介とか紹介とか紹介とか興味がありまくりなので tttttahiti[at]gmail までお願いします。ポートフォリオの url を送ったりします。 ポートフォリオが見たいだけの野次でも大歓迎です。何卒宜しくお願い致します。

git で画像扱う時の設定

git で画像も管理してて、多数の人(多数の環境)の間で編集しあってると、
編集してない画像ファイルが modifiy 済みみたいな挙動をして、git reset --hard しても元に戻らないみたいなことがある。

さくっと!

.gitattributes

# Autodetect text files
* text=auto

# Force the following filetypes to have unix eols, so Windows does not break them
*.* text eol=lf

# Denote all files that are truly binary and should not be modified
*.png binary
*.jpg binary

テキストファイルは 全部 lf 改行
binary ファイルは git にわかるように指定してあげて謎編集を防ぐ
的な?

小一時間費やしてしまった…