SWE の JavaScript プログラミング

Standard Widget Extentions (SWE) という WordPress プラグインを作って公開しています。 先日は SWE のスクロール時固定機能 (Sticky Sidebar について「そこらへんに落ちているサンプルコードとは動きが違うんだよ」という話を書きました。 今回は JavaSciprt 的にいろいろ苦労したところを書いておきます。

なお、ここで紹介している関数は特に断りがなければ jQuery の API です。

幅やマージンの %指定

レスポンシブ Web デザインでは以下のように width や margin がパーセント表示で比率指定されていたりします。 テーマ製作者はピクセルの比率から値を計算しているのでこのように結構エグい小数になっていたりします。

.content-sidebar {
  margin-left: -29.04761904%;
  width: 29.04761904%;
}

ここで一つ問題となったのが、width が %指定のままで position = fixed にして位置を固定すると比率の基準となる要素が変わるため幅が変化してしまうことです。 これを避けるには一度取得した値を再度設定しピクセル値で固定することです。

var w = $('#sidebvar').width();
$('#sidebar').width(w);

では、ブラウザがリサイズされたときはどのようにすれば良いでしょう? リサイズ前の幅のままではレイアウトが意図通りになりません。しかし、新しい幅はどうやって計算すればよいのでしょうか? 比率を取得するために CSS ファイルを自力で読まねばならないのでしょうか…。

わかってしまえば簡単なのですが、一旦 width をクリアすることで解決します。

$('#sidebar').css('width', '');

jQuery API リファレンスをよく読むと書いてあるのですが、空文字列に指定するとこれまでの API 経由で設定したスタイル指定をクリアし CSS ファイルの記述通りに振る舞うようになります。まとめて書くと以下の様に一旦クリアし再度取得したピクセル値で設定することになります。

$('#sidebar').css('width', '');
w = $('#sidebvar').width();
$('#sidebar').width(w);

一瞬なんだかわからないコードですよね。

サイズ関連

.width() で取得した値と .css(‘width’) で取得した値は異なることがあります。 一方が 250 なのに他方は ‘310px’ などと返ってきたりします。 型の差は置くとして、異なる数値になっているので困ります。 これは box-sizing プロパティのせいだったりするのですが、この値を見て動作を変えるようなコードを書くのはいろいろ面倒です。

それで結局どうしたかというと以下のようにしました。

  • 位置計算等に使用する幅の取得は .outerWidth(true) を使って、いつでも border や margin 込みの値を用いる。 jQuery の .width(), .innerWidth(), .outerWidth() は box-sizing の値に依って動作が変わることはない。
  • 先述の width の操作についてのみ、取得・設定とも統一して .css() で行う。

このように jQuery の関連関数は box-sizing プロパティに依らず使えるので便利です。

座標関連

座標取得には document を基準として位置を取得できる .offset() が便利でした。 ただし、以下のように .css(‘top’) を使って操作するときとで対象としている座標の位置が異なるので注意が必要です。

jquery-offset

ちなみに position = absolute のときの基準要素を見つけるには .offsetParent() が便利です。jQuery にはいろいろな関数が揃っていますね。

position と z-index

position = static だと z-index が指定されているテーマで不具合を起こすため、position = static を使うのでなく position = relative で (top, left) = (0, 0) としています。

小数点の扱い

サイズ関連でもう一つ困ったのは小数の扱いがブラウザによって異なることです。 整数 (ピクセル値) に直す時に四捨五入なのか切り捨てかみたいな話です。 深入りしたくなかったこともあり細かい挙動は忘れてしまったのですが、気になる方は検索してみるとこの話題を扱っているサイトが見つかると思います。 SWE では先の .css(‘width’, ”) を使うテクニックにより、これらの問題を避けています。

というわけで、Standard Widget Extensions のサイドバースクロール時固定機能はその辺のサンプルコードと違うのです! 興味がわいた方は使ってみてください。