Archive for 4月, 2011

[CSS] 立体的なレイアウトを組むコツ Vol.1(positionの基礎知識)


2011
04.29

Hello everyone.

なんだか海外の方からの反響が結構ある事に驚いています、私は英語の授業をサボり続けた事を今になって後悔しています。

返信とか凄い片言なんだけど大丈夫かな?

 

さて今回のコラムは、立体的なレイアウトを組むテクニックを2回に分けて紹介して行きます。

お勉強しましょう。

テクニックと言うよりコツですね、レイアウト構造を設計出来るようになれば事実上 html 上で再現出来ない2次元レイアウトなど存在しなくなりますので苦手な方は是非とも熟読して行って下さい。

 

さて、立体的なレイアウトと言えば外せないのが CSS の position プロパティです。

まずはこれをきちんと理解しましょう、特に positionrelativeabsolute はきちんと理解して使わないと何だか解らなくなって、要素が凄い所に飛んで行っちゃったりと収集がつかなくなるので、きちんと管理しておくのもポイントですね。

 

position プロパティの仕様
概要
static デフォルト値、何も指定しなかったらこれが指定されます。
何も指定していない状態なので toprightbottomleft などのプロパティは適応されません、イメージ的には背景に張り付いていると言うのが近い表現だと思います。当然ですが高さと幅を保持します。
relative 指定した要素を相対位置へ配置します、この相対位置の意味が良く解らないと言う話しは良く聞きますので後ほど図解します。
この値が指定されると toprightbottomleft のプロパティが有効になります、この時のイメージは身を乗り出していると言うのが近いと思います。これは高さと幅を取りながら位置をずらす事が出来るからです。
absolute 指定した要素を絶対位置へ配置します、これは relative と並べて書くと解りやすいので後ほど図解にて。
relative と同じく指定するとtoprightbottomleft のプロパティが有効になります、イメージ的には飛ばしている状態です。これは完全に任意の位置にずらすため高さと幅を放棄します。
この値には特徴があり、親のブロック要素に static 以外の値が指定されているとその親ボックスの左上を起点とするが、逆に static が指定されている(=何も指定していない)とウインドウの左上を起点として位置が決まります。
fixed 指定した要素を絶対位置に配置し、スクロールによる画面移動を無視してその場に留まります。
非常にユニークな値ですが、IE6 など諸問題があって積極的には使われていない印象があります。
有効になるプロパティやイメージも absolute と同じです、単純に一回決めた位置から動かないと言う事を覚えておけば良いでしょう。

 

relative と absolute の性質

それでは早速両者の性質について図解していきます、解り辛い文面を読むよりヴィジュアルを見て感覚を掴むのが良いでしょう。

 

inline 要素に relative(相対位置)を指定すると…

1
2
3
4
5
span {
    position: relative;
    top: 10px;
    left: 10px;
}

inline要素にrelativeをかけると

こうなります、赤いクロスの中心が起点となります。

要するに相対位置に配置すると言うのは static 状態(何も指定していない)の時に有るべき位置から◯◯px ずらすと言う事です、大きな特徴として高さや幅を保持すると言う点も見逃してはならないでしょう。図を見ると「どうですか?」の位置がずれていませんよね。

イメージとして身を乗り出していると比喩したのはこう言う理由からです、block 要素だともっと解りやすいです。

 

 

block 要素に relative(相対位置)を指定すると…

1
2
3
4
5
p {
    position: relative;
    top: 10px;
    left: 10px;
}

block要素のrelativeをかけると

相対位置=本来有るべき位置、から上と左 10px ずつずれた位置に block 要素が移動し、高さと幅は保持されるので foofoo の block は位置ズレを起こしません。結果、少し重なる形で表示されます。

 

 

inline 要素に absolute(絶対位置)を指定すると…

 

親要素に static が指定されている(特に何も指定していないデフォルト状態)場合

1
2
3
4
5
6
7
8
9
div {
    /* 特に何も指定していない */
}

span {
    position: absolute;
    left: 10px;
    top: 10px;
}

親要素がstaticの時にinline要素にabsoluteをかけると

親要素に対して何も指定していない場合や static を指定している場合、ウインドウの左上が起点になります。

ここで注目したいのが飛ばした時に残されたテキストです、緑色の部分が抜け落ちてテキストが前に詰められています。絶対位置に要素を飛ばした時はその高さや幅の情報を破棄します。

と言う訳で飛ばしていると比喩しました、もうそこには無いものとして扱われますからね。

 

 

親要素に static 以外が指定されている場合

1
2
3
4
5
6
7
8
9
div {
    position: relative;
}

span {
    position: absolute;
    left: 10px;
    top: 10px;
}

親要素がstatic以外の時にinline要素にabsoluteをかけると

対して今度は親要素に static 以外、今回は relative を指定してみました。

すると起点が親要素の左上になりますので、タイトルに少し被る感じにずれたのが解ります。

起点が変わるだけで、テキストは抜けた分が詰められているなど同じ挙動なのも確認出来ますね。

 

 

block 要素に absolute(絶対位置)を指定すると…

 

親要素に static が指定されている(特に何も指定していないデフォルト状態)場合

1
2
3
4
5
6
7
8
9
div {
    /* 特に何も指定していない */
}

p {
    position: absolute;
    left: 10px;
    top: 10px;
}

親要素がstaticの時にblock要素にabsoluteをかけると

ここまで来ると予想出来るようになって来ているのでは無いでしょうか?

例によって static 状態なのでウインドウの左上が起点、要素は高さと幅の情報を破棄するので foofoo のブロックは前に詰められます。

※飛ばした block 要素が伸びているのは単純に width が auto なので…同じ形のまま飛ばしたければ飛ばす要素の width も指定しておけば良いです。

 

 

親要素に static 以外が指定されている場合

1
2
3
4
5
6
7
8
9
div {
    position: relative;
}

p {
    position: absolute;
    left: 10px;
    top: 10px;
}

親要素がstatic以外の時にblock要素にabsoluteをかけると

そして最後は親要素を static じゃない状態にした時のサンプルです、起点が変わっているだけで foofoo の block は前に詰められていますね。

 

 

以上が実際にどう言う挙動をするかと言う実例を交えた解説です、html を作成していると思わぬズレ方や崩れ方に遭遇する事があると思いますが、そのおかしくなった理由にどれだけ早く気づけるかがとても重要です、だからこの知識もきっとあなたの役に立つ事でしょう!

 

さて、今回はここまで。

次回はこの知識を前提につまりこうすれば思い通りの結果を得られると言うテンプレ的方法や設計するコツを書きたいと思いますので、今の時点では…

 

へー、position ってこんな感じだったんだ。

 

ぐらいで良いです。

このコラムを完走して理解した時、あなたはきっと自由自在に立体レイアウトを組めるようになっているハズです。

 

それではまた。

 

ブラウザから100%の状態でPDFを開きたい時


2011
04.25

皆さんおはようございます、何やら朝の通り雨が凄かった大阪です。

さて、今回は単発エントリー。クライアント様より

 

PDF 開いた時に凄い大きく表示されるよ、100%で表示して欲しいよ!

 

との要望がありまして、反射的に adobe reader の設定でデフォ 100% にすれば良く無いかい?と思いましたが、IE みたいにブラウザ上で直接 PDF が開ける場合は原寸表示出来た方が良いですね。と言う訳で軽く調べてみた。

 

1
<a href="./hoge.pdf#zoom=100" target="_blank">PDFだよ</a>

 

href 属性の URL の最後に「#zoom=任意の倍率」これで行けましたね、取りあえず IE しかチェックしてないけど要望は IE だけだったのでこれで良しとしましょう。

そもそも Firefox とかだとダウンロードして adobe reader で開くから、それこそホントに設定して頂戴よとしか言えませんしね。

 

それではまた。

 

[IE7|IE8] jQueryのfadeIn/fadeOutした時にpng画像が変になる時のTips


2011
04.22

悪名高き IE6 がついに Yahoo さんからも干されてデベロッパー歓喜!となってから、それなりに時間が過ぎましたね。

あなたの会社では IE6 のサポート状況は如何なものでしょう?当社では Yahoo さんもこうしていますよ、せめて IE7 にしましょ?ね?ね?と言う地道な活動を続けて、それなりに効果が出ています。

実際 IE6 をサポートしなければ CSS がシンプルに書けたり、png のアルファチャンネルをプラグイン無しで描画出来…で、き…

 

出来てないじゃん!

 

と言う訳で今回は IE7 と IE8 で再現を確認したアルファチャンネルの描画バグをフィックスします、症状は下記のような感じ。

  • 普通に img 要素で描画する分には問題無い
  • 既に描画されている要素の opacity を弄るとアルファチャンネル部分が黒くなる

普通にサイトを作っていて、png ファイルの要素の opacity を弄るなんて事はまず無さそうですが、最近はスタイリッシュにファッファさせたくなるじゃないですか?マウスオーバーしたらメニューが、みたいな。

それをお手軽に使いたい時はなんと言っても jQuery の fadeIn / fadeOut ですよね、例えば fadeIn は要素の opacity を一旦 0 にしてから display:block 状態に、そこから opacity を 1 になるまで加算すると言う処理を勝手にやってくれます。

つまり opacity 弄っちゃってます、IE7 と IE8 はここにアルファチャンネルが含まれた png 画像が描画されていると残念な黒い何かが出てしまうと言う訳です。

M$さんは「png ファイルのアルファチャンネルに対応しました(笑)」って言ってたのにね。

 

それではサクッとフィックスしましょう、解決法は AlphaImageLoader を引き続き使う。これで良いと思います、IE 自慢の独自フィルターだし。そもそも IE しかこの症状出ないから、自己解決させるのが最上の手段でしょう。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
$(function() {
    if(navigator.userAgent.indexOf("MSIE") != -1) {
        $('img').each(function() {
            if($(this).attr('src').indexOf('.png') != -1) {
                $(this).css({
                    'filter': 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' +
                    $(this).attr('src') +
                    '", sizingMethod="scale");'
                });
            }
        });
    }
});

ページの読み込みが完了したらブラウザ判定、どうやら IE だなとなれば html 上の img 要素全てを each して、src 属性に “.png” が含まれていたら AlphaImageLoader をかける。

 

これで IE7 と IE8 で思う存分ファッファ出来るようになる、IE6 は多分これだと駄目だと思うけど。

Yahoo さんの非推奨ブラウザなので今回は無視する方向で、Yahoo さんいつもスケープゴートになってくれてありがとう。

 

それではまた。

 

JavaScript のソースは隠蔽するべきか? Vol.4


2011
04.21

皆さんこんにちわ、JavaScript のソース隠蔽について考えるコラムも今回で一応の結論を出そうと思います。

今回はもう既に色々出来上がっているので、無駄な前置きはググッと我慢して進めます。

 

それではこのミッションを遂行するための手持ち武器をまとめます。

  • JavaScript による navigator.userAgent と navigator.platform のチェックで偽装を認めない認証
  • Ajax による非同期なソース展開、送受信は POST とする事で URL 欄からの単純な攻撃を防ぐ
  • 開発は通常通り JavaScriptファイル(.js)で行い、呼び出す時は PHP 内でファイルを読み込んで文字列のみ送信
  • 認証を通らない時は何か画面に表示する
  • JS を切られたらもうそれは無視する

こんな感じですね、それでは解説を交え早速実装して行きましょう。

 

取りあえずファイル構成はこんな感じで想定してます。

/index.html
/js/jquery.js
/js/hoge.js
/js/foo.js
/js/piyo.php

適当なディレクトリに上記構成でファイルを作成してください、foo.js隠蔽したいファイルです。
条件を満たすと非同期に foo.js の中身が index.html に送信されるようにします。

 

まずは html 部分から、今回と言うか当 blog ではほぼ毎回 jQuery を使います、言うまでも無く色々と捗るので。

head 要素内に…

1
2
3
<script src="./js/jquery.js" type="text/javascript"></script>
<script src="./js/hoge.js" type="text/javascript"></script>
<script id="moge" type="text/javascript"></script>

jquery.js はご存知のライブラリ、まず呼び出しておきましょう。
hoge.js は判定文を書きます。
3行目は入れ子です、最終的に全て条件を満たすとこの中にソースを送信します。

 

次は hoge.js の中身です、前回の条件を踏まえて2つの condition を書いて上げましょう。

1
2
3
4
5
6
7
$(function() {
    if(navigator.platform.indexOf('iPhone') != -1 && navigator.userAgent.indexOf('iPhone') != -1) {
        $('#hoge').load('./js/piyo.php', {mode:'hoge'});
    } else {
        alert('error');
    }
});

iPhone シミュレータもハネたい場合は2行目を

1
if(navigator.platform == 'iPhone' && navigator.userAgent.indexOf('iPhone') != -1) {

にすれば良いかと思います。

navigator.userAgent も判定しているのは、将来的に webkit じゃないブラウザが出て来たら…と思うのですが  iOS の仕様的にあり得ない気もするので無くても良いと思います。

 

最後に piyo.php の中身です、使い回しが効くように switch で書いてみました。

1
2
3
4
5
6
7
8
9
switch($_POST['mode']) {
    case 'hoge':
        print(file_get_contents('./foo.js'));
        break;

    default:
        print('error');
        break;
}

 

えーと、これでおしまいです。

今回前置きを書かなかったのは、このシンプルなコードを書くために計3回もの記事を消費した訳で。このコラム自体が壮大な前置きだったんだよ!!と言う事に気づいたからです。

いや、まぁ実際に検証してみるってのは大事な事だと思うので無駄では無い。ハズ。

 

気を取り直して解説、

  • http request が来た
  • hoge.js Line:2 で判定
    • どちらも条件を満たした(次へ)
    • どちらかの条件が満たせなかった(エラー出力などして終了)
  • hoge.js Line:3 で id=hoge(script の入れ子)に piyo.php を呼び出す、mode と言うキーで hoge と言う文字列を POST する
  • piyo.php はコールされると $_POST[‘mode’] を見て分岐処理を行う、何も渡されずに呼ばれたら error と言う文字列を返す
  • piyo.php Line:3 にだけ書かれた foo.js のパスからファイルの内容をロードして print を実行、サーバサイドなのでブラウザからは解らない
  • PHP でプリント(出力)されたものは POST 値としてブラウザに返される、jQuery の .load() の効果で index.html に書かれた入れ子の<script id="hoge">〜</script>の間に返された文字列が出力される
  • 出力されると同時にその JS は勝手に実行される

こう言う動きになります、シンプルで良いですね。

 

切ない人の為に上記を実装したサンプルをこちらにアップしました、iPhone 以外からだときっと動かないハズ。

iPhone でアクセスするとやっつけ感満載のパズルゲームが始まると思います、何となく html5 の canvas 使ってみたくてサ。

 

そしてこれは下記環境下なら恐らく上手く隠蔽出来るハズ

  • ソースの保存や Firebug 系のツールが無い環境
  • JS の navigator.platform が偽装出来ない環境

あんまり調べてないからアレですけど、iOS 系なら大丈夫なんじゃなかろうか?どちらにせよ結構な手間をかけないとソースは見えないと思います。

 

 

いやー、長かったですね。お付き合い頂いた皆様、お疲れさまです。

今回良く解ったのは普通の Web ブラウザ上で JS のソースを完全に隠蔽するのは不可能、と言う事です。

完全に隠蔽した Web App を作りたいのなら、一旦素の状態で完成させた物をネイティブアプリの入れ子にリソースを全て埋め込んで、アプリの機能で html を表示して使うアプリをリリースする。と言う方法しか無いんじゃなかろうかと思います、何だか敗北感が凄いですがそう言うモノなんでしょうね。

 

では、最後に締めの言葉を。

 

デバイス限定だけど、そんなに手間をかけずに見え辛くするのは可能だよ!
やりたい人はやっても良いと思うよ!!

 

嗚呼、やはりこうなってしまうんですね。

今回の事は雑学として覚えておけば、妥協点のポイントとして役立つ時が来るかもしれません。

 

それではまた。

 

1 | 2 | 3 | 4

 

JavaScript のソースは隠蔽するべきか? Vol.3


2011
04.20

本日もやります、だんだんとノッてきましたしね。

ノリ過ぎて JavaScript の隠蔽の是非を問うようなタイトルなのに、何としても隠蔽してやろうと言う趣旨に変わって来ていますね。

サーチエンジン的に言うとタイトルと内容が一致していない評価が低いコンテンツになっているかも知れませんが、最終的な手間や再現可能環境をまとめて「JavaScript のソースは○○した方が良いかもね!」と強引に締める事で誤魔化そうと考えているので問題無いハズです。

 

それでは前回のおさらいから始めましょう。

  • サーバサイドでは精密なデバイス判定は難しい
  • ローカルサイトでも単純な UserAgent 比較だけではお話にならない
  • ラスボスは Mac Safari5 だった(今の所)

こんな感じでしょうか、要するに Mac Safari5 を攻略すれば取りあえず Oh Yeah と言う事で話しを進めます。

余談ですが iPhone のデバイス判定については色々調べてみました、中にはスクリーンサイズを取得して…と言う方法があり目から鱗だったワケですが結構簡単に破れちゃうなぁと言う事で今回は見送りました。

検証した所 iPhone4 の retina ディスプレイは 640 × 960 なのですが、3G/3GS との下位互換のためにスクリーンサイズは 320 × 480 が返される仕様でした。そんなサイズの PC モニタなんて無いですから一見強そうなんですが、VirtualPC や VMFusion みたいなバーチャルコンソールのシングルウィンドウモードで、その大きさにマウスでちょちょいとリサイズすればあっさり突破出来てしまいました。中々厳しいです。

 

navigator オブジェクトを突っついてみよう

前回目星をつけていると言いましたが、この Object には UserAgent の他にも様々な情報が格納されています。

詳しくは初めてのホームページ講座さんなんかで、navigator オブジェクトの仕様とか説明してくれているので眺めてみましょう。

パッと見だと navigator.appName とか navigator.platform 辺りはかなり有望なんじゃ無いでしょうか?だって通常はそんなの偽装する意味がないもの。

 

と言う事で検証用ファイルを作ります、body 要素内に script 要素を書いて…

1
2
3
4
5
6
7
document.write(
'appCodeName : ' + navigator.appCodeName + '改行' +
'appName : ' + navigator.appName + '改行' +
'appVersion : ' + navigator.appVersion + '改行' +
'anguage : ' + navigator.language + '改行' +
'platform : ' + navigator.platform
);

こんな感じで良いかな、解れば良いよね。そんな事よりこのコードビュープラグイン、<br />って書けないんだね!気持ち悪いけど「改行=<br />」と思って下さい。

例によって切ない人用にこちらにアップロードしましたので、色々見て行きましょう。

 

iPhone4 実機 + Safari5

appCodeName : Mozilla
appName : Netscape
appVersion : 5.0 (iPhone; U; CPU iPhone OS 4_3_2 like Mac OS X; ja-jp) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8H7 Safari/6533.18.5
language : ja-jp
platform : iPhone

これがベースとなります、これと違う点を発見すれば良いですね。

 

Mac OSX 10.6 + Firefox4(FireMobileSimulator)

appCodeName : Mozilla
appName : Netscape
appVersion : 5.0 (Macintosh)
language : ja-JP-mac
platform : MacIntel

なんか Firefox 可愛い。

 

Mac OSX 10.6 + Safari5(Developer Tools)

appCodeName : Mozilla
appName : Netscape
appVersion : 5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7
language : ja-jp
platform : MacIntel

キタコレ!appVersion は偽装してるみたいだけど、platform は流石にそのままですね!

 

ラスボス破れたり

 

と、言う事で判定は JavaScript で UserAgent と Platform を見る事にしましょう。

 

これで全ての武器が揃った訳ですが、海千山千の読者様は突っ込み所満載だなオイ!と思われているでしょう。

そうです、沢山問題がありますので弱点も今回のウチにまとめておきましょう。

  • navigator の中身全てを偽装するプラグインとかあったら負け
  • Safari5 より凄い開発ツールのあるブラウザがあると負け
  • 無くてもそう言うのを作れば良いだけなので負け

なんと言うか穴だらけですね!それでもまぁ市販のゲームだって逆アセかけて解析したり出来るしさ、データ周りだけサーバサイドで処理して送信するとかすればもう及第点と言う事で一つ。

次回はついにこの検証結果を踏まえた上での隠蔽プログラムの実装を紹介して終わろうと思います、もう少しお付き合いください。

 

それではまた。

 

1 | 2 | 3 | 4

 

オマケ:真のラスボス(ADP の公式シミュレータ)

真のラスボス
Platform は iPhone Simulator になってますね、ここは正直に書くのが礼儀的なものなのかも知れない。