pig's diary

何でも忘れるので万年初心者ね

本日勉強会を終えるまでの流れ

CSS3アニメーションを、(:hoverとかでなく)JSで起動して動かします。

  1. 動的にDOMを操作する
    • どこから探す? - DOM と それ以外
    • Firebugから要素を見つけてみる&操作する
    • >script<タグ内で操作する
    • もっと短く書く - DOMライブラリ利用
    • ところで
  2. CSS2との組み合わせ
    • かんたんな例 - DOMはほぼCSSありき
    • CSSを用意しておく - idやclassでの指定
    • 値も動的に - CSSプロパティを毎回設定
    • ところで
      • JSがOFFの人 - 累進的拡張でページを作る
  3. CSS3との組み合わせ
    • かんたんな例 - 時計
    • ちょっと複雑な例 - よくあるiPhone広告
    • ちょっと複雑な例2 - IMGギャラリー(半パクリ)
  4. 終わりに:参考にしたサイト/ページ
  5. 〜退室〜

動的にDOMを操作する

そもそもDOM操作とはどうやるんでしょう?

どこから探す? - DOM と それ以外

HTML要素はDOMに従って指定します。 DOMは、1998年にW3Cが勧告して決まったみたいです。

  • 昔 ・・・書き方がバラバラ
  • 現在・・・DOM(書き方を統一)

ダイナミックHTML - Wikipedia

当時(〜1997年ごろ)はJavaScriptからHTMLを参照、制御する方式が各社不統一であり、ウェブブラウザごとに別々のJavaScriptを書く必要があった。この状況を打開すべく1998年10月にW3Cはクライアントサイドスクリプト言語とHTMLドキュメントの緩衝材としての役割を果たすDocument Object Model(DOM)を勧告した。これによりDOMをサポートする新型のブラウザ(Internet Explorer6や、Netscape7.1、Mozilla FirefoxOperaなど)であれば、ブラウザを問わずひとつの記述で HTMLドキュメントを参照、制御できるようになった。


ドキュメントオブジェクトモデル(DOM)- とほほのJavaScriptリファレンス

DOM は Document Object Model の略です。HTML や XML で記述された各要素を取り扱うための標準インタフェースとして1998年に W3C によって勧告されました。仕様のコアとなる部分は特定の言語には依存しない形式で定義され、追加として、JavaScript などの言語へのマッピングが紹介されています。IE の document.all による DHTML や Netscape 4.* のレイヤに代わる機能として、IE5.0、Netscape 6.0 が DOM をサポートしています。ここでは、DOM の主な機能のみを紹介します。

Firebugから要素を見つけてみる&操作する

公開されているページを、FirebugでDOM操作してみましょう

var element = document.getElementById('defaultAd');

element.parentNode.removeChild(element);
// 「自分を消去する」というメソッドは無いので、
// 「親から見て自分にあたる子要素を消去」としています
<script>タグ内で操作する

ページ内で、DOM操作をしてみましょう。

&lt;script&gt;
window.onload = function(){
    var element = document.getElementById('defaultAd');

    element.parentNode.removeChild(element);
}
&lt;/script&gt;
もっと短く書く - DOMライブラリ利用

DOMライブラリを使って、短く書きましょう 「getElementBy...」などを短縮して書くことができます。

// jQuery
&lt;script src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&lt;script&gt;
$(function(){
	$(&quot;#defaultAd&quot;).remove();
});
&lt;/script&gt;


// Prototype
&lt;script src=&quot;http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&lt;script&gt;
window.onload = function(){
	$(&quot;defaultAd&quot;).remove();
}
&lt;/script&gt;

DOM操作を用いて、要素を見つけ出すながれはお分かりいただけたでしょうか。

ところで
      • なぜwindow.onloadで実行するのか

DOM操作は、HTML要素を探し出す操作です。Javascriptが実行されたタイミングに、まだ要素がロードし終わっていなければ、その要素を見つけ出すことはできず「undefined」になります。 方法としては、headタグ内で「window.onload」イベントにDOM関連の記述をまとめるか、bodyタグの閉じタグの直前にJSを記述するという方法があります。

iframeで他のページを表示しても、Javascriptは安全面を考慮し、中身のDOM操作をすることができない設計になっています。

CSS2との組み合わせ

では、DOM操作とCSSを組み合わせて書いてみます。 イメージとしては、要素にclass値などをくっつけたり消去したりしていく感じです

かんたんな例 - DOMはほぼCSSありき

まだ存在しない要素「#demo01」に対してCSSを予め書いておき、 あとからJS側で動的に要素を生成してbodyタグ内にほうりこみます。

#demo01 {
position:absolute;left:200px; top:100px; width:160px; height:120px;background-color:#f99;
}
function loadElement(){
	var d = document.createElement('div');
	d.setAttribute('id','demo01');
	d.innerHTML = '成功−−−。';
	var b = document.getElementsByTagName('body')[0];
	b.appendChild(d);
}

書くのが大変なので、以後jQueryで書いてみます。
jQueryで書くと、こうなります。(CSSはおなじ)

function loadElement(){
	$('<div>')
		.text('成功ーーー。')
		.attr('id','demo01')
		.appendTo('body:eq(0)');
}
</div>
    1. CSSを書く、
    2. JSでDOMを操作する

の基本的な流れはお分かりいただけたでしょうか

CSSを用意しておく - idやclassでの指定

classを付け替えて、スタイルを動的に変更してみましょう。 CSSでは、class「red」と「blue」に対し、予めスタイルを指定しておきます。

#element {
position:absolute;left:200px; top:100px; width:160px; height:120px;background-color:#f99;
}
#element.red {background-color:red; left:80px;}
#element.blue {background-color:blue; left:250px;color:#fff;}
function red(){
	$('#element').removeClass().addClass('red');
}
function blue(){
	$('#element').removeClass().addClass('blue');
}

☆「addClass()」を繰り返すと、class値が増えていく だけですので、「消してから、追加する」のがポイントです。
こうやって、classを切り替えるだけでスタイルをまるっきり変えることができます。 「display:none」を使って、消したり、表示したりすることもできます。

値も動的に - インラインCSSを設定

こんどは、予めCSSを用意しておくのではなく、Javascript側でCSS(==style属性)を指定してみましょう。 JSで指定するのは、メモリを食いますから避けたほうがいいかもしれませんが、動的な値を指定したい場合は、JSでの設定が活躍します。

#element {
position:absolute;left:200px; top:100px; width:160px; height:120px;background-color:#f99;
}
function red(){
	$('#element').removeClass().addClass('red');
}
function blue(){
	$('#element').removeClass().addClass('blue');
}
$(function(){
	$(document).click(function(){
		$('#element').css({
			left: Math.random()*300,
			top: Math.random() *200
		});
	});
});

demo4
このようにランダム値や、ウィンドウサイズに従って計算した値をCSSに指定したい場合は、JSで要素に直接CSSを指定することでハッピーになれます。


CSSとJSの組み合わせについておわかりいただけたでしょうか。2つの優先順位は、いつもこうです。

  1. CSSを書く(外部CSS、head内CSS
  2. JSでDOM操作をする
  3. (必要があれば、JSでインラインCSSを操作する)

CSSのルールはJSより先に定義されるべきです。 定義したCSSルールは、その後どのように動的に操作されたDOM要素に対しても有効であるということを理解いただけたと思います

ところで
  • JSがOFFの人 - 累進的拡張でページを作る

JSがOFFの人も、ページの「情報」にはアクセスできるように設計すべきです。 たとえば、CSSで「display:none;」だったテキストを、ボタンクリックによって「display:block;」で表示させるべきではありません。また、テキストを動的に読み込ませて表示するのも注意する必要があります。
下の記事では、そういった構築を行う手順について書かれています。
累進的拡張(Progressive Enhancement) | マイコミジャーナル

最小限の共通部分から開始する
構造に対してデザインする
最低限のデバイスに対して機能を追加する
アクセス性に対して機能を追加する
構造化されたレイアウトに対してレイアウトマークアップスタイルシートを追加する
リンクを使って最低限のスタイルシートを追加する
JavaScriptCSSで振る舞いを追加する
うまく動作しないブラウザ向けにハックを追加する
最新のブラウザ向けにスタイルを定義する

JSによって表示される情報は、ロード完了後にJSによって非表示にしておく、という配慮が必要です。

CSS3との組み合わせ

やっと本題です。CSS3アニメーションとJSを組み合わせて使ってみましょう。 まず、さっきやった「赤、青」のdemoを、もう一度見てみましょう。

#element {
position:absolute;left:200px; top:100px; width:160px; height:120px;background-color:#f99;
}
#element.red {background-color:red; left:80px;}
#element.blue {background-color:blue; left:250px;color:#fff;}
function red(){
	$('#element').removeClass().addClass('red');
}
function blue(){
	$('#element').removeClass().addClass('blue');
}

demo3

このCSS部分に、アニメーション指定をして見ましょう。

#element {
position:absolute;left:200px; top:100px; width:160px; height:120px;background-color:#f99;
-webkit-transition: background-color 1s linear 0 , left 1s ease 0; /*ここのみ追加*/
}
#element.red {background-color:red; left:80px;}
#element.blue {background-color:blue; left:250px;color:#fff;}
function red(){
	$('#element').removeClass().addClass('red');
}
function blue(){
	$('#element').removeClass().addClass('blue');
}

ソースはほとんど変わりません。CSSに1行追加しただけでハッピーです。JSもいじっていません。
上の例ではheadタグ内のCSSのみでしたが、動的に指定するとどうでしょうか。

#element {
position:absolute;left:200px; top:100px; width:160px; height:120px;background-color:#f99;
-webkit-transition: left 1s ease 0, top .6s ease;
}
function red(){
	$('#element').removeClass().addClass('red');
}
function blue(){
	$('#element').removeClass().addClass('blue');
}
$(function(){
	$(document).click(function(){
		$('#element').css({
			left: Math.random()*300,
			top: Math.random() *200
		});
	});
});

この例も、head内CSSに1行追加しただけです。興奮しているのは私だけでしょうか?描画に関してCSSはいつも、最も優先度が高い状態で有効なので、JSによってclass値が入れ替えられると、その後の動作は必ずCSSに従って描画されることになります。

例えば - 時計

ご存知のとおり「transform」はCSS3の目玉プロパティの一つです。例えば、これまではHTMLを「傾ける」ことができませんでしたが、「transform」ならそれができます。誰かが時計を作ったようです。

とても素晴らしいです。でも、寝るときに音が気になりそうなので、CSSに1行追加して秒針をスムースに移動させてみましょう。

#sec {
    -webkit-transition: -webkit-transform 1s linear; /* 追記 */
}

非常に、スムースになりました。

ちょっと複雑な例

また別の誰かが、イメージギャラリーを作ったようです。数がかなりあり、大したものです。トランジションにたくさんの種類がありとても美しいです。HTMLソースはブワーッと書かれてて読みにくいですが、そのうちだれかがjQueryプラグインにしてくれると思います。

ちょっと複雑な例2

iPhone広告によくある、スクロールしたら追従してくる広告を作ってみました。

.floatingAd {
position:absolute;width:260px;text-align:center;
-webkit-transition: top 2s ease;
margin:0;padding:0;
}
.floatingAdInner {
text-align:left;padding:10px;overflow:hidden;margin-bottom:0;
background:#f99;
background: -webkit-gradient(linear, left top, left bottom, from(#66ff00), to(#00aaff));-webkit-border-radius:20px;
}
.floatingAd > img {margin:0;padding:0;vertical-align:top;}
.floatingAdInner > img {float:left;margin-right:10px;-webkit-border-radius:6px;}
.floatingAdInner > strong {display:block;}
.floatingAdInner > span.closeButton {display:block;text-align:right;}
(function(jQuery) {
  function privateFunctionForPlugin(locale) {
  };
  
  jQuery.fn.floatingAd = function(options) {
/*    var options = jQuery.extend({
        format: "#,###.00",
        locale: "us"
    },options);*/
    var WINDOW_HEIGHT = $(window).height();
    var WINDOW_WIDTH  = $(window).width();
    
    var scrollTop = 0;
    $(window).scroll(function(){
    	offTop = $(this).scrollTop() + WINDOW_HEIGHT;
    });
    
    return this.each(function(){
      // thisを使ってここから書いて行く
      var self = $(this);
      
      var _w = $(this).outerWidth();
      var _h = $(this).outerHeight();
      
      $('.closeButton', this).click(function(){
      	self.remove();
      });
      
      var currentTop = 0;
      var targetTop  = 0;
			
			
			var offsetBottom = 20;
			
      $(this).css({
      	'left':(WINDOW_WIDTH - _w) /2,
      	'top': $(window).scrollTop()+ WINDOW_HEIGHT  - _h -offsetBottom
      });
      
			$(window).scroll(function(){
	    	if(targetTop-1<currentTop&& targetTop+1>currentTop){
	    		self.css({top:offTop - _h -offsetBottom});
	    	} else {
	    		
	    	}
	    });
      
    });
  };
})(jQuery);

$(function(){
	$('.floatingAd').floatingAd();
});
<!--body閉じタグの直前とかに-->
<div class="floatingAd">
	<div class="floatingAdInner">
		<img src="katy_perry.jpg" alt="" />
		<strong>ケイティーペリー</strong><span><a href="http://www.flickr.com/photos/machechy/4139754341/sizes/sq/">by machechyp</a></span><span class="closeButton">×閉じる</span>
		
	</div><img src="arrow.png" alt="" />
</div>

以上になります。