Hatena::ブログ(Diary)

Cyokodog :: Diary

October 01, 2009

jQuery.exFixed.js を機能拡張しました

以前、exFixed という jQuery プラグインを作成しました。IE6 で position:fixed を実現するプラグインで、特徴として

  • IE6 でもガタつかない position:fixed が可能
  • クロスブラウザで fixed 要素に対し、位置移動、リサイズ等の動的な変更が可能(素のanimate メソッド等も併用可)

といった事が挙げられます。

今回、このプラグインをご利用下さった方々からのフィードバックを元に、機能拡張と不具合修正を行いました。

機能拡張

これまでは IE6 でもモダンブラウザの position:fixed と同レベルの扱いが出来ることを目指してましたが、今回は以下のような position:fixed 自体の機能拡張を行いました。

baseNode パラメータ
fixed 要素の配置上の基準位置となる要素を指定することができます
baseX , baseY パラメータ
垂直または水平の単一方向にのみ baseNode パラメータ による基準位置指定を有効にすることができます
fixedX , fixedY パラメータ
垂直または水平の単一方向にのみ position:fixed を適用することができます
resize メソッド
動的な fixed 要素のリサイズ / 位置移動処理を簡単に記述することができます
不具合修正
  • IE6 で body 要素に background-image を設定した状態で exFixed を使用すると、background-image の設定がクリアされてしまう不具合を修正
  • IE8 の標準モードで exFixed を使用すると実行時エラーが発生する不具合を修正
  • fixed 要素の一部あるいは全体がブラウザの表示領域から隠れた状態で、スクロールバーを動かすと無限スクロール状態になる不具合を修正
  • IE6 以外のブラウザで、スクロールされた状態で更新ボタンを押すと、fixed 要素が非表示になってしまう不具合を修正

新たに追加された機能

baseNode パラメータ

通常 position:fixed された要素の配置位置は、ブラウザの表示領域の四隅のいずれかが基準位置になりますが、baseNode パラメータに要素を指定すると、指定した要素の配置位置が fixed 要素の基準位置となります。

f:id:cyokodog:20091001012802p:image

上図のようにコンテナ要素の右上に fixed 要素を配置したい場合は、baseNode パラメータにコンテナ要素を指定し、top , right の値を 0 にします。

$('#target').exFixed({
    baseNode : '#container',
    top : 0,
    right : 0
});

Demo

ちなみにコンテナ要素に position:relative 、fixed 要素に position:absolute を指定すれば、コンテナ要素からの相対的な配置は可能ですが、スクロール時は(当然ですが)固定表示されません。

ブラウザリサイズ時の配置の追従

サンプルのようにコンテナ要素の幅が固定長で両サイドが margin:auto の場合、ブラウザリサイズ時(コンテナ要素は常にセンタリングされた状態を保とうとするので)コンテナ要素の配置位置が移動します。この時、baseNode パラメータでコンテナ要素を指定してた場合は、fixed 要素もコンテナ要素の位置移動に追従し再配置されます。

baseX , baseY パラメータ

垂直または水平の単一方向にのみ baseNode パラメータ による基準位置設定を有効にすることができます。

f:id:cyokodog:20091001013054p:image

上図のように、右辺についてはコンテナ要素を、底辺についてはブラウザの表示領域を基準に配置したい場合は、baseNode にコンテナ要素を指定し baseY パラメータを false とします。

$('#target').exFixed({
    baseNode : '#container',
    bottom : 0,
    right : 0,
    baseY : false
});

Demo

fixedX , fixedY パラメータ

垂直または水平の単一方向にのみ position:fixed を適用することができます。

f:id:cyokodog:20091001013417p:image

上図のように、垂直 , 水平 方向にスクロール可能なページがあった時..

f:id:cyokodog:20091001013443p:image

垂直方向にスクロールした場合、fixed 要素は他の要素に干渉せず固定位置に表示されたままとなります。

f:id:cyokodog:20091001013519p:image

水平方向にスクロールした場合も同様に固定位置に表示されますが、要素の配置関係上、隣接する要素に重なって表示されてしまいます。

Demo

f:id:cyokodog:20091001013554p:image

fixedX を false として水平方向への position:fixed を非適用状態にする事で、隣接要素への重なりを抑止できます。

$('#target').exFixed({
    top : 10,
    left : 10,
    fixedX : false
});

Demo

動作原理について

IE6 の場合は position:fixed を適用したくない方向の setExpression 記述を省略すればいいだけですが(関連記事)、その他のモダンブラウザについてはスクロール処理に合わせ fixed 要素の位置を調整する必要があります。単純な方法として、スクロールイベント内で position:fixed してる位置からスクロール量分を減算するという手がありますが、配置条件によっては対象要素がガタついて表示されてしまいます。

前回のエントリで、

只今、以前作成した exFixed.js という jQuery プラグインの機能拡張を行っており、その中で、

  • スクロールイベントの開始、終了時にのみ処理を行う
  • その際、スクロールイベントのスクロール方向に応じて処理を変える

という実装が必要になりました。

スクロールイベントの開始 / 終了 / 方向を判定する jQuery プラグインを書いてみた - Cyokodog::Diary

と言っていたのは、このガタつきを解消するのに必要だったためです。

具体的には、position:fixed させたくない方向にスクロールイベントが発生したら、以下処理を行う事でガタつきを抑止してます。

  • スクロールイベントの開始時に、position:fixed を absolute に切り替える
  • スクロールイベントの終了時に、position:absolute を fixed に切り替える
  • 上記の切替の際、その時点でのスクロール量、各種パラメータで指定された配置条件や単位(%など)を考慮した配置上の設定、復元を行う
resize メソッド

resize メソッドを使用すると動的な fixed 要素のサイズ変更 / 位置移動処理を簡単に記述することができます。

resize メソッドを使用せずに動的な fixed 要素のサイズ変更や位置移動をする場合、以下のように fixedOpen メソッドで変更可能状態にし、fixedClose メソッドで最終的なサイズや位置を確定する必要がありました。

fixedObj.fixedOpen(function(){
    fixedObj.fixedClose({
        top : 200,
        left : 200,
        width : 500,
        height : 300
    });
});

animate メソッド等を使用しない単純なサイズ変更や位置移動なら resize メソッドによる簡略化した記述が可能です。

fixedObj.resize({
    top : 200,
    left : 200,
    width : 500,
    height : 300
});

Demo

仕様変更について

exFixed オブジェクトの取得方法の変更

exFixed オブジェクトとは、前述の resize メソッドのサンプルでいうと "fixedObj" のことを指します。fixed 要素に対しリサイズ等の動的な変更を与える場合、exFixed オブジェクトの持つ各種メソッド(fixedOpen , fixedClose , fixedSize , resize )を使用する必要があります。

従来は以下のように exFixed メソッドの返却値を exFixed オブジェクトとする仕様になってました。

var fixedObj = $('#target').exFixed({
    bottom : 0,
    right : 0
});
fixedObj.fixedOpen( function(){....

メソッドチェーンという jQuery の基本思想の観点からすると、このようにプラグインメソッドが独自オブジェクトを返すことで、jQuery オブジェクトの連鎖を中断してしまうのは、あまりよろしくない設計かと思い直しまして、jQuery オブジェクトをそのまま返す仕様に変更しました。

プラグイン作成におけるこの辺の話は以下記事が詳しいです。

では exFixed オブジェクトはどのように取得すればいいかというと、メソッドチェーンで返された jQuery オブジェクトに getExFixed というメソッドがバインドされるので、これを実行し取得します。

Ver 1.3.0 より exAPI ベースの実装となりましたので、以下のように API オブジェクトを取得するようになります。

var api = $('div.fixed').exFixed({
    api : true,
    dynamicFixed : true,
    right : 100,
    bottom : 100
});

あとは従来通りの手法で fixed 要素を動的に扱うことができます。詳しくはこちらをご参照ください。

ちなみに今回新規に追加されたパラメータと併用して扱うことも可能です。(当然ですが)

Demo

exFixed オブジェクトの使用条件

exFixed メソッドパラメータを省略して実行することができます。この場合は CSS での定義された位置やサイズが適用されます。

<style>
    #target{
        top : 10%;
        left : 20%;
        width : 50%;
        height :50%;
    }
</style>
<script>
    jQuery(function($){
        $('#target').exFixed(); // style で定義した値が反映される
    });
</script>

但し、exFixed オブジェクトを使用して fixed 要素に対し動的な操作を行う場合は、必ず exFixed メソッドパラメータを指定する必要があります。パラメータには top(又は bottom)と left(又は right)の指定が必須となり、width や height も単位が % の場合は必須になります。

var fixedObj = $('#target').exFixed({
    top : '10%',
    left : '20%',
    width : '50%',
    height : '50%'
}).getExFixed();

var fixedObj.fixedOpen(function(){...

ちなみに、これらのパラメータを設定せず fixedOpen 等のメソッドを実行しても何も処理しない仕様になっています。

ご要望の対応

bosukete さんより以下ご要望を頂いておりました。

親要素の位置を基準とした、position:fixed 要素の配置を行いたい

希望されてる詳細な動作について確認したところ

  • ブラウザのリサイズにより親要素と fixed 要素の相対位置にずれが生じた場合、fixed 要素の位置を調整しずれを無くす
  • (水平スクロール時は指定要素に fixed 要素を追従させたいので)、垂直スクロール時にのみ position:fixed を適用する

という内容でした。今回の機能拡張により、以下記述で実現できるようになりました。

$('#target').exFixed({
    baseNode : '#container',
    top : 0,
    left : 0,
    fixedX : false
});

Demo

ダウンロード

こちらからどうぞ

bosuketebosukete 2009/11/05 20:12 おお!
せっかく要望を叶えていただけたのにチェックが遅くなりました!
早速導入してみたいとおもいます!
本当にありがとうございます!

cyokodogcyokodog 2009/11/05 23:35 また何かありましたら、よろしくお願いします。

bosuketebosukete 2009/11/21 19:09 お疲れ様です、遅くなりましたが使用させていただきました。
firefox3やIE7以降での表示はキチンとされます。
IE6では、読み込み時にbody要素に指定した背景(cssにて固定の背景を使用した場合)が表示されません。
スクロールをするとbodyの背景が表示されますが、固定されず、動いてしまいます。

あと、Fixedにて固定したdiv要素ですが、IE6でウインドウズサイズを小さくした場合、画面からはみでた部分が消えてしまいます。
(画像、css背景画像、Flashともに。リンクも消えます)

お手すきのときにでも、ご確認願えますでしょうか?
何卒、よろしくお願いいたします。

cyokodogcyokodog 2009/11/22 01:15 う〜ん、ちょっと再現できないですねぇ...ちなみに以下のサンプルでも同様の現象は起こりますでしょうか?こちらの環境でIE6/8,Firefox3.5で確認したところ問題なく動作してます。

http://cyokodog.appspot.com/lab/QA/exfixed/exfixedQA01a.html

はしよった形でもいいので問題の発生するソースを見せていただくことってできませんでしょうか
あ、あとページの背景画像に対しbackground-attachment:fixed;する場合はbody
要素ではなくhtml要素に対し行うようにしてください。VerUpの過程↓で背景画像の使用に条件ができてしまいました(ただ画像が表示されないっていうのは別の理由でしょうけど..)

http://d.hatena.ne.jp/cyokodog/20090902/jQueryExFixed03

cyokodogcyokodog 2009/11/22 01:21 あ!すいません。
IE6 でfixed要素に画像が適用されないというのが再現しました。
原因を調べますのでしばらくお待ちください。

cyokodogcyokodog 2009/11/22 01:25 たびたびすいません。勘違いでした。先程の返信無視してください。。やはり問題なく動いてしまいます。

bosuketebosukete 2009/11/25 18:16 対処ありがとうございます!

・背景画像をbodyからhtmlに変更すると背景は表示されるようになりました。

拙作で申し訳ありませんが、URLにサイトのリンクを貼らせて頂きます。
サイトでは、画面左側にあるメニューを固定しております。
exfixedの指定は、windowsize.jsというファイルを作り、ウインドウサイズが768px以上の環境でのみ適用されるようにしております。
・固定した要素の中でcssで背景を設定すると、やはりウインドウサイズを縮小したのち元に戻すことで、縮小時にはみ出た部分(リンク先だと、メニューや卵の絵のFlash)が再描画されません。

ごちゃごちゃしたページで申し訳ありません、どうぞよろしくお願いいたします。

cyokodogcyokodog 2009/11/26 00:14 URLありがとうございます(かっこいいデザインですね!私も趣味でギターさわってます)
おかげで原因が特定できました。
fixed 対象要素にサイズが指定されてないと発生するようです。

ソースは修正するつもりですが、お急ぎでしたら以下のよう height の指定を追加することで解決するかと思われます。

$('#left').exFixed({
baseNode : '#wrapper',
top : 0,
left : 0',
height : $('#left') // 追加
});'

bosuketebosukete 2009/11/27 19:42 ありがとうございます!
私はドラマーなのですが、PCに向かうのに疲れた時には最高のリフレッシュです(笑)
height指定、そのまま

height : $('#left') // 追加

を追加したのですが、高さを指定するとセンター寄せになってしまい、高さを表示しないと何も表示されません。
元のサイト側のCSSに#leftの高さを指定したところ、きちんと動作いたしました!

cyokodogcyokodog 2009/11/27 23:44 あ!
height : $(’#left’).height()
の誤りでした。ごめんなさい。

修正版の Ver.1.2.1 リリースしましたので、こちらでしたらサイズ指定は無くてもOKです
よろしくお願いします。

bosuketebosukete 2010/01/08 04:21 お世話になります。
exfixed.js、重宝しております。
さて、しばらく見ない間にまた新しいバージョンが出ているようなので試してみましたが、どうにもうまくいきません。
あるサイトの右下に「ページトップへ戻るナビゲーション」をつけようと思っているのですが、使い方にある通り

<script>
$(function(){
$('#navi_pagetop').exFixed(); // for IE6
});
</script>

としましたが動作しません。
cssは

html {
background:#000 url(/bg.jpg) no-repeat center -430px;
}
body {
text-align:center;
color:#333;
font-family:Verdana, "MS Pゴシック", sans-serif;
}
/*IE6のposition:fixed対応*/
#navi_pagetop {
height: 130px;
width: 42px;
display: block;
text-indent: -9999px;
right: 0px;
bottom: 50px;
background: url(pagetop.png) no-repeat;
position: fixed;
}
#navi_pagetop a:link,#navi_pagetop a:visited,#navi_pagetop a:hover,#navi_pagetop a:active {
display: block;
height: 130px;
width: 42px;
}
/*IE6での背景透過「DD_belatedPNG.js」がposition:fixedに対応していないためスターハックで対処*/
* html #navi_pagetop{
position: static;
}

です。

そこでデモページにある

<script type="text/javascript">
jQuery(function($){
$('#navi_pagetop').exFixed({
baseNode : '',
bottom : 50,
right : 0
});
});
</script>

形で記述したところ、動作いたしました。
が、bodyに背景画像をいれている状態ではガタつき、htmlに背景画像指定を移したらきれいに動作するのですが、背景画像が固定されてしまいます。
原因などお分かりのようでしたら、ご教示願えますでしょうか?

よろしくお願いいたします。

cyokodogcyokodog 2010/01/09 00:53 bosukete さん

いつもコメントありがとうございます。
DD_belatedPNG.jsを併用したサンプル作ってみました。

http://cyokodog.appspot.com/lab/QA/exfixed/20100108/exfixed.qa01a.html

まず背景画像の件ですが 固定させたい場合は html 要素、固定させたくない場合は body 要素に割り当てます。詳しくは下記 url
を参照ください(情報がまとまってなくてすいません。その内一箇所にまとめたいと思ってるのですが..)

http://d.hatena.ne.jp/cyokodog/20090902/jQueryExFixed03

fixed 要素の画像がちらつく件は知ってたのですが記事に書いてませんでした(すいません)
これはfixed 要素の内包要素に画像を割り当てることで回避できます。サンプルだと #navi_pagetop 内の a 要素になります。
この条件でパラメータなしで exFixed()
メソッドを実行するとうまくいくと思います。(DD_belatedPNG.js用のスターハックはなしでも平気でした)

コメントでいただいたソースに近いかたちでサンプルを作りましたので、詳しくはサンプルのソースを確認してみてください。
不明な点等ありましたらコメントの程よろしくお願いします

bosuketebosukete 2010/01/10 12:37 早速の対応ありがとうございます!
スターハックもいらないのですね・・・。
ためさせていただきます!

cressoncresson 2010/12/24 23:06 初めまして、exfixed.jsを使わせて頂きました。
やりたかった背景固定がIE6でもできて、
とても感動致しました…ありがとうございます!!

私の使い方がよくないのかもしれないのですが、
exFixedにて固定したdiv要素が見えなくなるまでIE6でウインドウズサイズを小さくし、
元に戻したとき、exFixedにて固定したdiv要素が消えています。
(画像、css背景画像ともに消えます。リンクも消えるようです。)
使わせて頂いているバージョンは1.3.0です。

お手隙の際にでもご確認お願いできますでしょうか?
作成中のもので申し訳ないのですが、URLにサイトのリンクを貼らせて頂きました。
画面右側にあるメニューを固定しております。
何卒よろしくお願い致します。

cyokodogcyokodog 2010/12/28 15:12 >cressonさん
コメントありがとうございます。
yahoo japan の IE6の件で、そろそろ需要なくなるかなと思ってましたが、ご使用いただきありがとうございます。
(個人的にも会社のブラウザがIE8になったのであまり使わなくなってましたので)
ご指摘いただいた件、バグでした。
修正版(jquery.exfixed-1.3.1.js or
jquery.exfixed-latest-min.js)をgithubにアップしときましたので、こちらで試してみてください。

またなにかありましたら、よろしくお願いします。

cressoncresson 2010/12/28 19:17 先日書き込ませて頂いたcressonです。
早速のご対応ありがとうございました!

修正版を使わせて頂きIE6でアクセスしたところ、
オブジェクトがサポートされていないという旨の
javascriptエラーが出て、固定配置されない、という動きをしました。
URLにサイトのリンクを貼らせて頂きましたので、
ご確認お願いできますでしょうか?
(アップロード先が前回と異なるサーバになってしまい申し訳御座いません。
ファイル自体は修正版を読みこむようにしたこと以外変更は御座いません。)

何卒よろしくお願い致します。

cyokodogcyokodog 2010/12/28 19:49 >cressonさん
すいません。ファイル名を微妙に変えてしまってます。
jquery.exfixed.1.3.1.js
ではなく
jquery.exfixed-1.3.1.js
としてください。
(. が - に変わってます)

cressoncresson 2010/12/28 20:10 こんばんわ、cressonです。
ファイル名が変わっていたのですね!
こちらの確認漏れでした、大変申し訳御座いませんでした。

div要素が消えるバグが修正されていることを
サーバ上、ローカルにて確認させて頂きました。

ご対応頂き、誠にありがとうございました。
またお世話になることがあるかもしれませんが
何卒よろしくお願い致します。

こんぼいこんぼい 2011/09/21 11:36 すばらしいライブラリをありがとうございます!!!
使用していて、こんな機能があれば有難い、と思った点がありましたので
投稿させて頂きました。

「baseY」を使用していて、
ページの下までスクロールして行ったときに
ページトップがフッターに重なりたくない、といのがありまして。
「ページの一番下から○○pxの領域にはかぶらないようにする」
というような設定をすることは可能でしょうか?

cyokodogcyokodog 2011/09/21 21:05 こんぼいさん
プラグインのAPIを使ってロジックをゴリゴリ書けばできるかもしれませんが、現状、パラメータ設定等では実現できません。(実装してみようと思ってたのですが、会社のIEがIE8になってモチベーションがなくなってしまいました><)
先日作ったこちらのプラグインでは要件は満たせませんでしょうか?

http://d.hatena.ne.jp/cyokodog/20110904/exflexfixed

こんぼいこんぼい 2011/09/22 11:15 お返事ありがとうございます!
試してみたのですが(exFixed→exFlexFixedの順で記述)
ページトップが確かにフッターにはかぶらなくなったのですが
スクロールするとウインドウの上にはりつく状態になってしまいました。
(当然といえば当然かもしれませんが;;;)
ちょっといろいろ試してみたいとおもいます(^o^)

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

リンク元