プロが教える店舗&オフィスのセキュリティ対策術

js, jQuery 初心者です。下記のコードの手直しを助けて下さい

このコードはページ内の複数設置されたリンクのいずれかをクリックすると
背景の画像がフェードしながら変わるというものです。
例えばリンク1を押すと背景画像1がフェードしながら呼び込まれ、
リンク2を押すと背景画像2が呼び込まれるといった感じです。

このソースコードを使うに当たって問題が2つあり、
初心者の自分では手直しできないため
こちらに質問させていただきました。

問題1,Firefox 4 では作動するのに、他のブラウザではうごかない。
テスト済みブラウザ→ Chrome v.11.0, IE8, Safari 5

問題2、次画像のフェードインが、前画像のアウトの後にならないと読み込みが始まらない。
これだとフェード時に画像が一時期消える(真っ白になってしまう)時間ができてしまうので
出来れば次の画像をフェードなしでストレートに読込み、その上で前の画像をフェードアウトさせたいです。

どなたか問題解決の手直し方法をわかる方がいらっしゃいましたら
ぜひ教えてください


[code]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="ja">
<head><title>sample</title>
<meta http-equiv="Content-Style-Type" content="text/css">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">google.load("jquery","1.5.0");</script>



<style type="text/css">

#wrapper {
width: 100%;
height:100%;
background-image:url(img/img1.jpg);
background-repeat:repeat;}

#container{
width:1000px;
height:1000px;}

</style>

<script type="text/javascript">

$(function(){
 $("#nav a").click(function(){
  var val = this.rel, layer = $("#wrapper");
  layer.fadeOut(500, function(){
   layer.css("backgroundImage", "url(img/"+val+".jpg)").fadeIn(500);
  });
 });
});

</script>

</head>

<body>
<div id="wrapper">
<div id="container">
<div id="nav">
<a href="#" id="btn1" rel="img1">background1</a>
<a href="#" id="btn2" rel="img2">background2</a>
<a href="#" id="btn3" rel="img3">background3</a>
</div>
</div>
</div>
</body>

</html>
[/code]

A 回答 (5件)

>大きな背景画像のスイッチなので


それだけタイムラグが発生するくらいの大きな画像だと枚数が増えれば増えるほどページの表示速度も遅くなるということだと思います。

>div を重ねたほうがいいのですね
divで重ねなくても、No1で書いたように、ページを表示させた時に、1ピクセルにして表示するとか、visibility:hiddenで載せておくとかすれば、予め他の背景画像を読み込ませておけるので、すぐに表示されるようになります。

まあ、乗りかかった船。せっかくだから載せておきます。
いろいろ問題あって時間かかりすぎた><

CSS部
#wrapper {
position:relative;
width: 100%;
height:100%;
}

#container{
z-index:1;
position:relative;
width:1000px;
height:1000px;
}

#img1{
position:absolute;
width:100%;
height:100%;
background-image:url(img1.jpg);
background-repeat:repeat;
}

JavaScript部
var thisbg = "img1";
$(function(){
$("#nav").find("a").each(function(){
if(this.rel == thisbg){return true;}
$('<div />', {
id: this.rel,
css: {
"position": 'absolute',
"top": "0",
"left": "0",
"visibility": "hidden",
"width": '100%',
"height": '100%',
"background-image": 'url('+this.rel+'.jpg)',
"background-repeat": 'repeat'
}
}).appendTo('#wrapper');
});
$("#nav a").click(function(){
var val = this.rel;
$("#"+thisbg).fadeOut(500, function(){
thisbg = val;
$("#"+val).css({"display":"block","visibility":"visible"});
});
});
});

HTML部
<div id="wrapper">
<div id="img1"></div>
<div id="container">
<div id="nav">
<a href="#" id="btn1" rel="img1">background1</a>
<a href="#" id="btn2" rel="img2">background2</a>
<a href="#" id="btn3" rel="img3">background3</a>
</div>
</div>

説明
冒頭で書いたように背景画像が多くなればなるほどページ全体の読み込み速度は遅くなります。
デフォルトの背景色以外は効率性も考え、JavaScript部分で読み込ませています。

デフォルトの背景DIVは、レスポンスの為に予め設定しておく必要があります。
指定は、CSS部の
#img1{}
とHTML部の
<div id="img1"></div>
の部分です。
<div id="img1"></div>
は必ずwrapper下に入れておいて下さい。

あとの必要なDIVは、JSが
<div id="nav"></div>
の中に入っているa要素を調べて書き出してくれるので、設定は
<div id="nav"></div>
の中にAタグを入れるだけです。
いくらでも増やせます。

z-indexで切り替えということでしたが、fadeOutにしたら不可視になるので、手間は同じだし、背景画像でもし透過画像(jpgなのでないでしょうが)を使われたりしたらおかしなことになると思うので、z-indexでの切り替えはしていません。

検証
IE7,IE8,FireFox,Safari,Opera,クローム
#IE6は背景が縮まったままになります。解消できなかった><

では!

この回答への補足

再度の御返答ありがとうございます

>まあ、乗りかかった船。せっかくだから載せておきます。
>いろいろ問題あって時間かかりすぎた><

貴重なお時間を使ってまでコードを作っていただいて本当に、本当にありがとうございます!
ずっとひとりで悩んでいたので助かってます
FF以外のブラウザでも動きましたし、IE6 は別 css/javascript にし
背景が変わらないようにしたいと思います

図々しいついでに、いただいたコードについて質問してもよろしいでしょうか・・・
もちろんお手数でなければで構いませんし
もし数日内に御返答がなければこちらの投稿を持ってベストアンサーとしたいと思っております^^


質問1

>visibility:hiddenで載せておくとかすれば、予め他の背景画像を読み込ませておけるので、
>すぐに表示されるようになります。

背景画像その1の "img1.jpg" はcss内で読み込まれていることは分かるのですが
javascript の上部 function 内にある css のプロパティ、
"visibility": "hidden",
これで他の背景画像(img2,img3)もページロード時に隠れて読み込まれているのでしょうか?
それともhtmlに別個で img2,img3 をどこかに設置し、css を visibility:hidden; にしなければ
ページロード時に img1 の様に読み込まれないのでしょうか


質問2

>$('<div />',
これはhtml内の <div id="nav"> を javascript で閉じているのでしょうか
それとも何か別の事をしているのでしょうか


質問3

>$('<div />',
試しに </ div> としたところ動きませんでした
なぜインラインでクローズ(</ div> ではなく <div />)なのでしょうか


先程も供述しましたが、お時間があればで構わないので
どうぞよろしくお願いします

補足日時:2011/06/07 00:16
    • good
    • 0

>質問1


質問の回答の前に余談を。
サンプルソースを書く前に
display: none
visibility: hidden
の挙動を検索しました。
ですが、詳しく書いているページが見つからなくて、不可視にした際に、画像を読み込んでくれるのか、読まないのかわかりませんでした。

そこで、ログ出力するPHPを作って、<div>に背景画像として作ったPHPを入れ、display: noneをした時にログ保存されるかどうかを実験しました。
結果、IE8、FireFoxはOKでした。
Operaを試した時に、ログ保存されませんでした。つまり背景画像にアクセスしていない。
ここでdisplay: noneの検証は終了

次に同じようにvisibility: hiddenを検証。
全てのブラウザでログ保存されたことから、visibility: hiddenの場合は不可視にしても中身を読み込んでいることが確認できました。
だから、今回は、display: noneではなく、visibility: hiddenを使っています。

質問1を解決する前に質問2をまず答えます。

>質問2
$("#nav").find("a").each(function(){
で<div id="nav"></div>内にあるAタグを抽出し、それらのAタグをfunction(){}に入れて(ループして)います。

if(this.rel == thisbg){return true;}
は、デフォルトのIDだったらすでに指定されているので処理をしないで次に回しています。

$('<div />', {
からの記載は、まず、'<div />'で空要素のDIVを生成しています。
と同時にIDやCSSを付与し、#wrapperの中に放り込む作業をしています。
つまり、手作業でHTMLに書き出したことをJavaScriptでやらせているわけです。

背景画像変えたくなったら<a>タグだけ追加とか変えるとかすればいいので便利でしょ^^

>質問3
ブログとかで<br />とかってしているの見たことないです?
<img (省略) />とか。
HTMLは詳しくないので、自信ないですが、タグは開始されたら閉じるものですよね。
それを同時にするのが />かと^^
つまり、<div></div>
と同じ役割というところですね。

開始されてないのに、</div>にしたらおかしいでしょ。

>再び質問1
質問2と質問3の項目でimg1と同じようにimg2,img3も生成されたことはわかりましたね?

$(function(){
省略
});
の処理が終わった時点で、#wrapper下には
<div id="img1"></div>
とともに
<div id="img2"></div>
<div id="img3"></div>
が自動で生成されているわけです。
だから、img1のようにimg2とかimg3を手作業で設定する必要はありません。

通常のタグをHTMLとして書き出した時に、visibility: hiddenとしても、要素内を取得してくれるわけですから、新たに要素を追加した場合でも設定されている背景画像は読み込まれる(と思います)
ここまでは検証してないですが^^;
まあ、背景画像切り替え時にタイムラグがあるとしたら読み込んでない可能性があるので、言って下さい。
もう一度検証してみますので。
うまく読み込んでいるとは思うんですけどね。
    • good
    • 0
この回答へのお礼

再度の御返答ありがとうございます

>サンプルソースを書く前に
>display: none
>visibility: hidden
>の挙動を検索しました。

私の拙い質問に PHP まで使用して検証していただいて本当にありがとうございました
いただいたコードの説明もとてもわかり易く、どんなことをしているのか理解できました;;

>つまり、<div></div>
>と同じ役割というところですね。

div も img と同じように単独タグとしてスペースとスラッシュで閉じられるのですね
知らなかった・・大変勉強になります

>まあ、背景画像切り替え時にタイムラグがあるとしたら読み込んでない可能性があるので、言って下さい。

試しに背景画像をありえないくらい重くして試してみたところ
ページロードに時間がかかり、その後の背景切り替え時のラグはまったくありませんでした
きちんと全ての画像を最初に読み込んでくれたようです(やたー!)
万が一のため、ページにプリローダーを設置してナローバンドユーザーにも対応させたいと思ってます

本当に、本当に、ありがとうございました m(_ _)m

お礼日時:2011/06/07 22:45

画像が大きいのでしょうか、読込みに時間がかかるのが原因かと想像されます。



バックグラウンドの背景を切り替える方式だと、切り替えてから読込みが始まるのでご質問のようなことが起こる可能性はあります。
これをできるだけ避けるためには、最初に必要な数だけそれぞれの背景のdivなどを用意しておいて、重ねて表示しておくなどとして、切り替えるときは背景を変えるのではなく、そのdivの重なり順を変更することで背景を切り替えたように見せればよいのではないでしょうか。

ページロード時に各背景の読込みが終了すれば、それ以後はスムーズに切り替えられるはずと思います。
    • good
    • 0
この回答へのお礼

御返答ありがとうございます

>これをできるだけ避けるためには、最初に必要な数だけそれぞれの背景のdivなどを用意しておいて、
>重ねて表示しておくなどとして、切り替えるときは背景を変えるのではなく、
>そのdivの重なり順を変更することで背景を切り替えたように見せればよいのではないでしょうか。


おっしゃるとおり非常に大きな背景画像のスイッチなので
div を重ねたほうがいいのですね
ただその場合恥ずかしいことにスクリプトの方が初心者なので自分ではコードを作れません
もしお手数でなければサンプルコードをいただけないでしょうか
お時間があればで構わないので、よろしくお願いいたします

お礼日時:2011/06/06 16:08

>あくまで任意の透過度になるまでは次の画像を読み込んでくれません・・


まあ、そういう設定ですしね。

>素人考えですが、function をふたつにわけて、ひとつは次画像を読み込み、
>同時にもうひとつはフェイドアウト、というような形にできないでしょうか
今の状態なら無理だと思いますよ。
ひとつしか指定できないもの(背景画像)を、2つにすることはできません。

やるとするなら、
#wrapper
の上の階層にもうひとつDIVを作り、
そこで新たな背景画像を挿入するくらいですかね。

流れとしては、
1.上の階層の新背景画像を挿入。
2.wrapperのフェードアウトを開始。
3.wrapperのフェードアウトが終了。
4.wrapperに新背景画像を挿入し、可視とする
5.上の階層の背景画像を削除

<script type="text/javascript"><!--

$(function(){
$("#nav a").click(function(){
var val = this.rel;
$("#tempwrapper").css("background-image","url(img/"+val+".jpg)");
$("#wrapper").fadeOut(500, function(){
$("#wrapper").css({"background-image":"url(img/"+val+".jpg)","display":"block"});
$("#tempwrapper").css("background-image","");
});
});
});
--></script>

<div id="tempwrapper">
<div id="wrapper">
 (省略)
</div>
</div>


>firefox 以外のブラウザではスクリプトを読んでくれません
完全に同じではないですが、私の環境ではFF以外でも動いています。
IE8、IE7、IE6、Opera、クローム、Safariで検証済み
    • good
    • 0
この回答へのお礼

御返答ありがとうございます

頂いたコードで試したところ完璧に動作しました
なにより他ブラウザでも動きました(前のはどうして動かなかったのか謎ですが・・)
ブラウザのコンパタビリティーテストも含め
本当にありがとうございました!

お礼日時:2011/06/06 15:53

>フェード時に画像が一時期消える(真っ白になってしまう)時間ができてしまう


画像の読み込みは環境によって違いますが、必ず読み込みに時間がかかるので、こういった症状は防げないように思います。
この読み込み対策として、アクションをさせるページで変更させる画像を予め読み込ませておくと良いかもしれません。

さて、本題ですが、上記の読み込み時の画像表示までのタイムラグによる白くなる状態はないという前提として、
今回の質問者さんが抱える問題としては、完全に不可視にしているから問題があるように思います。

設定した透過度にし、新たな画像に切り替え、透過度を元に戻せばうまくいくと思います。

つまり、
layer.fadeOut(500, function(){
layer.css("backgroundImage", "url(img/"+val+".jpg)").fadeIn(500);
});

layer.fadeTo(500,0.3,function(){
layer.css("backgroundImage", "url(img/"+val+".jpg)").fadeTo(500,1);
});
とすることで、目的の挙動になるのではないかと思います。
透過度を変えたい場合は、0.3で指定している引数を変更して下さい。
    • good
    • 0
この回答へのお礼

ご返答ありがとうございます

頂いたコードではやはりフェイドアウトとフェイドインが同時ではないため
あくまで任意の透過度になるまでは次の画像を読み込んでくれません・・
素人考えですが、function をふたつにわけて、ひとつは次画像を読み込み、
同時にもうひとつはフェイドアウト、というような形にできないでしょうか

あとなぜかfirefox 以外のブラウザではスクリプトを読んでくれません
<script>タグ内の内容が悪いのでしょうか?
理由を御存知でしたらぜひ教えてください

よろしくお願いします

お礼日時:2011/06/01 13:22

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!