月別アーカイブ: 2012年5月

[CSS/JS] CSSのプロパティ名をベンダープレフィックス付きで取得

※2012.05.19 : 記事の内容とスクリプトを修正しました。
※2012.08.27 : 以下のコードを改修したものがこちらにあります→


表題のような事がしたかったので、そのような関数を書いてみました。

var cssProp = function( name, camelcase ) {

	var index = (typeof camelcase === 'undefined') ? 0 : camelcase ? 0 : 1,
		cacheObj,
		element,
		prop;

	if ( !cssProp.cache ) {
		cssProp.cache = {
			element: document.createElement( 'div' ),
			vendor: (/webkit/i).test( navigator.appVersion ) ? ['webkit', '-webkit-'] :
				(/firefox/i).test( navigator.userAgent ) ? ['Moz', '-moz-'] :
				(/msie/i).test( navigator.userAgent ) ? ['ms', '-ms-'] :
				'opera' in window ? ['O', '-o-'] :
				'',
			transitionEvent: {
				webkit: 'webkitTransitionEnd',
				Moz: 'transitionend',
				ms: 'MSTransitionEnd',
				O: 'oTransitionEnd'
			}
		}
	}

	cacheObj = cssProp.cache;

	if ( cacheObj.hasOwnProperty( name ) ) {
		return cacheObj[name][index];
	}
	if ( name.toLowerCase() === 'transitionend' ) {
		return cacheObj.transitionEvent[cacheObj.vendor[0]];
	}

	element = cacheObj.element;
	prop = name.replace( /-./g, function( m ) {
		return m.charAt( 1 ).toUpperCase();
	} );

	if ( prop in element.style ) {
		cacheObj[name] = [prop, name];
		return cacheObj[name][index];
	}

	prop = cacheObj.vendor[0] + prop.replace( /./, function( str ) {
		return str.toUpperCase();
	} );

	if ( prop in element.style ) {
		cacheObj[name] = [prop, cacheObj.vendor[1] + name];
		return cacheObj[name][index];
	}

	cacheObj[name] = [undefined, undefined];
	return undefined;
};

サンプル

引数にプロパティ名を渡して呼び出すと、対応している場合は環境に応じたプロパティ名が、対応していない場合はundefinedが返ります。以下はIE9の場合の例。

alert( cssProp( 'transform' ) ); // 'msTransform';
alert( cssProp( 'transition' ) ); // undefined

キャメル記法でなく、ハイフン区切りな文字列で取得したい場合は、第二引数にfalseを渡します。

alert( cssProp( 'transform', false ) ); // '-ms-transform';

ちなみに「3D系のtransformに対応していない場合」とかは考慮してません…(perspectiveの実装を調べればOK?)。あと、transitionEndは実装の判定方法が分からなかったので、そこはすっ飛ばして常にベンダープレフィックスが付与された文字列が返ります。transitionに対応していればイコールtransitionEndも対応とみなして良いものなんでしょーか(‘A’ ?)

とりあえず自分で作ってみたかったというのが第一にあったので挑戦してみましたが、特に理由が無い限りはModernizrというHTML5やCSS3の実装に関する強力なライブラリがあるようなので、そちらを使わせてもらった方がいいですね。

うーん、もっと勉強しないとなー。



[Flash] Flashムービーの読み込みと再生

最近は久しぶりに実務でFlashを触っています。
で、今になって「タイムラインベースのFlashムービーは読み込みの完了を待たずにストリーミング的に再生される」という、かなり基本的と思われる仕様を初めて知りました。

そしてそれは当然スクリプトからも制御できて、レアケースではありますがドキュメントクラスで

package 
{
	import flash.display.MovieClip;
	import flash.events.ProgressEvent;
	
	public class Main extends MovieClip
	{
		public function Main()
		{
			loaderInfo.addEventListener(ProgressEvent.PROGRESS, progressHandler);
		}
		
		private function progressHandler(e:ProgressEvent):void 
		{
			// 80%以上読み込みが完了したら再生
			if (uint((e.bytesLoaded / e.bytesTotal) * 100 ) > 80) {
				loaderInfo.removeEventListener(ProgressEvent.PROGRESS, progressHandler);
				gotoAndPlay(2);
			}
		}
	}
	
}

みたいにして、何割完了したら再生というような処理も書くことができます。
これってもしかして常識でしょうか…。

冷静になって考えてみると「ああ、そうかー」とも思うのですが、そもそも「読み込みが完了していないと再生されない(できない)」というのがまず頭にあったので、この仕様を知った(というか教えてもらった)時は、目からウロコでございました。うーん、どこで間違ったんでしょう…。

ちなみに上記は外部SWFを読み込み・再生する場合も同様のようですが、ローカルでの確認や読み込むSWFがキャッシュに存在するなど、瞬間的に読み込みが完了する状況では、ProgressEvent.PROGRESSのハンドラでうまくMainTimelineオブジェクト(Loader.content)にアクセスできず、nullが返ってきてしまいます。

イベント自体は配信されていますし、適当になんやらすれば回避は可能ですが、原因がわかっていない(というか調べていない)ので、なんとも。何かまた変な勘違いしている可能性も否定できませんけど(‘A';)

思い込みと中途半端な理解は怖いなあ、というお話でした。