Code

2014年12月31日水曜日

擬似要素 (pseudo element) の取得

 IE 8 から、擬似要素がサポートされて、現在すべてのブラウザーがサポートされるようになりました。:before や, :after を使えば、DOM Tree は時に綺麗になることがあります。例えば、アイコンをある要素の前に挿入した場合、通常 <i> 要素を入れるか、background-image を使って、padding を追加する方法がありますが、擬似要素の :before の content に url(xxxx) を入れると、background-image と同じ効果になります。そうすると、余計なことをしなくて、単純にそのアイコンを操作することができます。
 昨日、サイトに :before 要素を javascript で取得して、操作しようとのケースがありました。擬似要素をどのように javascript で取得するかを調べてみました。メモしておきます。
    window.getComputedStyle(element, ':before')
 content attribute を取得する場合、上記で取得したスタイルの後ろに .content を追加すれば、取得できます。
 また擬似要素の content に複数文字列を表示したい場合、単純に
  el:before {
        content: "Num" counter(item) "."
    }
 のようにリストすればいいです。

 CSS にこのような擬似要素を使えば、いろんな面白い効果ができます。例えば:
 CSS icons
 また、今流行っている font graphic を使えば、例えば、
 Font Awesome
 このように、フォントを使えば、font-size を使えば、大きさも調整できるし、Retina の hi-res のスクリーンも難なく対応できます。SVG より、こっちのほうが使い易いと思います。
 それでは。

2014年12月2日火曜日

スクリプットタグでのテンプレート問題

 最近、IE 8 で Bad HTML の解釈が他のブラウザーと違ってて、プログラムが動かなくなったことが発見しました。
 基本的に、あってはいけないことですが、<script></script> の中に、他の <script> tag が定義されて、W3C の標準に違反になりますが、ブラウザーは自分の解釈で実行できてますけど、どうやら、この場合、IE 8 だけ、</div> が追加されるそうです。。。
 
 W3C の標準とブラウザーの実装は基本的に同じですので、</script> という close tag を探して、script の終了をわかるようになります。もし <script> の中に他の <script> tag を入れたら、このルールが破れますので、どのように実行するかはブラウザーに任せます。。。
 これで、最新のブラウザー (IE9 ~) は問題なく、正確な HTML と同じように解釈しますけど、 IE8 は独自のルールに従います。。。

 まぁ、IE 8 の使用率はもう 2% 以下だから、直さなくてもいいと思います。
 それでは。

2014年11月20日木曜日

IE 11 userAgent 変更

 今日、隣のチームが変なバグを遭遇しました。一般的には IE8 では動かないバグがよくありますが、今回は IE11 で editor が動かなくなりました。具体的に言うと、chrome などのブラウザーでは、rich text editor が自動的に生成されますが、IE 11 では普通の textarea になっていました。
 ちょっと調べてみたら、なぜか、iframe が生成されるコードが実行しなくなりました。もう少し確認したら、IE 11 はサポートブラザー外になりました。
 コードを追ってみると、userAgent を取得して、"MSIE" をチェックして、IE のバージョンを確認する処理がありました。IE 11 では MSIE という文字列がなくなったことが発見しました。
 へ〜、本当に起こりました。。。こういうことは。
 以前予想していましたが、実際起こるのですね。userAgent でブラウザーを判断することはよくないと以前から話してましたが、まだいろいろライブラリーがそれを使ってますね。。。
 まぁ、ブラウザーの userAgent は相変わらずごちゃごちゃですけど。。。

 今回は rv:11.0 からバージョンは取得できるので、それをコードに追加して、うまくいきました。。。ただ、他のスクリプットエラーが出て。。。
 x-ua-compatible を EmulateIE9 に追加したら、実行できました。。。
 なんでだろうね。。。

 MS も IE 11 をおしているようです。面白いサイトです:
 http://www.rethinkie.com/hello-again/#/intro

2014年11月9日日曜日

protractor コマンドラインと補助ツール

 基本的に、protractor の config js ファイルにあるものはそのままコマンドラインにパラメーターを書けば、上書きできます。常用のものは
   --baseUrl="NEW URL"  <- これでテスト対象の URL が変更できます。テストケースの中に browser.baseUrl から取得可能です。
   --params.xxx.xxx=NEW VALUE <- もし、config js に pramas フィールドが追加されるなら、params の値を送れば、NEW VALUE が適用されます。

 もし、一つだけのテストケースを実行したいなら、
  --suites=SUITE NAME
  --specs=TEST CASE FILE NAME
 で、ターゲットスイート、テストケースファイルが実行できます。複数実行したい場合、 コマで区切れば、protractor がそのまま実行できます。
 
 テスト結果のレポートは HTML バージョンは下記のライブラリをつかれば、簡単につくれます。スクリーンショット付きで。
package/protractor-html-screenshot-reporter

  config js ファイルの onprepare 関数に Jasmine の reporter を設定すれば、自動でフォルダに HTML と画面キャプチャーが作成されます。

 あと、selenium sever をサーバーのものを使いたいなら、
  --seleniumAddress を使えば、どこかのサーバーアドレスに設定できます。localhost じゃなくて。
 注意すべきところは、リモートサーバーを使いたいなら、タイムアウト時間をちょっと長めに設定したほうがいいです。
 これも Jasmine のものと合わせて、config js ファイルに
  allScriptsTimeout: 30000 <- WebDriver の script タイムアウト時間を 30 秒に設定
  jasmineNodeOpts: {defaultTimeoutInterval: 30000} <- Jasmine timeout を 30秒に設定
 あと、ページタイムアウト、これを browser.get(url, time) 第二の引数に設定するも可能です。
  getPageTimeout:30000

 どのブラウザーでテストするには、capabilities, multi-capabilities で設定できるので、注意は一つ。
 IE の場合、IEDriver の問題で 64bit が超遅いです。IE 11も対応してないので、IE10 + 32bit driver を使えば、回避できます。
 
 record&play ツールとして、firefox には selenium builder を使えば、protractor js フォーマットのテストケースはそのままできますので。活用すれば、時間の節約に。
 selenium builder
 ただ、できたケースはコードはあまり良くないし、select には作成できないので、これを locator の element(by.options()), by.repeater で自分で書くしかないです。

 それでは、また。

ローカル Web App : AngularJS + ExpressJS + Node.js

 先週、検証チームから依頼があって、protractor を UI で動くようにしたいと。確かに、コマンドラインはちょっと使いづらいので。慣れてる人は、それでいいかもしれないけど、テスターはやはり、もうちょっとビジュアル的な UI や、テストケースレポートが欲しがるようです。
 いろいろ考えてみると、protractor も Node.js で動かしているので、そのまま Node を使えるなら、HTML 5 の Web App を作れば、簡単に UI ができるし、NodeJS の力を使って、コマンドラインを実行すれば、早くできると思われました。
 実際調べて見たら、Express.js と Hapi.js みたいなライブラリーがあって、web server もすぐ立てられそうです。また将来、コードをそのまま使って、どこかのサーバに置いたら、同じ UI で、すぐ Online できるので、メリットが大きいです。
 それで、AngularJS を Front End で、Express.js を Back End にして、ツールを作ることになりました。インストールは npm で済ませて、Yeoman, bower で AngularJS のアップを作って、grunt でビルドなども立てて、すぐ開発に入りました。
 Express.js に generator がついてるので、それを使って、Back End のアプリも簡単に立ち上がりました。
    $ npm install express-generator -g
  $ express myapp
  下記のフォルダストラクチャーができました。app.js に path に基づいて、get, post などを書けば簡単には response 作れるようになります。static ファイルを front end に送るには、 sendfi le 関数を使えば、protractor のテスト結果レポートも簡単に Front End で表示できる。
.
├── app.js
├── bin
│   └── www
├── package.json
├── public
│   ├── images
│   ├── javascripts
│   └── stylesheets
│       └── style.css
├── routes
│   ├── index.js
│   └── users.js
└── views
    ├── error.jade
    ├── index.jade
    └── layout.jade

7 directories, 9 files

さらに、もし興味があれば、 MEAN.js というライブラリがあるので
mean.js
MangoDBをデータベースとして、フル JavaScript のアプリも簡単につくれます。
Meteor も有名です。そのまま iPhone, Android アプリも作れるので、どんどん良くなっています。

それでは。

2014年10月31日金曜日

IE8 AngularJS & jQuery ui - problem -> ng-non-bindable の使い方

 昨日、隣のチームから変なバグが聞かれました。具体的に、jQuery ui の datepicker が IE8 では動かなくなった。まぁ、最新版の AngularJS は IE8 サポートしてないから、問題ないけど、今のプロジェクトでは 1.0.8 を使ってるし、IE8 もサポート対象ブラウザーなので。。。あ〜頭が痛くなる。。。
 jQuery の datepicker のサープルを IE8 で開いて、動きは正しいようです。多分、AngularJS と jQuery ui の間に何か干渉が起きたと思われました。HTML を見てみたら、各日付の <td> tag 中の <a> に <!-- IE fix --> コメントが追加されたことが気づきました。AngularJS には <a> tag を IE8 での特別処理が入ってるようです。
       // add a comment node to anchors to workaround IE bug that causes element content to be reset
      // to new attribute content if attribute is updated with value containing @ and element also
      // contains value with @
      // see issue #1949

つまり、AngularJS は上記の IE fix コメントを追加したのです。一般的なライブラリは innerHTML を使って、タグの内容を取得すると、その IE fix も一緒に取得されるのです。parseInt などを使うと、エクセプションが throw されます。本来数字のみ入っている場所に他の文字列が入ったので、何か起きると、不思議ではない。
 
 もう少し調べてみたら、Angular は ng-non-bindable という directive を提供しています。これを使うと、 Angular は HTML DOM をスキャンする時、そのブロックをスキップさせます。つまりその中にある要素は Angular の $digest サイクルに入らない。
 これで、Angular は勝手に <a> tag 何かを入れることがなくなります。問題解決。

 今後 IE 8 をサポートしている間、気をつけないと。
 それでは。

2014年10月18日土曜日

Protractor での自動テスト

 先週から、検証チームを助けて、Protractor での自動テストが始めました。先日ダウンロードして、インストールしようと思ったんですけど、npm がなぜかshanum エラーが出ました。調べたら、ネットワークのせいかもしれないと、もう一回インストールして、無事成功しました。
 Protractor を動かすには、まず Selenium サーバーを起動して、config ファイルにそのアドレスと、spec の場所を入れて、後、Jasmine sytax での spec が必要です。
 Protractor とともに、webdriver-manager と言う Node のコマンドがインストールされます。webdriver-manager update を実行すると、google から chromedriver.exe, IEserverdriver.exeと、Selenium jar ファイルがダウンロードされます。その後、webdriver-manager start で selenium サーバーが起動されます。Jetty なんちゃら 4444 がコンソールに表示されたら、起動成功。
 その後、config に下記の JSON を記入して、spec を書いて、すぐ実行できるようになります。
exports.config = {
  seleniumAddress: 'http://localhost:4444/wd/hub',
  specs: ['todo-spec.js']
};
spec のサンプル:
describe('angularjs homepage todo list', function() {
  it('should add a todo', function() {
    browser.get('http://www.angularjs.org');

    element(by.model('todoText')).sendKeys('write a protractor test');
    element(by.css('[value="add"]')).click();

    var todoList = element.all(by.repeater('todo in todos'));
    expect(todoList.count()).toEqual(3); browser.sleep(3000);
    expect(todoList.get(2).getText()).toEqual('write a protractor test');
  });
});
protractor conf.js を実行すれば、angular のウェブページが表示されて、TODO に自動的に一つアイテムを追加されて、その後、 TODO の数をチェックして、終了。

 注意すべきところは、protractor は selenium のラッバーみたいなもので、AngularJS 終了を待ってから、コマンドを実行してます。(おそらく、Angular の phase をチェックしてるかもしれない)、もし、ウェブページに Angular がなければ、変なエラーが出るのです。原因は protractor ずっと待ってて、待ち続けて、タイムアウトになります。
 このとき、browser.get や element などが使えなくなります。browser.driver を使うべきです。browser.driver は webdriver js で、findElement などが使えます。この時、適当に sleep を入れて、JS の実行完了や、ajax の実行などを自分でまつ必要になります。。。
 やはり、protractor が使いやすいですね。
 
 後日、また続きを。それでは。

Android WebView の 動画が遅い件

 先日、新しい Ads のパフォーマンスが良くないなと思っただけで、今日は他のチームも発見して、相談されました。具体的には WebView を使って、HTML ファイルを表示してますが、画像では iOS, Android 両方問題なく、良く表示されてますが、動画の場合、ある Android 機器が超遅くて、遅くて、使い物になれないほどです。
 実際、Web Inspect で見てみると、JS の実行が遅いです。じゃ、 CSS ではどうでしょうと思って、ほぼすべてのコードを書き換えて、CSS でアニメーションを実現して、試しました。。。でも、遅いです。。。CSSの場合、ハードウェアの加速があるので、速いと言われていますが、Android ではそうではないそうです。まぁ、機器のスペクもよるので、Nexus 5 で試しましたが、iOS ほどスムーズではないですが、そこそこ動いています。
 こう見ると、多分古い Android 機器はだめみたいです。。。何でだろうと思って、やはり WebView はブラウザーより遅くて、開発時は注意しないと。
 一応メモして、将来何か参考になるかもしれないです。
 それでは。

2014年9月27日土曜日

モバイルでは viewport 設定

 先週、作ってるサイトがバグ見つかった。問題は non-responsive のページは一画面に全部表示されなかったことです。期待としては responsive ページはそのまま表示、non-responsive ページは縮小して、一画面に収まれるようになることです。
 調べてみたら、viewport の設定に問題があった。今のプロジェクトでは、responsive ページとnon-reesponsive ページは C# の属性を標識して、render engine で違う viewport を設定します。
 viewport と言えば、携帯のピクセルは実際ページのどのぐらい当てるかの設定です。例えば、viewport の width を 800 に設定したら、携帯のスクリーンは 800 pixel となります。もしサイトの横サイズは 800 だったら、ちょうど一画面に収まれます。1024 に設定したら、800 pixel サイズのサイトはちょっと小さく表示されます。
 一般的には responsive サイト、またはそのサイズのままで表示したい場合、 width を device-width を設定すれば良いです。これで、ディバイスの横幅をそのまま使われます。また、サイトを小さくしたい場合、init-scale を小さくすれば良いです。それに、minmum-scale, maximum-scale でサイトの拡大と縮小倍率はコントロールできます。user-scalable でユーザがサイトピンチで拡大できるかどうか設定できます(yes or no).

 今回の問題は width を 800 に設定したら、initial-scale も 1.0 に設定したからです。これで、width は正しく 800 になっても、サイトのイニシャルスケールは 1.0 つまり、サイトはどのぐらい大きいか、もうそのまま表示されます。つまり、width の設定が上書きされました。今後注意しましょう。

 ちなみに、古いバージョンの iPhone または Android のデフォルトブラウザーでは、width を指定した後、scale を指定すると、viewport が効かないようになりますので、ご注意ください。つまり、content="width=1024, user-scalable=no" は動きますが、content="width=1024, maximum-scalable=2" は動かないです。

 後、Android と iOS の古いバージョンでは、viewport を正しく解釈できないことが発見しました。多分 CSS の影響だと思いますが。。。
 最新の Chrome (Android) をダウンロードして、チェックしてよいです。iOS なら、できるだけ、iOS 7を使いましょう。iOS 6 の Safari はまだまだバグがあります。特に、transform に関して、正しく表示できない時があります。

 それでは。

2014年9月19日金曜日

リターンキーでフォーム Submit

 昨日、変なバグが見つかった:ある input text にフォーカスを押して、リターンキーをクリックしたら、画面が更新されました。。。何でだろうと思った。。。
 実際見てみると、input は form タグの中にあるので、フォームの action は "#" と書かれています。# だと、自分のアドレスに submit されますので。。。でも input は text type だし、submit タイプではないから、何で submit がトリッガーしただろう??
 調べてみたら、もし Form の中に input text が一つだけある場合、リターンキーを押すだけで、 form が submit されます。これはブラウザーの固有動作です。しかも IE 5 からあります。
 また、IE から変な動作を継承したな〜と思いました。
 直す方法としては form の action を削除するか、display : none の input text をもう一個追加するです。
 将来のブラウザーはこれを直さないだろう。メモしておこう。

 それでは。

2014年9月8日月曜日

Angularjs $timeout 調べ

 DI (Dependency Injection) は Javaや、ASP.NET などバックエンドには人気ですけど、AngularJS はそれを JavaScript に応用できるようにしました。具体的に言うと、モジュールをロードするときや、関数を呼び出す場合、$injector の invoke 関数で、呼び出す対象の引数を全部パースして、providerと instance キャッシュの中に探して行く、もし同じ名前の対象があったら、それを使います。
 さらに、Ajax call を実行するとき、$http と $httpBackend を利用することで、$browser も内部で持つことで、すべての操作をライブラリ内部で intercept できるようになります。
 この中に、面白いのは $timeout というものです。実際の timeout 関数は既にあるのに、何で $timeout を実装するのか?
 理由としては、二つあります。まずは Unit test を書くとき、自分で timeout をトリッガーできるようになります。実際のコードを見ると、promise を使っていますが、promise の中には、window.timeout 関数が使われています。これで timeout を同じ機能が実行できるようになります。さらに、もし外部で同じ promise を resolve したら、同じ関数が呼ばれますので、timeout 発生時と同じ動作になります。これはかなりいいことです。もう timeout を待つ必要がなくなります。
 もう一つは Angular Scope の $digest に関係あります。$timeout の中に $rootScope.apply() が呼ばれています。これを理解するには JavaScript 実行のサイクルを理解する必要があります。以前では setTimeout(function() {}, 0) を呼び出すことで、今までの JavaScript コールスタックをすべてクリアした後に、コードを実行する方法があります。$timeout も同じです。AngularJS に自分のサイクル、いわゆる $digest がありますの、この関数ですべての watcher を oldValue, newValue を計算して、listener をその後呼び出します。一つのサイクルを終わらないと、Angular は対象の変更が察知できないことがあります。例えば、ng-include でテンプレートの path を変更したい場合、関数の中に
    /* templateUrl の値は abc とします。*/
    templateUrl = "";
    /* その他の操作*/
    templateUrl = "abc"; // テンプレートをリロードしたい
をやると、$digest はこの関数終わった後に実行されますので、templateUrl は変更してないように見えます。つまり、変数の変更をAngularJS に察知させる為に、一つの $digest サイクルの終わりを待つ必要があります。このとき、$timeout は利用すれば、ちゃんと意図通りできます。
     templateUrl = "";
     /* 他の操作 */
     $timeout(function() {templateUrl = "abc"})
これで、最初の templateUrl がクリアされて、$digest の実行で、ng-include directive がクリアされます。その後、次の $digest サイクルで、templateUrl がまた元に戻したので、すべての expression がもう一度更新されます。
 もちろん、自分で setTimeout を実行して、scope.apply() を呼び出しても、同じ機能ができますの、そのショートカットとして、$timeout を使えば、簡単になります。
 
 まぁ、dirty check にはいろいろ不利なところもありますが、Knockout.js の set 関数を比べると、自分は Angular のほう好きです。
 最近、このライブラリも人気だそうです:
    durandal
   このライブラリは require.js を使っていますので、Angular でできない遅延ロードもできます。聞いたことですが、テンプレートのほうも Angular よりちょっとだけ優れています。
 まぁ、これらは Angular 2.0 で改善される予定なので、少し待ってもいいような気がしますけど。
 
 それでは。

2014年8月27日水曜日

Angular Scope 外の HTML を Angular Scope に入れる

 最近、ある旧 Page を Angular を使っている新しい Page に入れたかったのですが、Angular の Bootstrap は HTML を入れる前に行われていて、Scope が使われてないことがありました。
 まぁ、解決にはそんなに難しくないですが、解決のプロセスが面白いから、メモしておこう。
 まず、angular.element を取得します。その後、injector を取得して、$compile を変数に保存します。
     var compile = angular.element(ele).injector().get("$compile")
     これで、$compileProvider で作成した $compile 関数が取得できました。
 その後、HTML String を $compile に当てて、Scope を利用して、リンクした HTML を該当場所に入れます。
 compile(angular.element(ele).scope())
    最後に、Scope の $digest を呼び出すために、$apply() 関数を呼び出す。終わり。

 Angular は自分の実行サイクルがあるので、その外で生成した HTML はそのサイクルに入らないので、これを入れるために $apply を利用します。ーーまたは $timeout を使います。(実際、$timeout の中に $rootScope.$apply() が呼び出されています。)

 短くいうと、HTML String を Angular の世界に入れるため、$compile を使います。$compile 関数は Link 関数を返しますので、link はある Scope をベースに実際の Angular の世界に入る HTML String を返されます。その後、$apply で $digest を呼び出して、一回 Angular の世界をリフレッシュします。
 
 愚痴:1.0.8 に ng-if がないので、作ろうかなと思ってますけど、、、否決されました。しばらく ng-switch を使う予定です。1.2 を使いたいな〜。

2014年8月7日木曜日

iOS 7 Safari リンク 2回クリック問題

 今日新しい問題を発見しました。以前はこのようなサイトを作ってなかったから、わからなかったが、iOS 7 から :hover クラスの中に display と visibility があれば、一回目の touch は hover 状態にして、2回目のタッチは実際のリンクに行きます。。。
 調べてみたら、どうやら iOS 7 からいろいろ変わってきました。
  ios-has-a-hover-problem
 
 具体的に言うと、以前の Touch Device では、:hover クラスを無視しましたが、iOS 7 からは
   div span {display:none}
   div:hover span {display: block}
みたいな動作を見逃さないように、一回目のタッチを :hover にして、つまり span を表示させて、このとき、click イベントがトリッガーしません。2回目のタッチで、click になります。。。
 これは困ったな〜
 ネットでは :hover を no-touch クラスをつけて、タッチデバイスではなければ、no-touch を外すという直す方法がありますが、個人では、display:none の要素を opacity で隠したりしたほうがいいかもしれません。
 まぁ、まだいろいろ試しているところ。。。また後日追記します。
 それでは。

2014年7月26日土曜日

cross-browser IE8 ボタン クリック問題

 最近仕事が変わりましたので、IE8 も対応ブラウザになりました。。。
 以前から、出て来た IE8 ボタンのクリック問題をまとめておきます。
1 まずは、radio ボタンをクリックしたら、何か動作を自動的に実行する場合、IE8 だと、クリックだけでは onchange イベントハンドラーが呼び出されない。これは、radio ボタンを focus を失うとき、onchange が trigger されます。。。まぁ、理解できますけど。。。
 直し方としては、radio ボタンにもう一個の onclick イベントハンドラーをバインドします。そのイベントハンドラーに
    $("radio button の selector").focus().blur()
を実行します。これで、onchange が自動的に呼ばれるようになります。

2 display:none のボタンの label をクリックしても、ボタンの状態が変わらない。。。
 これは display:none だから。直す方法が二つあります。display:none をやめて、opacity を 0 に設定したり、position を absolute に設定して、top: -9999px, left:-9999px を設定したりすることで、ボタン要素が見えないが、label のクリックは効くようになります。
 もう一つは Label に click ハンドラーをバインドして、もし label が click したら、for attribute で設定したボタンの click 関数を呼び出します。

 それでは。

2014年7月24日木曜日

WCF + Angular で Sever と Client の Decouple

 最近、C# ASP.NET に突入。Back end は C# ASP.NET で、Front End は主に AngularJS を使います。以前 Microsoft の Web Application サンプルはほとんど knockout.js を使っていたため、古いシステムはほとんどそれでした。が、AngularJS から Dependency Injection などのデザインパタンが導入されて、Unit Test や End to End Test が簡単にできるようになったので、だんだん AngularJS に移行する動きがあります。
 今のプロジェクトも移行中です。新しい Web Site は全部 Responsive Design を使っていて、AngularJS ベースに作っています。ただ、やはり cshtml の中に C# Razor のコードと HTML コードがごちゃごちゃになって、みにくいです。それで、WCF を使って、JSON オブジェクトを Front End に返して、View に関してのすべてのロジックは AngularJS をベースに JavaScript で実装することはいいような気がしてます。
 まず、Action を WCF の End Point に変更して、Model はそんなに大きくないので、$http を使って、AJAX でロードして、その後、もう Front End の世界です。新しいブラウザだと、もっと速いような気がしています。サーバーの負荷を考えると、もっと低いような気がしてます。なぜなら、View の parse が必要なくなり、すべて C# コードになるからです。 Ajax コールが多くなりますが、データを組み立てるだけなら、全然軽いと思います。
 Front End でも、Dependency Injection を使っているので、サーバーと隔離するできるし、サーバー側もデータをメインでテストできるから、すべてはスムーズに分けるようになります。Decouple も MVC だけでなく、Server と Client の間でもできるようになります。
 これは多分いいことです。次回の会議でちゃんと話しましょう。
 それでは。

2014年7月19日土曜日

画像を真ん中にする -> CSS or JavaScript

 以前発覚した一つの問題ですが、タブレットで Ads の画像をスクリーンの真ん中にできるだけ大きく表示するには、CSS でやるか、JavaScript で動的に設定するか。。。
 CSS の場合、下記のように HTML を書いて
  <div id="container">
    <div id="wrapper">
        <div>何かのコンテンツ or img タグ</div>
 </div>
  </div>
  #container には {display: table; height:100%; margin: 0 auto;} を設定して、#wrapper に {display: table-cell; vertical-align: middle; } スタイルを設定すれば、真ん中に表示されるはずです。-> Body の height も 100% に設定する必要がある。
    サンプル
 画像の場合、さらに width と height を設定する必要があるが、基本的に width を 100% にして、height を auto に設定すれば、同じ ratio で表示される。
 
 ただ、タブレットだから、orientation を変更する場合、height に合わせる場合があるので、考えた結果、JavaScript で画像の naturalWidth と naturalHeight を取得して、スクリーンサイズを比較すれば、naturalWidth / width, naturalHeight /  height の大きい方に合わせて、さらに position を relative に設定して、top と left を (width - img.offsetWidth) / 2 , (height - img.offsetHeight) / 2 に設定する必要がある。もちろん body の width と height は 100% を設定する必要がある。

 実際比べてみれば、多分 JavaScript のほうがやりやすいと思う。処理は簡単だから、jQuery を使う必要もないし、全部 native の JS で実現できる。
 注意すべきところは Android は resize で、iOS は orientationchange イベントをそれぞれハンドラーをアタッチする。
 var eventStr = navigator.userAgent.match(/iPhone|iPad|iPod/i) ? 'orientationchange' : 'resize';

 それでは。

2014年7月15日火曜日

AngularJS Scope と $apply

 今日時間ができたので、Angular の動きをちょっと追ってみました。module の登録は一つの難しいところですし、injector という概念も難しいと思います。ただ、実際使うとき、Scope というのはかなり重要です。
 基本的にAngularJS は Compile 段階で、必要に応じて、Scope を作ります。さらに ng-scope というクラスを該当要素に追加されます。Scope を取得するには、angular.element(el).scope() で scope object が取得できます。ng-app の要素に対して、rootscope が作られます。
 Scope は一つの object ですので、その prototype 中に、$apply という関数はあります。これはどういうとき使うかというと、Angular の世界に何かイベントを引き起こす時使います。イベントを引き起こすというのは model を変更したり、メッセージを $emit, $broadcast したりする場合です。
 さらに遡ると、JavaScript の中に、イベントハンドラーは、jQuery の proxy などの bind 関数を使わない限り、基本的に window Scope で実行されるので、window Scope は Angular の Scope と違うため、単純にその中のでデータを修正したりすると、Angular の $digest 処理が実行されません。そうすると、$watch のデータのリフレッシュなどは Angular が検知できなくて、画面のリフレッシュもできません。
 一つの例として、もし directive の link 関数で、要素に何かイベントハンドラーを bind したら、さらにこのイベントが発生したことを、 Angular の世界にそれを通知する場合、該当要素の Scope を取得して、$apply 関数を呼び出す必要があります。
    if (ctrl.$viewValue !== value) {
      scope.$apply(function() {
        ctrl.$setViewValue(value);
    });
 
 実際のソースコードを見てみると、Angular は compile 段階で、HTML のテンプレートを保存したり、$$watcher に expression を追加したりしています。その後、 link 関数を返して、呼び出されます。その link 関数の中では、イベントハンドラーの追加や、jQuery UI の呼び出すことなどができます。さらに、何か変化がありましたら、Scope の $apply が呼び出されますので、 Angular の loop に入って、HTML のリフレッシュが実行されます。
 例えば、ng-model directive の実行順番は:
 Angular が bootstrap するとき、すべての directive を compile して、link 関数を呼び出します。このとき、ng-model の入っている要素の change イベントにイベントハンドラーをバンドルされます。キーボードのキーを押したとき、この change イベントが発生しますので、ハンドラー関数が呼び出されます。
 その後、 interpolation がこの directive を $watch リストに追加します。-> すべての directive とモジュールを初期化完了したら、Angular の loop から抜き出します。

 もしユーザーが何かのキーを input に押したら、ng-model のイベントハンドラーが呼ばれて、$apply 関数で model の value を変更します。
 $apply 関数の中に $digest 関数が呼ばれて、すべての登録した $watch 関数を一通り実行されます。
 これが終わったら、interpolation が実行されますので、HTML の変更などが実施されます。
 次、キーを押したイベントハンドラーの実行が終わりますので、Browser がリフレッシュされます。
 
 ちょっと複雑のように見えますが、実際どの directive もこのようなループが実行されます。一つ理解すれば、Angular はどのように動くかはたいてい明確になります。
 それでは。

2014年7月6日日曜日

Responsive web design の実施

 かなり前ですが、一回会社の UX, Designer チームと食事会があって、そこでこれからはどういう方針でデザインをやって行こうかと少し話しました。基本的には上層部に方針があって、ただ、我々はなんか新しいものを入れたいと思っていました。いろいろチャレンジしたいだそうです。
 それで、デザインのレビュー会議で、Responsive で行こうと、みんな決めました。まぁ、会社からそういう要求がないけど、やっぱり新しいものをやってみたかったです。まず UX とDesigner チームの方達はデスクトップとスマートフォンー向けの PSD ファイルを見せてくれました。その間は、もう私たち自由でやって、完成したらレビューさせることになります。
 デザインを持ち帰ったら、サポートするブラウザーのバージョンより、media query が使えたり、使えなかったりしていますので、方針を決めるにはちょっと時間がかかりました。JS のライブラリを使うか、IE7 を捨てるか、またはライブラリを自作するのかと。その中で、複雑にはやりたくない本音があるので、自作で簡単なライブラリを作りました。それは簡単で、ただブラウザーの幅をチェックして、親要素にクラスを追加するだけにしました。そうすると、media query が使えなくても、追加されたクラスでいろいろやって行けるようになります。
 次、Mobile First というベストプラクティスがあって、私たちはまずモバイル向けのサイトを作りました。media query でまず必要な要素の CSS を書いて、ほとんど親要素は 100% にして、その中のものは適切に幅を設定するようにしました。次、メニューとかどうするかとか、画像は小さいすぎるとか、実際にモバイルで動かしてみて、いろいろ調整しました。UX チームからはいい評価をもらったので、デスクトップ版の作成に入りました。
 こちらも同様、サイトのボディーは100%にして、すべての要素を emか、パーセンティジで細かくセットしました。
 まぁ、実際振り替えてみると、そんなには時間かからなかったんです。以外とすぐ行けました。感覚的には、いい HTML Structure が必要です。HTML が混乱すると、作業が急速に増えます。今、デバイスなどのサイズはかなり変な数字になっていますので、将来的にはもっとサイズを細かく設定する必要があると思われます。
 その後、みんなレビューして、これでオーケーだと。楽しかったです。
 後日また、経験を追加しておきます。

2014年6月29日日曜日

いいエディター紹介しよう

 先週新しい2名 Front End Dev がチームに加入しました。エディターは何か好みがあるかと聞いたら、あまりないと答えた。今まで、ずっと Eclipse、VS を使って JS コードを書いてたと。うちのプロジェクトはニュース関係なので、よくテキストを扱うため、なんかライトなエディターを使ったほうがいいとアドバイスしました。Sublime Text は一番あってるかもと。
 下記のところからダウンロードできます。
     http://www.sublimetext.com/3

 いっぱいプラグインも使えます。まず、最重要なのは package control.
     https://sublime.wbond.net/installation
    Sublime Text 3 を書いてあるタブ中のコマンドをコピーして、 Sublime Text 3 に Ctrl+` を押して、コマンドコンソールに貼付ければ、エンターキーを押して、自動的にインストールされます。
 その後、Ctrl + Shift + p (マックの場合 Cmd + Shift + p)を押して、"install package" を入力すれば、package control がリストされます。それを選択して、エンターキーを押すと、エディター左下に小さい "=" が動きます。それはすべての package 情報をダウンロードしているサインです。少し待つと、別のインプットボックスが出て来て、その中に emmet を入力すれば、emmet plugin が表示されます。結構便利なツールなので、インストールすることはおすすめです。具体的に、下記のドキュメントがあります。
   http://docs.emmet.io/

例えば、! を入力して、Ctrl+e を押すと、自動的に HTML5 のベース HTML Header, Body が展開されます。また ul.hi>li*5 を入力して、Ctrl + e で自動的に ul と五つの li タグが出てきます。しかも ul に hi という CSS Class がついています。結構便利です。
 他に、コマンドを実行したり、Live Style という Chrome の workspace と似てる機能があったりして、使いこなすのも速いです。 フォルタも開けます。Ctrl + p を押して、ファイルを名前をインプットすると、自動的に探してくれます。
 自分は通常の開発はほとんどこのエディターを使います。grunt コマンドも実行できます。まぁ、grunt の file watcher を使ったほうがもっと速いです。
 
 それでは。ここまで。

2014年6月15日日曜日

AngularJS: なぜ {{name}} を使うか

 最近、同僚に AngularJS で何で {{}} を使うところと使わないところがあるかと聞かれました。まぁ、簡単に答えました:ng-model などの Directives では Angular Framework はそれをわかっているので、{{}} で示す必要がないです;ただ、HTML String の中で、どれが Static 、どれが AngularJS の $watch 対象か、区別をつくために、{{}} を使う。

 それは基本的な Angular Framework の作りで決まっています。Angular では ng-app や、 ng-click などすでに提供した Directives がありますし、それ以外 {{}} で変数を $watch するところ、$apply で処理する String があります。Scope にその値を探したりする必要がありますので、{{}} を使うようになりました。
 これは基本的な Handlebars などのテンプレート Lib も似たようなものです。

 今日簡単に書いて、時間があったらまた詳細をまとめよう。

2014年6月10日火曜日

関数の Call Stack in JavaScript

 最近 Back end の仕事にはまってて、Java はちょっと使いにくいなと思いました。やはり、JavaScript がいいですねと。:)
 今日、Safari の Web Inspector が iOS でのデッバグができなくなったことを発見しました。。。なんでだろうね。
 どうしても、関数のコールスタックを見たくて、ちょっと調べてみました。一般的に arguments.callee.caller から親関数が見つかります。
 または new Error().stack をコンソールで出力すれば、一連のコールが見えます。試してみたら、この Error が mobile webkit では定義していないようです。arguments.callee.caller を使うしかないです。

 実際の問題点は、うちのアプリは一回三つの画面をレンダリングするので、その一つは HTML フォーマットの動画CM です。それで、実際その画面が表示されたら、 CM を起動したいです。ただ、JS では自分は表示されているかどうかわからないので、iOS と Android の native コードで検知しています。画面が表示されたら、CM の Start 関数を native コードで呼び出して、動画を始めさせます。このタイミングと実際何所で呼び出されたかを知っている方は知っているが、他のあたらしい開発者はわからなくて、何かいい方法がないかを考えています。。。

 まず、ここまで。

2014年5月18日日曜日

Android Media Query サイズ再考

 先週、Android バージョンのアプリがリリースする予定でしたが、横向きを追加すべきとの観点が顧客から出てきました。phone サイズだと、横向きがの高さが本当に小さいから、それに加えて私たちのアプリにヘッダとフッターがあるから、いっそう立て幅が小さくなります。。。
 ただ、ユーザがより多くのコンテンツを読みたいことが予想できますので、今月中のリリースに向けて、着々アプリの修正が進んでいます。その中に、私メインで作った天気ページは縦方向しか対応してないため、横になると、字がかぶったり、位置がずれたりしています。対応が必要です。
 私たちの Phone サイズテスト機は Nexus 5となっています。実際使って見ると、なんと、WebView の横幅は 800 px もあります。。。一般的な Tablet は 1024 となっていますが、接近していますね。。。何とも言えないけど。。。
 それで、480px 以下だと、phone レイアウトを表示するとか、下記の一般的な表があります。
    Phone width =< 480px,   Tablet 480px < width =< 1024px,  Desktop > 1024px
 iPhone 5や、Nexus 5がリリースされると、上記のサイズは実際とあわないことになりました。
 それで、多分上記の分け方に問題があるような気がしています。なぜなら、Android ではタブレットのサイズが違いすぎるためです。今まで見たアンドロイドタブレットの中に、1024x360 のものもあります。縦になると、実は Phone と変わらない横幅です。
 多分、これから開発するとき、Responsive デザインを実装する時、Phone サイズなどの分類を考えずに、直接デバイスのサイズを考えたほうが良さそうです。
 まず、>= 1024px、これは大きいサイズのタブレットとデスクトップ。
 次 < 1024px、これは普通のタブレットサイズ。
 さらに、< 480px、これは小さいデバイス。
 これで、まず全部の要素をできるだけパーセンティジで定義して、全部の要素をブラウザリサイズするとき、隠さないようにします。次、画面のサイズにあわせて、Media Query を使って、個別要素のサイズを調整します。
 注意点としては、位置が Absolute の要素に対して、たまに他の要素とかぶったりします。どの親と一緒かをはっきり設定しなければなりません。BEMスマックスなどの Methodologies を参考にすれば、面白いでしょう。
 もし、CSS では難しいであれば、背景画像を使いましょう。小さい画像なら、base64 でエンコードして、CSS に入れれば、余計な HTTP Request なしで済むから、便利でしょう。
 ほんの小さい考えですが、デザイナにインプットして、使いやすいアプリになりますように。
 それでは。

2014年5月10日土曜日

HTML5 要素構造 Design

 今まで、結構 HTML5 ページを書きましたけど、レイアウトを実現ために、どのような要素 (tag) を使うかとか、親 div に入れるかとか、結構ややこしいです。最近の考えをここでメモして、将来また best practice として、後輩に伝えよう。
 HTML 4 から、HTML 5になって、一ついいことは Web page 構造と意味が明確になります。例えば、以前何でもかんでも div を使うところ、今は article, section などで情報の構造により、適切にタグが定義してくれました。ただ、 Gmail などのページを開くと、驚きほど数の div タグが結構使われています。実際自分は Sigle page web app を使うとき、いざ何かを実現したい場合、まず親 div 要素を定義します。これはもう解決できないような気がしていますが、それ以下の子要素、孫要素の構造はもっとエレガントに書かないと、将来のメンテナンスや拡張が難しくなると思います。
 実際の考え方として、データの構造を理解した上で、それにあわせて、要素を決めようと。その後、CSS3 で位置を調整したり、z-index を使ったり、web app を完成します。それで、HTML を読むとき、実際のデータとあっているし、レイアウト変更する場合、例えば responsive デザインを導入する際に、新しい css を書けば済むでしょう。
・まず、Array に定義しているすべての複雑なデータアイテムをページにリストする場合。
 ul > li を使った方がいいと思います。inline 要素、block 要素でも全部 li に入れられますし、親子関係も見ればすぐわかります。もし全部 div を使う場合、class に一つ共通的なものを振りましょう。なぜなら、jQuery 一つで、または native js 一つで、すべて同類のものが取れるからです。そうすると、動画や、文字を大きくするとか簡単になります。
・次、数字などのデータをページに表示したい場合。
 table を使いましょう。以前なら、(IE 6 ぐらいの時代?)ページ全体を一つの table のおさめて、レイアウトを調整しましたが、現在では、それは bad practice の一つになっています。 table は数字など、ものを比べるとき使うべきです。例えば、月ずつの返済額とか、エリアの対象一覧とか、同類データは table に入れると、わかりやすいし、js で tr td 文字列を簡単に作れます。
・文章や説明など article と section, p, span を使いましょう。
 例えば、不動産の説明文書など、実際見れば、一つの article です。このようなタグを使うことで、 HTML 読みやすいなります。もう一つの例として、dt dd pair で使うことで、定義、説明であることはすぐ気づきます。

つまり、実際のデータ構造にあわせて、タグを使うことで、HTML がわかりやすくなります。
ただ、例外も結構あります。例えば、drop down の select に対して、特別なスタイルを使いたい場合、jQuery ui では新しい div , a , ul li を動的に作成して、select の上にカバーする形になっています。実際の a タグの意味はあってないけど、構造としてはこれもわかりやすいです。後日また整理します。

それでは。

2014年5月7日水曜日

初めて、サムソン gear smart watch を触った

 今日、いろいろ悩んでいる間、同僚から AJAX の質問が来ました。それはサムソン Gear Smartwatch で動く widget の UI についてでした。
 ちょっと意外なのは widget はほぼ JS + HTML5 + CSS3 で開発することでした。Tizen という開発環境の中で、index.html や Lib などがありました。ちなみに、widget 内部では jQuery を使っているらしいですが、外部には公開されてなくて、自分で jQuery Lib を html ファイルに include する必要です。Tizen は Eclipse をベースにしているので、ちょっと使いにくいけど。。。
 後、サンプルはそれほどあって、何かアプリを作るとき、それをシードとして使えます。まぁ、ほとんどは JS コードですが。

 最初の感想は iPod nano みたいです。使いにくい、使いやすいより、同僚はおもちゃとしてはそこそこ面白いらしいです。

 本題に戻ります。内部のシステムは Andoroid らしくて、動くアプリは Webview で実行されて、後親機が必要で、いつも通信しているそうです。彼は天気情報などネットで取得できるのに、何で Widget では動かないかと。。。
 実際 Debug ボタンを押したら、Chrome の Web Inspector が起動され、要素や、JS などは Debug できます。画面が小さい以外、あまり感想がないです。
 調べてみたら、Widget では Web と通信するために、サービスを作る必要があります。まぁ、予想とおりですけど。 Android はデフォルトで Web をアクセス機能を有効するわけがないから。
 あまり深くどのようにサービスを作るかを調べてないけど。一応、原因が見つかりました。実際 XMLHttpRequest を発行すると、Debug モードでアプリが異常終了します。Release モードでは何も起きない。。。ちょっとわかりにくいです。
 
 一ついいことはまた JS の面白さを同僚に伝わったそうです。:)
 それでは。将来は本当の Watch を使いたいですけどね。

2014年5月6日火曜日

Android WebView 謎。。。

 最近、HTML5 Ads ページのバグが報告されました:Android の WebView で全ページ表示できない。。。
 本来なら、スクロールバーが表示されるので、問題がないでしょうと思っていました。ただ、営業の方達はぜひ全ページを表示できるようにと。
 以前は JS で設定し直す手段で Ads を正しく表示できるようにしましたが、原因がわからなくて、未だに調査中です。。。また今回のバグが出てきました。。。 orz
 ただ、iOS では Ads の表示が正しいと。多分 Android は Webkit をベースにしていますが、 WebView の実装が iOS と比べると、まだまだ W3C の標準になってないでしょう。また、各要素のデフォルト margin, padding がブラウザの設定が違うでしょう。
 そうすると、iOS では正しく表示できているので、 Android の開発者に依頼して、WebView の設定を調べてみようと。20分で、setInitialScale(1) をコメントアウトしたら、iOS と同様に表示できたとの連絡が来ました。。。
 一応 Ads ページの中に、viewport がちゃんと設定しているし、なぜ setInitialScale をもう一度呼び出すか、デフォルト値はなにになっているか、ページ中の Viewport ではだめですかとかいろいろ質問がありましたけど。今週中に Android バージョンが公開されますので、後回しにしました。
 自分は設定する必要がないと思いました。後日、詳細を調べてみよう。

 また、アンドロイドディバイスのサイズが本当にいろいろあって、media query で Responsive レイアウトをスタイリングする時、実際のディバイスが確認するようと。たまにはシミュレータとディバイスとブラウザリサイズの表示が異なります。実機で確認するのは不可欠です。
 
 早めにリリースできるように。:)
 それでは。

2014年5月1日木曜日

アンドロイドの WebView CSS Refresh問題 <= JSで再度設定し直す。原因調査中。。。

 ニュージーランドに旅行に行きました。:)しばらく更新してないから、いろんなものを忘れないうちに、メモしておこう。
 今日アンドロイド Phone サイズの対応作業がありました。基本的に Media Query を使いますが、たまには HTML の書き方に疑問を持つようになりました。なぜなら、最初 Web Page を作るとき、Tablet を想定してから、Phone サイズになると、文字のサイズや、本来なら絶対2行にならないところが切れたりして、ちょっと対応しにくかったです。幸いコンセプトが違うから、矢印などいらない部分を全部隠して、2時間で作業をほぼ完了しました。
 ただ、 広告ページを対応するとき、iPhone では綺麗に表示できたのに、アンドロイドでどうしてもうまくいかないことがありました。CSS で写真の高さを 100% 設定しても、スクロールバーが出るし、押してしばらくすると、スクロールバーが動けるようになりました。原因はわからない。。。
 基本的にアンドロイドとiPhone は WebKit をベースにしているから、表示も同じのはずですが。まぁ、基本的にデフォルトのスタイルがちょっと違ったりしていますけど。意外にアンドロイドの WebView 使いにくいなと感じました。
 それで、setTimeout を使って、ある程度遅延を入れて、再度 CSS を設定し直したら、うまく行きました。
 Android 4.4 Chrome での表示は正しいですけど。。。
 何でだろうね。明日時間があったら、見てみよう。。。

2014年4月4日金曜日

テキストの Responsive デザイン

 最近読んだ Responsive Design の文書です。
techniques for responsive typography

 作者はほぼテキスト関係のベストプレクティスを網羅しました。結構いい文章でした。以前自分は Responsive サイトを作るとき、主にブラウザのことを考えて、em を使ったりして、細かいところは px で指定していました。これもいいですが、完全に文書の中のものを使うとなんだかちょっと使いにくいような気がしています。
 やはり、C++ = C + "++" っていうパタンは使いやすいです。:)
 後日また心得を追加しよう。
 それでは。

2014年3月30日日曜日

日本はなぜ Front End を重視しないか?

 最近、あまり Yahoo! Japan 以外の Web Page をアクセスしてないけど、今日偶然ある不動産屋のホームページを見てみたら、遅くて、別のサイトを切り替えました。個人的には日本と欧米と比べると、Web 系の技術はまだまだ道が長いようです。ウェブサイトは Back End だけではないです。Front end が遅くなると、システム全体の評価が低くなります。
 Back End は自分のサーバーで動くから、遅いことはすぐ気づくでしょう。そこで、アルゴリズムの改善などして、インデックスを DB に作ったりして、まだなんとかなるでしょう。ただ、 Front End、いわゆる HTML 部分は顧客のシステムで動くので、いろんなブラウザがありますし、PC のスペックも様々です。最近、モバイルからのアクセスもかなり増えていますので、そこは通信や、JS の実行、ファイルのロードなどがさらに遅くなります。元々 Web Page が遅くなると、モバイルではさらに遅くなります。 Retina サイズのイメージを考えると、あ、頭が痛くなります。。。
 
 以前も書きましたけど、どうやって、ウェブサイトのロードスピードをあげるかと。
Web App が遅い??

 今日別の観点から、改善すべきところをリストします。
・まずは画像についてです。今のブラウザは画像をロードするにはいろんな加速技術を使っています。一つのドメインから、平行で二つの画像がダウンロードできますし、img の src を見つかったら、ウェブページをロードするスレッド以外、別スレッドでダウンロードするとか、いろいろありますけど、やはり、一つのリクエストのコストは大きいです。これを極力減らすべきです。
 一つの方法はすべての画像を一つにまとめて、CSS で background-position を使って、画像の一部分だけを表示します。これはスプライトといいます。下記のウェブページで画像をまとめて、一つのものにします。
 Sprit Generator
 後、もし画像のサイズがわかるなら、 img に width と height を書いて、ブラウザはそれを読んだら、まずポジションを確保します。そうすると、ページの内容がまず全部表示して、画像は後から少しずつ表示されます。全体にスピードアップような感じがします。
・次、CSS, JS ファイルを一つに、コンプレスすべきです。これは結構いろいろありますから、後日またツールを紹介します。
・後は JS についてですが、JS はいつも一つのスレッドで実行しますので、ブラウザがもし <script type="text/javascript">を見つかったら、他の処理を止めて、まずそこのコードを実行します。現在 V8とか、Gecko とかすごく速い JS Run Time Env があるが、やはり JS は遅いです。
 それで、すべての <script> を <body> の最後に置くと、DOM のロードなどが少し速くなります。ユーザは白い画面のままで待つ時間が短縮されます。
・CSS で作れるものは、画像を使わないほうがいいです。後、アニメーションとかも CSS を使ったほうがいいです。CSS はいろんなものが作れます:
  CSS GUI Icons
ブラウザはこれを実行するスピードがイメージをレンダーするスペードより、百倍速いです。
  CSS スタイルを適用するとき、別の文章があります。英語のものですけど。
  CSS Best Practice
  時間があったら、翻訳します。
・HTML の要素も減らしましょう。<div> など、必要なときだけ使うべきです。一つの画面に要素が 2000 個以上使うことはあまりないでしょう。複雑なウェブページ以外ですけど。後、後日また書きますが、JS にできるだけ HTML コードを書かないようにすべきです。メインテナンスでは、どうやって、そういう動作になったか読みづらくなります。

まぁ、ここまで一段落。それでは。

2014年3月27日木曜日

デフォルト値の重要性を見える例

 今後、Junior 開発者とコードレビューするとき、データ設計の重要性とデフォルト値を設定すべきだと伝える例です。

 すべての値を各レコードに書くより、あるデフォルト値を外に設定して、特別な時だけ、特別な値を設定すべき。
 これで、かなりのマニュアル操作が減らせます。
 一つの例:
 ある、JSON ファイルに uri があります。
    { sections: [
           {
               uri: "http://example.com/12345",
               story-uri: "http://example.com/{0}"
           },
           {
               uri: "http://example.com/45678",
               story-uri: "http://example.com/{0}"
           },
           {
               uri: "http://example.com/1804232",
               story-uri: "http://example.com/{0}"
           },
           {
               uri: "http://example.com/2431245",
               story-uri: "http://domain2.example.com/{0}"
           }
    ]}

 最後の一個だけ story-uri が他と違います。もし、こういうレコードが何十個にあると、修正するにはかなり時間がかかります。

それで、下記の JSON に変更すれば:
    { sections: [
           {
               uri: "http://example.com/12345"
           },
           {
               uri: "http://example.com/45678"
           },
           {
               uri: "http://example.com/1804232"
           },
           {
               uri: "http://example.com/2431245",
               story-uri: "http://domain2.example.com/{0}"
           }
     ],
     common-story-uri: "http://example.com/{0}"
}

 コードには、まず各レコードに story-uri があるかどうかチェックして、もしあったら、それを使います。もしなければ、common-story-uri を使います。多分5行ぐらいのコードですむことです。こうすれば、不要な重複をなくして、レコードの story-uri を変更するときも一目瞭然です。

 これは Fall back というんです。それでは。

愚痴:Android の WebView が遅い。。。アジャイルいろいろ => やはりヒーローが必要です。

tl;dr : 基本的に Android の WebView は遅いです。特にアニメーションがカクカクする場合があります。JS でのアニメーションは使わないようが良いでしょう。また AngularJS を使うと、また一層遅くなるので、もしパフォーマンスに気にするなら、React.js を使ってみてください。
 速くする方法としては、画面を pre-load するだけです。ユーザーの動作を考慮して、Idle 時間に先に作っておいて、表示するとき、画面を切り替えだけ行います。
 
 愚痴です。いい内容、答えもないので、ただメモして、いろいろ考えたいだけです。時間の大切な方はご遠慮。

 最近 Android バージョンのアプリが作り始まりました。あまり進捗など見てないけど、Front End チームの一員として、会議に呼ばれました。問題は一つ、iOS に比べると、Android の WebView がちょっと遅くて、スライドする時、画面のレンダリングが追いつけない。。。 これじゃ、また何所が遅いかをみんなで討論して、何か解決方法がないかと。
 実際見てみたら、そんなには遅くないけど、動きが速いとき、やはり iOS には及ばない。。。これは Android 自身の問題じゃないかと。みんな知っていることでしょうと。が、そうは行かないですけどね。
 今は独自の jQuery Light のライブラリを実装して、すべてのページに使っているし、かなり細かくファイルを分けて、ロードの時間をできるだけ短縮しました。実際一つだけのページをロードすると、速いとは言わないが、遅くないと思います。では、問題は何所にあるだろう?
 今の iOS App は表示している画面以外、別のスレッドで次の画面と前の画面をレンダリングしています。なぜなら、Google Analytics によると、ユーザが一つの画面に止まる時間は12秒でもある。コンピュターの世界にいると、1秒ではかなりの時間です。その時間を使って、裏でいろいろマルチスレッドがやります。
 Android アプリはあまりこういう工夫はしていないそうです。
 まぁ、あまり言いたくないけど、何か問題を発見したとき、会議にする前に、まずみんなに聞いてみましょうよ。もちろん知っている人は知らない人はいるんですけどね。これはまたアジャイルの弱点は少し出て来た。
 今のプロジェクトでは、設計ドキュメントもないし、仕様書もない。。。すべてがソースコードにあります。これはすばらしいことです。ただ、問題はみんなソースコードを書くとき、開発者のレベルより、コメントが読めたり、読めなかったりします。後、ソースコードを読みたくない開発者もいるから、すべての知識を浸透するには難しいです。
 それでエンジニアリードという職をもうけて、どう設計するかの指導役ですが。今、その方はあまり iOS, Android アプリの経験がないので、いろいろ難しいことがあります。じゃ、今まで何をやって、いい結果になったか問う言うと、チームにヒーローがいるからです。
 ヒーローがすべて知っているし、指導もできるし、自ら難しい問題を解決してくれます。今のチームにはそういう人がいなければ、どうなっているかは本当にわからない。この状況を変えるにはどうすればいいでしょうかね。。。
 それでは。
 

2014年3月22日土曜日

Mac OS X で JDK の切り替え

 最近、隣のお姉ちゃんが間違って JDK 1.8 をインストールしてしまいました。うちのプロジェクトは JDK 1.7 を使っていますけど。。。
 まず変なエラーが出て: Saxon-HE-9.4.jar のSaxon he 9.4 XPathfactory#newInstance() の Configure ファイルのなんちゃらがフォーマットが正しくない。。って。何でだろうと思ったんですけど、見たことのないエラーだし、どうしようかなと。
 Tomcat の設定、Eclipse の設定、Maven ファイルのライブラリのバージョンをいろいろ調べましたが、変なものが見当たらない。。。
 それで、正しく動いている War ファイルをサーバーからダウンロードして、入れてみたら、やはり同じエラーが出て来ました。まぁ、これで、ローカルマシンの問題だと断定しました。JAVA_HOME を見たら、1.8 となっていました。。。
 これは、これは。すかさず、1.7 をダウンロードしました。ちなみに Oracle のウェブサイトからは変なファイルがダウンロードしたので、インストールできませんでした。以前保存した dmg ファイルをまた Air Drop を使って、運んで、無事インストールが成功しました。
 じゃ、次は JDK バージョンの切り替えです。いろんな方法がありますけど、一番いい方法を見つかったので、メモしておこう。
 まず、Java のバージョンを調べる /usr/libexec/java_home というコマンドがあります。
それを使って、.bashrc, .bash_profile などのファイルに
export JAVA_HOME=$(/usr/libexec/java_home -v 1.7)
を書けば、そのバージョンの JDK が使えます。
もっと便利に、コマンドの追加して
http://superuser.com/questions/490425/how-do-i-switch-between-java-7-and-java-6-on-os-x-10-8-2

alias java_ls='/usr/libexec/java_home -V 2>&1 | grep -E "\d.\d.\d_\d\d" | cut -d , -f 1 | colrm 1 4 | grep -v Home'

function java_use() {
    export JAVA_HOME=$(/usr/libexec/java_home -v $1)
    export PATH=$JAVA_HOME/bin:$PATH
    java -version
}
切り替えも簡単になります。
まぁ、難しいことではないけど、間違ってインストールすると、変なエラーが出たりしますので、今後自分も注意を。
それでは。

2014年3月19日水曜日

iOS ファイル HTTP 経由ダウンロード、失敗することがある

 この時代になると、HTTP サーバーを接続して、ファイルをダウンロードをするには、かなり普通なことになりまして、サーバーがちゃんと生きてあれば、通常は失敗しないだろうと。3G でも、4G でもそうですが。
 実際では、失敗することがあります!えっ、えっ?
 回数が足りないだけです。:)
 通常 3G で接続するとき、みんなかなり注意しますけど、Wifi で接続する場合、必ず成功するのはないです。
 それで必ず、Timeout や、失敗するかどうかをチェックしましょう。
 先日ちょっとひどい目に遭いました。。。
 いくら発生率が低くても、発生することがあり得ます。Shit happens. :)

モバイル Web App が遅い ??

Update: iOS 8 から UIWebView のウップグレードとして、WKWebView が追加されました。Nitro も使えるようになりましたので、in App WebView がさらに速くなりました。

最近面白い記事を二つ読みました。一つはなぜ Mobile Web App が遅いか
        why mobile web apps are slow
 もうひとつは遅くても、ちゃんと開発すれば、全然感じられないほど速い。
        the making of fastbook an html5 love story

 ネーテブの App と比べると、Web App が遅いのは当然、ただ何所まで遅くなるかはみんなわからない。それで、いろんな文章が出て来た。読んだ文章は結構データも充実しているので、信頼できるでしょう。ただ、ネーテブコードでも遅くなるケースも結構あるので、これは開発者次第です。
 そうすると、Facebook App をSencha を使って、開発すると、ネーテブとほぼ同じ、またはもっと速いよとの文章です。
 実際コードを読んでみると、HTML5 は遅いかもしれませんが、まさしく Sencha のように、よく作ると、あまり感じられません。
 じゃ、Web App を作るとき、何を注意すべきでしょう:
・まず、DOM 操作が遅いから、できるだけ減らしましょう。DOM 操作というのは HTML Element を作成して、その後、append, before などの関数でそれを挿入すること。DOM ツリーが更新されるので、時間がかかります。特に、IE7, IE8 の時代、JavaScript 自体が遅いし、大量のノードを挿入すると、メインプロセスが止まって、無応答になります。
・できるだけ、文字列で HTML 文を作って、一気にDOM にいれましょう。これは .innerHtml を使います。これは Mustache や、 Handlebars と言ったテンプレートライブラリの用途です。もし、小さいものならば、 underscore.js も template 関数があるので、それを使ってもいいでしょう。
・resize, scroll などにバンドルするハンドラ関数を throttle や debounce 関数を使って、実行の回数を減らしましょう。scroll すると、一瞬にかなりの数のハンドラ関数が呼ばれますので、かなり負荷が高いです。ある時間を経過後、ハンドラを呼べばいいでしょう。
・setTimeout を有効に使いましょう。setTimeout(func, 0) の意味は JavaScript のコールスタックが空になったら、 func を実行するのです。元々注意すべきところは setTimeout は何時実行されるかは不明ですので、ある程度の時間を経過したらというのです。例えば、いっぱい HTML 文字列を挿入して、挿入後、 Focus を新しく生成した Input に設定する処理では、何時挿入が完成するかはわからないので、その後で setTimeout 0を設定すると、挿入完了したら、実行されます。
・DOM の Event Propagation を有効に利用しましょう。例えば、li タグ中の div にハンドラ関数をバインドしたい場合、li の親の ul にバインドすれば、event.target でクリックした要素が取得できますので、一つのハンドラですむのです。li にいっぱいハンドラ関数をバインドすると、結構コストがあります。
・ロードするライブラリを注意しましょう。いつどのようなライブラリがロードされるかちゃんと管理しましょう。本来なら require.js がこういう仕事のためですが、自分はそのライブラリちょっと気に入らないので、使いたくないです。ライブラリをロードするにはかなりコストがありますので、最小限のコードを実行しましょう。例えば zeptojs を使ったりしてしましょう。まぁ、本当に速くしたいなら、自分で自分用のライブラリを作りましょう。そうすると、エラー処理とか省略できるので、かなり速くなります。自作の場合、jsperf.com がかなり良くできています。使ってみてください。
・写真のロードや、ファイルのサイズ、後キャッシングするかどうかもかなり影響しますので、注意しましょう。
 - まず写真について。現在のブラウザは写真をロードするには複数のスレッドを使っていますので、二つのドメインからロードすればいいです。そうすると、Static のリソースは別々のドメインに保存すればいいです。
 - 次ぎ、ファイルのサイズについて。ファイルの請求はかなり時間がかかりますので、jsや、cssファイルを一つのファイルにまとめて、不要なスペース、改行を全部削除しましょう。 Ruby や、Node.js にいろんなツールがあるから、有効に使いましょう。RoR の Asset Pipeline はかなり良くできてますので、使えるなら、使いましょう。
 - キャッシングについて。もし一つのファイルは変更する予定がないなら、expire 日付を一年以降に設定したりして、ロードは最初の一回のみでいいでしょう。RoR ではファイル名の後に SH 列があるので、内容が変更したら、その文字列も変わるので、かなり便利です。
・HTML5 の新しいフェーチャーを使いましょう。
 - Local Storage を使いましょう。Cookie が送信されるので、サイズを累計すると、かなり大きくなります。だから、必要なときだけ、データをロードして、送信しましょう。
 - Offline 機能を有効に使いましょう。これはキャッシングと同じような感じですが、 Offline 機能を使うと、どのファイルをどう更新するかは自分でコントロールできます。
 - 動画なら、CSS を使いましょう。JS の fadeIn, fadeOut 関数などはかなりCPU 使いますので、良くないです。 CSS だと、GPU を使って、画像が作られますから、ブラウザの負担た小さいです。
・ CSS についても注意しましょう。できるだけ、div .cls1 .cls2 {} のようなものを書かないでください。これはブラウザが CSS を適用する際に、.cls2 から、要素すべての親をスキャンして、div .cls1 となっているかどうかチェックするから、時間がかかります。できれば、.cls2 だけ書いてください。これは速くなります。

まぁ、他にもいろいろありますけど、後日また追加します。
それでは。

2014年3月6日木曜日

Chrome の Same Origin Policy を無効にする

Windows の場合を補足しておこう:
C:\Users\%USERNAME%\AppData\Local\Google\Chrome\Application\chrome.exe --disable-web-security
# つまり、chrome.exe の後ろに --disable-web-security を追加する。またはショットカットを作って、パラメターとしてそれを渡す。

ただし、通常の chrome を実行している間、同じプログラムで二つプロセスが実行できないため、エラーが出ます。
こういうとき、下記のコマンドを実行しよう。
chrome.exe --user-data-dir="C:/Chrome dev session" --disable-web-security
これで、違う chrome プロセスが実行されますので、安全モードの Chrome と web security 無効の Chrome が同時に実行できます。

Mac で一番いい方法見つけたので、メモしておこう。
.profile に下記を追加して、コマンドラインで chromex を実行すれば、 別ドメインへの XHR が実行できるようになる。

chrome () {
  /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome $* 2>&1 &
}

alias chromex="chrome --disable-web-security"

 Safari の iOS web inspector はちょっと使いにくい。。。
 Mobile での HTML5 widget 開発には役立つだろう。:)

 それでは。

2014年2月24日月曜日

アジャイル、新しい理解

 前から、アジャイル開発はいいなと思ってました。最近チーム内で実際やってみたら、いろいろ新しい理解ができました。まずは一つの図です:
http://findingmarblesdotcom.files.wordpress.com/2011/12/agile_mindset.jpg

 これは Retro の後、うちの Scrum Master がちょっと怒ったらしくて、みんなに送信したものです。なるほどと思われるところは赤いエリアです。アジャイルは完全に自由ではないです。自由すぎると、混乱にもなります。
 ソフトウェアへの変更依頼はなくならないです。以前から、何人かの先生から品質のいいソフトを作るために、まず全部の仕様をまとめて、決まって、開発に入ると聞きました。が、それは完全に間違っていると思います。変更依頼は本来ソフトウェアについたもので、それがないと、いいソフトが作れません。
 だから、人の弱みをカバーするために、顧客本当のニーズをわかるために、各 Sprint で成果物をみんなに見せて、変更しながら、よくして行きます。
 アジャイルを実施するためにはチーム内2以上のシニア開発者が必要だと思います。まず、一人ではみんなに行動を見せて、上達して行くのは大変です。自分の作業もあるから、手本を見せながら、やって行くのは大変です。二人いると、負担がかなり減ります。それに、まずチームメンバーになぜそうするか、どうしたら良いか、何でデザインパタンを使うかなど、いろいろ理解してもらう必要があります。次、見積もりのところ、必ずシニア開発者を混ぜて、みんな一緒に見積もりしましょう。そうでないと、見えない作業が発生したりしますので、また後で無理矢理詰め込んで、みんな疲れます。
 ソフトウェアは一般的な製品と違って、必ず人の手に頼りますから、その理解大切です。
 まぁ、いろいろ書きたいけど、具体的にどうやって行くかのプロセスを後日詳細を。
それでは。

2014年2月16日日曜日

CSS Tips 3: float, clear

 Web Page を作る際に、よく要素を横で並べたりするので、リストを使うと、通常縦並びになりますが、このとき、li に float: left をつけると、横並びに変わります。もちろん、li の width を注意しなければならない。一般的に親要素の 100% width を割り算して、設定します。例えば、三つ li の場合、width を 33.33333% に設定します。
 ですが、 float になった要素はポジションとして height が計算されないから、他の要素が上にかぶるとか、親要素が高さが足りないとか、そういうことがたびたび見かけます。
 このとき、親要素の height を設定しましょう。または li:first-child に float: none を設定して、位置とサイズをちゃんと与えましょう。自分の後ろの方法が好きですけど。
 clear: both も一つの方法です。ul の後ろに、div clear の要素を挿入することで、ちゃんと境界が作れいます。通常 div に内容がない場合、height と width がともに 0 ですので、見えないです。 clear : both というのは float の要素と別に、次のブロックを始まります。

それでは。

Spring Framework で Strategy パタン

 これから、私たちのシステムの Generalisation をしますが、なかなかやり方が決まらなくて、どうするかを考えてみました。一応メモをとっておきます。
 まず、事情を説明すると、現行システムは一つの顧客しか対応してなくて、顧客が増えるたびに、同じクラスで関係ありそうなところを if... else... や、 switch 文を入れたりして、分枝を作っていました。それが良くないことだとみんながわかっています。顧客が増えるたびに、すべてのソースコードをいじりますし、他の顧客を影響しないようにテストの負担も大きいです。それで、今回で、もう Unit テストや、 E2E テストをすべて一回整理して、システムの Refactoring をやろうと決めたのです。最初はコストのかかる仕事ですけど、将来の開発を考えると、やらざるえない選択だと思います。
 いろいろ考えた結果、今使っている Spring Framework をベースにして、DI を使います。最初は共通処理をインターフィースとスーパークラスに抽出します。 Eclipse の Refactoring 機能を使って、簡単にできるはずです。次、各顧客独自の仕様を抽出して、チャイルドクラスに移ります。そうすると、顧客の間は影響しないようになります。もし何か特別な市よりがあったら、顧客の実現クラスにスーパークラスのメソッドを override したら、問題ない。システムの構造も理想です。将来開発担当者を変わっても、他のプログラマーもすぐ何所でどのように修正するかはすぐにわかります。
 肝心なところはどのように対象クラスを選択して、処理を Delegate するかになります。一つの方法は Factory クラスを作って、顧客の名前を渡して、対象クラスを返すようになります。ただ、そうすると、顧客が増えるたび、Factory クラスをいじらなければならないです。前よりかなり進んでますが、もっと良い方法がないかと考えました。
 どうせ顧客の名前や ID に基づいて選択するから、マップを作って、そこから選択しようと。
 まず、各顧客のクラス Bean を定義します。
<bean id="Customer1Strategy" class=" xxx.xxx.Customer1StrategyImpl" />
<bean id="Customer2Strategy" class=" xxx.xxx.Customer2StrategyImpl" />
<bean id="Customer3Strategy" class=" xxx.xxx.Customer3StrategyImpl" />
 次、 Strategy マップを作ります。
<bean id="CustomerStrategies" class="xxx.xxx.CustomerStrategies" >
   <property name="strategies">
     <map>
       <entry>
         <key>
           "Custromer1"
         </key>
           <ref bean="Customer1Strategy" />
        </entry>
       <entry>
         <key>
           "Custromer2"
         </key>
           <ref bean="Customer2Strategy" />
        </entry>
       <entry>
         <key>
           "Custromer3"
         </key>
           <ref bean="Customer3Strategy" />
        </entry>
    </map>
  </property>
</bean>
 まぁ、その後は簡単です。CustomerStrategies をサービスに Inject して、サービスを呼び出すとき、顧客の ID をセットして、
ICustomerStrategy strategy = (ICustomerStrategy)customerStrategies.get(custmoerID);
を呼ぶと、顧客ごとのクラスが取得できるようになります。
 
 とりあえず、ここまで。それでは。

2014年2月8日土曜日

jQuery の Why & When

 先日変なコードが見たから、自分の心得をシェアしようと。
 Web App を開発するとき、DOM を操作する必要があるから、一つ悩ますことはブラウザの間に区別が結構あります。最近は良くなりましたけど、IE6、IE7 の時代はひどかったですね。特に MS はあまり W3C を準拠してなかったが、IE の市場シェアは 80% 以上にあって、変なウェブページがいっぱい作られました。そうすると、現在のモダルブラウザ (Chrome, Firefox, Safari, IE9, IE10 など) どうしても対応できなくなっています。それで Quirks モードが出て来て、 IE の Dev tool にモード、ドキュメントモードなど分けわからないメニューアイテムが追加されました。
 じゃ、何で jQuery を使うの?いつ jQuery を使うべきでしょうか?答えは主に左記のことですが、jQuery もいろいろ便利な機能があるから、みんな使っています。注意すべきところはライブラリを使うと、必ずコストが着いてきます。例えば、jQuery のコードがロードする時、ブラウザは1万行ぐらいの JavaScript コードを解釈し、実行する必要があります。大きいウェブページの場合、ロード時間を気になる場合、light jQuery というものもあります。例えば、zepto js. 自分の会社もjQuery が重いから、自前の light jQuery Like lib を作りました。
 まず、複数のブラウザを対応する場合、DOM の操作するとき、できるだけ jQuery を使いましょう。複数のブラウザは Cross-browser と言います。例えば、ウェブページに選択された文字列を取得したい場合、IE では createTextRange を使いますが、Chrome や Firefox にはその関数がありません。option を select に追加したい場合、IE では innterText を使えますが、Firefox にはその属性がありません。(なぜか Chrome にはあります。。。) jQuery の作者 John の話では DOM is a mess. それで jQuery のコードにこれらの区別をカバーするようなコードが結構あります。使うと決めたら、もう全部 jQuery を使うべきだと私は思います。createElement の速度は速いが、その速さはもう jQuery のロードで消耗したから、意味がありません。
 次は開発のスピードをあげるため、CSS の Selector をよく操作する場合、jQuery の関数を使いましょう。Native の JavaScript はそこが難しくて、jQuery の関数はそこをカバーしてくれました。後、CSS の Class name で要素を取得する場合、jQuery の selector も結構便利です。中にはモダルブラウザの querySelector, querySelectorAll が使われてますので、スピード的には速いです。
 後、スピードの要求がさほど高くない場合、jQuery のアニメーション機能や、Event 機能が便利ですので、使いましょう。

 あまり良くないことは Native の JavaScript コードと jQuery を混在して使うことだと、自分は思います。なぜなら、Native の JavaScript 関数は各ブラウザに通用するかは調べるには時間がかかりますし、コードを読むとき一貫性がないというか、メンテが大変だと思います。
 もう一つは、もし一つの要素を高い頻度で使うなら、全局の変数でキャッシュすべきです。なぜなら、 $(".abc") にはコストがあります。$ は実は一つの関数です。後、毎回それを実行すると、メモリー的にはあまり良くないです。
 
 まぁ、いろいろ書きましたけど、いいたいことは、開発前にもし Cross-browser となりましたら、jQuery が便利です。:)

2014年2月4日火曜日

Google の検索結果から URL をコピーするな

 最近、iOS の UIWebView で URL を開こうとすると、変な文字が後ろについちゃって、開けなくなりました。変な文字と言うのは %E2%80%8E です。ちょっと UTF-8 のコードを検索すると、Left-Right-Mark のようです。
 詳細をテスターに聞いたら、その URL は Google の検索結果から直接コピーしたものでそうです。試しに、google で何かを検索して、web inspector で HTML を見たら、URL の後ろに&lrm;というものがありました。それは Left-Right-Mark です。
 詳しくは wiki をご覧ください。アラビア文字などにはよく使われるそうです。試しに、自分もコピーしたら、そのマークはやはりコピーされます。 Sublime text などのテキストエディターで見てみると、そのマークが見えないですが、矢印キーではちゃんと一文字があることがわかります。
 今後、アドレスバーからコピーするようと伝えました。
 
 このとき、Notepad を気づいた:Windows の Notepad はすべてのマークなどはすべて削除されます。コピーした文字しか残らないです。
 :D やっと Notepad の使い道を見つかりました。

iOS7 WebView media query update

 今日、テスターがある変なバグを発見しました。それは、iOS 7 retina であるホームページのアイコンがずれました。
 もともt、background-size と background-position で sprite イメージをいろんなところにある小さいアイコンを表示していますが、その background-size が効かなくなって、background-position も正しく計算できないようになって、その現象が起きました。
 ただ、起きるところと起きないところがあって、どうしただろうなと思いました。詳しく見て、比較したら、css の書き方に問題があるような気がしていました。
 media query では、-webkit-device-pixel-ratio をチェックして、2 だったら、retina 用のイメージを background-image に再設定すべきですが、@2x のイメージをまた background-size でリサイズして、半分に変更して、また前の background-position が同じように使えます。
 問題あるところは background: url(../images/sprite@2x.png) no-repeat 0 0; となっていて、background-size はその前で設定していました。
 iOS6 以前だったら、background-image しか影響しないですが、 iOS7 だと、background の値がすべてリセットするそうです。そうすると、background-size が auto auto になり、リサイズが失敗します。
 直し方が簡単です、background の代わりに、background-image だけ設定して、他のものを触らないようにすれば、直ります。
 これは background というものは結構暗黙に設定する値があるので、明示的に各値を設定すべきだと思います。
    background -> background-color, background-image, background-repeat, background-position...

 ついてに、すべての背景イメージは sprite にすべきです。これはまた書きます。
 それでは。:)

2014年2月3日月曜日

CSS Tips 2: z-index

 複雑な Web App を作るときに、必ず overlay や、ダイアログなど、ある要素の上に他の要素を表示するケースが出てきます。このとき、CSS の z-index をよく使います。
 z-index は名前とおり、レイヤーを定義する属性です。例えば、z-index を 200 を指定すると、z-index の値がそれ以下の要素の上に、対象要素が表示されます。
 注意すべきところは z-index が position 属性と関係あります。いわば、 position が static 以外の要素しか z-index が効かないのです。
 position については前の記事をご参考ください。
 つまり、何で z-index が効かないと思ったら、要素の position を確認してから z-index を数字を確認すべきです。
 IE6 からこういう動きですので、現在のブラウザもその通りに動きます。知らないのはちょっと面倒なことになりますので、メモしておきます。

何で Auto test をやるか

 最近、隣の方になんで Auto test をやるかを聞かれました。。。今の時代はそれは主流だと答えましたが、いまいち彼がわかってないようですので、Test Driven Development からいろいろしゃべりました。
 テストって大事だと、どんなコードでもバグがあるとみんなはわかっているかもしれませんが、実はバグに関してかなり前から面白いエピソドがあります。
 コンピュターの原始時代、いくつかの天才より航空券のブッキングや、科学計算システムが作られました。これらのシステムは結構できてたそうです。(何十年前のことだから、実際使ったことがないから、聞いただけですが。でも、Linux のコードを読むとき、たまに天才がいるなと思いました。)その中、ある顧客が航空券を予約した時、本来人数を入力すべきところを大文字の”P”と間違って入れたそうでした。そうすると、システムが狂って、変な結果になりました。。。
 それから、みんな初めて使用者はエラーを起こすと気づいたそうです。それで、Validation などいろんなロジックをプログラムに追加されて、システム全体がめちゃくちゃ複雑になって行きました。もう一つは、コードが一人で書くものではないので、モジュール化しないと、機能がバラバラになると、もうメンテーできなくなるからです。
 また話を戻って、そのようなエラーとか、全数テストが不可能だから、境界値などのテスト理論が出てきました。人が一つ一つテストすると、時間がかかるし、大変だから、世の中のいいプログラマーはまたこれを軽減しようと、テスト専用のパッケージを作りました。JUnit とか、Jasmine とか、最近の Karmaや、Projector など、言語別、機能別のライブラリが結構出てきました。
 もう一つは Agile の普及より、Continuous Integration が常識になりつつあるから、一つのモジュールが何人か開発して、その後変更しつつ、テストしつつ、システムを完成して行きました。
 じゃ、何でアジャイルを使うかまた説明が必要になりましたけど。それは開発者の弱点が克服できないから、みんな協力して、一つの機能づつ、顧客とも確認しながら、前進して行くのはいい結果に結びつけるからです。
 それで、毎回の Sprint とか、毎回のリリースで、ある一人のテスターが全部テストをやり直すのは不可能ですので、Unit Test や、End to End テストのスクリプトによって、テストするのが速いし、バグもいちはやく発見できます。

 まぁ、ここまで話すと、多分もう理解するだろう。以前自分もあまり気づいてないことがあったりして、一応メモしとこう。

 それでは。

2014年1月21日火曜日

CSS tips 1:position:relative, absolute, fixed

 CSS には color などの属性以外、いろんなルールがあります。今までちょっといたい目にあったことをまとめておきました。↓
1 position : absolute, relative
 HTML のエレメントはブラウザのウィンドウのどこに表示するかはいろいろルールがあります。一般的にこれはブラウザ自身が決まります。例えば、div がブロック要素なので、display 属性を指定しないと、次の行から表示されます。
 要素のポジションを変えたい場合は、position を使います。もし position を指定しないと、デフォルトの値が static になります。
 position:relative の意味は 親と static の位置より、left/top/right/bottom で指定した値に従って、相対的に移動します。相対位置になります。
 position:absolute の意味は親の位置より、left/top/right/bottom で指定した値に従って、表示されます。absolute というのは絶対位置です。
 position: fixed はちょっと違います。Fixed は一般的にブラウザの document より位置が決まります。エレメントを常に表示したいときは使います。

 今までのプロジェクトでは relative と absolute はよく使います。なぜなら、デザインより、要素を位置を変えたいから。当たり前ですけど。
 注意すべきところは、親の位置から relative / absolute になります。この親は必ず position が static ではない親です。もし見つからなければ、 body エレメントに参考して、位置を決めます。
 例として、ツールチップを実現したいですが、 js ライブラリを使いたくない場合、css の hover で display 属性を none/block で切り替えます。ツールチップ span エレメントで定義している場合、この span の位置を変えたい場合、親の position を relative にして、left/top/right/bottom を指定しない場合は、 static と同じ位置になりますが、 span はこの親により位置が決まります。

それでは。