[JS] JavaScriptからメディアクエリの実装を判定

var mediaQueriesSupported = (function() {
	var supported = false;
	var styleSheet = document.styleSheets[0];
	var targetRuleIndex = (styleSheet.cssRules || styleSheet.rules).length;

	if ( styleSheet.insertRule ) {
		styleSheet.insertRule(
			'@media all and (min-width: 1px) { .mediaquery-testtarget { position: absolute; } }',
			targetRuleIndex
		);
	} else {
		return supported;
	}

	var d = document.createElement( 'div' );
	d.className = 'mediaquery-testtarget';
	document.body.appendChild( d );

	var style = d.currentStyle || document.defaultView.getComputedStyle( d, '' );
	supported = style.position === 'absolute';
	document.body.removeChild( d );

	return supported;
})();

メディアクエリが機能するか実際に試してその結果から判定。StyleSheetオブジェクトがinsertRuleメソッドを持たない場合(IE8以下)は、もうそこで非対応とみなしています。処理の都合上、DOM構築完了以後に記述する必要があります。

window.matchMedia

JavaScriptからメディアクエリを扱うための機能としてwindow.matchMediaというものがありますが、これの判定に関しては下記のような簡易なもので十分でないかと思います。

var matchMediaSupported = !!window.matchMedia;

matchMediaという名前のグローバル変数がどこかの何かによって定義されるのを想定する場合とか、もっとちゃんと判定したいなら実際に動かして機能をテストします。この判定によって最初のメディアクエリも対応していると見なして良いんじゃないかって気がしますが、実際はメディアクエリに対応しているけどwindow.matchMediaは対応していないブラウザが存在するので難しいところです。IE9とか。

またwindow.matchMediaが返すMediaQueryListオブジェクトが実装によってaddListenerメソッドを持ってたり持ってなかったりもします。Safari 5(iOS 4)とかのレアケースではありますが、ブレークポイントをトリガーに処理をハンドリングしたいとかの場合は気に留めておくと良いかもしれません。簡易な実装の判定は下記のようになるでしょうか。

var matchMediaAddListenerSupported = !!(window.matchMedia && window.matchMedia( 'all' ).addListener);

なおwindow.matchMediaをPolyfillする下記のようなライブラリもあり、MediaQueryList.addListenerのサポートも拡張で可能にしてくれています。

matchMedia.js


Canvas事始め

色々と思うところがあり、Canvasコンテンツ制作についての勉強を始めました。

とは言っても時間的なコストはなるべく抑えたいので、CanvasをFlashライクに扱えるらしいライブラリEaselJSを使うことにしました。また、環境面ではMicrosoft製JavaScriptコンパイル言語TypeScriptを導入しました。アロー関数式おいしいです。

作ってみたもの (古くないPCとブラウザ専用)
想像していたよりずっと動きが重い、というのが作ってみての率直な感想ですが、ただこれは自分が理解してないってだけで、もしかしたら同じ表現をするのでももっと早い書き方とかがあるのかも。

ずっと前に買ったFlash用の数学・物理学表現の本を引っ張り出してきてそれを参考にしながら作ってみましたが、やっぱり数値演算は難しいです…。とりあえずは継続することが大事なので、自分自身が楽しみながらやれるよう工夫しながら身に付けていき、今後の案件に備えようと思います。

※以下、デモのTypeScriptコード

“Canvas事始め” の続きを読む


[JS] Flipbook.jsをアップデート

以前に書いた記事で作ったパラパラマンガ用JSライブラリ「Flipbook.js」。パラパラする部分はimgのvisibilityを切り替える仕様だったのだけど、やっぱ早いは正義なのかなと思ったのでスプライトシートを背景画像に使ってbackground-positionをずらす仕様に作り変えてみた。

仕様が変わったことで以前のバージョンと同じ取り回しでは動かなくなっちゃったけどまあ別にいいよね。ついでと言ってはなんだけど1枚のスプライトシートで複数パターンのアニメーションをさせるための機能(setPos())などを追加してみた。

注意したいのが、スプライトシートがあまり大きくなるとiPhone(iPod) Safariでは制限に引っかかって画像が一切表示されなくなること。そういう意味では以前の仕様のままでも良かったのかなーと作り変えた後に思ったり。ま、いいか。

デモや使い方は以下より。
(※上述の理由によりデモ部分はiPhone Safariで表示されません)

Flipbook.js


[jQuery] DOMの構築待ちについて

先日、社内のWebデザイナーに標題についての解説をしました。自分の説明が悪くイマイチ理解してもらえなかった感がありましたが、JS(jQuery)を扱う上で重要かつ基礎的な知識の一つだと思いますし、改めて内容を整理しつつ記事にしてみました。

HTMLをほぼほぼ理解しているJS/jQuery初級者で、細かい用語などは自力で調べられる方が対象となります。

“[jQuery] DOMの構築待ちについて” の続きを読む


[JS] カーソル進入位置に合わせて変わるアニメーション

というロールオーバー演出が使われているFlashサイトを以前どこかで見かけました。残念ながらURLとかは忘れましたが、触ってて気持ち良かったことだけは覚えていたので、いつかどこかでパクらせて頂こうと思いJSで作ってみました。

デモ

最初は斜めも含めた8方向で作ってましたが、それだとカーソルを乗せたり離したりを繰り返した時の動きがフワフワと不安定な印象で、あんまり気持ちよくなかったため4方向にしました。要素のサイズがある程度以上大きい場合は8方向の方がしっくりくると思います。

主要なコードは以下。

HTML

<div class="box">
	<div class="overlay"></div>
</div>

CSS

.box {
	position: relative;
	width: 60px;
	height: 60px;
	overflow: hidden;
	background: #333;
}
.overlay {
	position: absolute;
	top: 60px;
	width: 60px;
	height: 60px;
}

JavaScript(jQuery)

jQuery( function( $ ) {

	var hoverHandler = function( e ) {

		var isMouseEnter = e.type === 'mouseenter',
		$box = $( this ),
		$overlay = $( '.overlay', $box ),
		overlayW = $overlay.width(),
		mouseX = e.clientX - ($box.offset().left + overlayW / 2),
		mouseY = e.clientY - ($box.offset().top + overlayW / 2),
		degrees = Math.atan2( mouseY, mouseX ) * 180 / Math.PI,
		style = {};

		if ( degrees > -135 && degrees <= -45 ) {
			style.top = -overlayW;
			style.left = 0;
		} else if ( degrees > -45 && degrees <= 45 ) {
			style.top = 0;
			style.left = overlayW;
		} else if ( degrees > 45 && degrees <= 135 ) {
			style.top = overlayW;
			style.left = 0;
		} else {
			style.top = 0;
			style.left = -overlayW;
		}

		$overlay
		.css( {
			top: isMouseEnter ? style.top : 0,
			left: isMouseEnter ? style.left : 0
		} )
		.stop( true )
		.animate( {
			top: isMouseEnter ? 0 : style.top,
			left: isMouseEnter ? 0 : style.left
		}, 200 );

	};

	$( '.box' )
	.on('mouseenter', hoverHandler )
	.on('mouseleave', hoverHandler );

});

僕に算数の知識とやわらかい頭脳があれば、もうちょいなんとかなるんだけど。そもそも角度から求めるべきじゃないのかな?前述のFlashサイトではどうやってたんだろう…