IT系おじさんのチラシの裏
2018年10月~
当サイトの記事にはアフィリエイト広告のリンクが含まれる場合があります

JavaScriptとCSSで画像をふわっと切り替えるスライドショーを作る

以前、「JavaScriptでスライドショーみたいな画像切替え(jQueryなし)」と題してスライドショーは作ったのですが、CSSは使っておらず、フェードイン/アウトのようなトランジション処理も入っていなかったため、見栄えがいまいちかなぁーと思っておりました。

なので、今回はCSSも使って、ふわっと写真や画像を自動的に切替えるサンプルです。もちろん、今回もjQueryは不要。

実行例

あれこれ説明するより、実行結果を見たほうがわかりやすいと思うので、まずは実行例。

スライドショー スライドショー スライドショー スライドショー スライドショー スライドショー スライドショー スライドショー スライドショー スライドショー スライドショー スライドショー スライドショー

表示時間:

13枚の写真が次々とふわっと現れてふわっと消えていきます。

HTML部分の解説

<div class="slide">
	<img src="[画像01]" />
	<img src="[画像02]" />
	<img src="[画像03]" />
	<img src="[画像04]" />
	<img src="[画像05]" />
	<img src="[画像06]" />
	<img src="[画像07]" />
	<img src="[画像08]" />
	<img src="[画像09]" />
	<img src="[画像10]" />
	<img src="[画像11]" />
	<img src="[画像12]" />
	<img src="[画像13]" />
</div>
<p>
	表示時間:<input type="range" id="slide_speed" value="2000" min="100" max="10000">
</p>

特に難しいところもないと思いますが、クラス名に"slide"を指定したdivタグで表示したい画像を囲っているだけです。

また、一応スライドショーの切り替え速度をその場で変更できるように、input要素のtype="range"でレンジバー(スライドバー)を表示しています。

実際には速度ではなく、setTimeout関数に渡す値なので、値が大きければ大きいほどスライドの切り替え時間が長く(遅く)なります。

逆にスライドバーを右に寄せるほど速度を上げたい場合はsetTimeout関数に渡す値を「最大値-現在値」にするか、CSSで表示を反転させるのも良いでしょう。これについては後述します。

CSS部分の解説

<style>
.slide {
	position:relative;
	height:400px;
}
.slide img {
	position:absolute;
	opacity:0;
	transition:all 1s ease-in-out;
	height:100%;
	object-fit:contain;
}
</style>

シンプルかつ短いですが、ここがキモの部分です。

まず、全体を囲っているslideクラスですが、position:relative;として基準点とすることが必須。

前回のスライドショーの例ではdisplay:none;とdisplay:block;を切り替えることで、画像の表示/非表示をコントロールしていましたが、それではtransitionのアニメーションが発生しません。そのため今回はopacity(不透明度)を使うことでスライドの切り替えを実現しています。

しかし、要素としては存在したまま透明度だけが切り替わるため、透明な画像を13枚並べたとしたら、13枚分の空白が出来てしまうのでそれは困る。透明人間は見えなくても物理的にはぶつかってしまうのと同じです。…………例がおかしいかw

透明人間は置いておくとしてw ともかく、div.slideをrelativeで基準点とし、その中のimgはabsoluteで基準点に配置。つまり、13枚の画像が同じ場所に重なった状態にしなくてはなりません。絵描きさんにはレイヤーと言えば一発で伝わりますよね。たぶん。

そして、div.slideがrelative指定になっているため、高さの指定も必須。height:400px;を指定し、スライドショーの高さを決めています。

もちろん、画像側ではobject-fit:contain;を使うことで、div.slide内に収まるように、いいかんじにリサイズされます。ちなみに最近のモダンブラウザなら問題ありませんが、IE11ではobject-fitが効かないため、どうしてもIE11にも対応したい場合は下記の記事も参照してみてください。

それから前述したスライドの表示速度を変えるレンジバーについてですが、現状では右に寄せるほど表示が遅くなりますが、逆の動作にしたい場合はCSSで反転させる方法もあります。

具体的にはこんな感じ。

#slide_speed {
	transform:rotateY(180deg);
}

transform:rotateYで180度回転させるんです。すごく強引ですが、以前は見た目もそのままなので意外と使いみちがありました。

実際、JavaScriptでコマ撮りムービー風の表示をする記事で使っています。

ただ、最近のChromeのアップデートでレンジバーの見た目が変わって色が付くようになったため、多少違和感が出るようになってしまいました。残念。

JavaScript部分の解説

<script>
window.addEventListener('load', function () {
	viewSlide('.slide img');
});
function viewSlide(className, slideNo = -1)
{
	let imgArray = document.querySelectorAll(className);
	if (slideNo >= 0) {
		//初回以外は現在のスライドを消す
		imgArray[slideNo].style.opacity = 0;
	}
	slideNo++;
	if (slideNo >= imgArray.length) {
		slideNo = 0; //次のスライドがなければ最初のスライドへ戻る
	}
	imgArray[slideNo].style.opacity = 1;
	let msec = document.getElementById('slide_speed').value;
	setTimeout(function(){viewSlide(className, slideNo);}, msec);
}
</script>

JavaScriptの部分は前回のスライドショーの例から変更した点は以下のとおり。

  1. 画像切替をstyle.displayからstyle.opacityへ変更。
  2. window.onload後にスライドショーを開始するように変更。
  3. 初回実行時にグローバル変数へ画像要素を格納していたのを廃止し、毎回querySelectorAllで取得するように変更。
  4. その場でスライドショーの表示時間を変更できるようslide_speed要素を参照するように変更。

1が重要な部分ですが、CSSの項目で解説したとおり、display:block/noneの切り替えではアニメーションが発生しないため、これをopacity:0/1の切り替えに変更しています。

2についてもそれなりに大事で、1枚目の画像をパッと表示しても良いのなら、いきなりviewSlide関数を呼び出しても良いのですが、1枚目からふわっとアニメーションさせたいのなら必須。ちゃんとページのロードが終わった後にopacityの変更をしないとアニメーションが発生しないのです。(1枚目だけね)

3はオマケ。グローバル変数って便利ですけど、あちこちで使っていると変数名かぶったりして予期せぬバグの温床になるため、なるべく使いたくないなぁーと思って。今回は毎回querySelectorAllを実行することでグローバル変数を不要としました。

4は更にどうでもいいオマケ。スライドショーの表示スピードをリアルタイムで変えたいなーと思って付けただけです。

ちなみにスライドバーの右と左の動作を逆転(右に行くほど速く)したい場合は下記のとおり、「最大値-現在値」にすれば良いでしょう。

	let msec = document.getElementById('slide_speed').max - document.getElementById('slide_speed').value;

まとめ

JavaScriptでスライドショーみたいな画像切替え(jQueryなし)」という記事は投稿済でしたが、もう少しイケてるスライドショーにしたいなぁ~と思って、CSSのtransitionのease-in-outを使ってみました。

ちょっとサンプル写真のチョイスがよくないかな? 似たような写真の連続だから、あまりふわっと現れてふわっと消えているように感じないかも知れません。

今回伝えたかったのはJavaScriptとCSSを組み合わせたときに、「いつ」アニメーションが動作するのか、という点です。

setTimeoutやonclickでも良いですけど、JavaScriptでCSSのプロパティを変更するケースというのはよくあると思います。特にdisplayプロパティをいじることで要素の表示/非表示の切り替えをする方法は最も使われるパターンと言っても過言ではないでしょう。

しかし、それではCSSのtransitionが発生しません。ではいつ発生するのかというとopacityの変更時。いえ、厳密には他にも発生するタイミングはあるのですが、今回の例では一番わかりやすいかな、と。

そんなわけで、displayプロパティをいじらずに、opacityで画像の表示/非表示を切り替え、スライドショーを作る例を記事にしてみました。

単純な仕組みではありますが、どこかの誰かのお役に立てれば幸いです。

関連記事

JavaScriptのcanvasで縦書きを行う際の備忘録

canvas上に縦書きの文章を出力して画像化しようと考えてちょっとハマったので忘れないうちにメモしておきます。 結論から先に書くと、基本的にcanvasにはwriting-modeの設定が効くの

JavaScriptのWebAudioAPIで楽曲の口パクをしてみる

以前、ソフトウェアの解説動画を作った際、おっさんの声だけ流れてるのもアレだし、最近流行りのアバターにしゃべらせるやつやってみよう、と思ったことがあります。 vtuberとかおじさんよくわからない

コメント

  • 初めまして。
    新人WEBデザイナーのホリイと申します。

    https://blog.ver001.com/javascript-slideshow-transition/
    こちらの記事を参考にさせて頂いたのですが、
    表示時間のmaxを100000と、ゆっくりに設定した所、
    アクセスしてから初めのスライダーが表示されるまで時間がかかる様になってしまいました。
    初めのスライダー画像をすぐに見せたい場合のカスタマイズがお分かりでしたら、教えていただけると幸いです。

    いきなりの質問で恐縮ですが、何卒よろしくお願い致します。
    [返信]
  • ご質問の意図を測りかねているのですが、slide_speedのmaxを100000にしても最初に表示される写真の速度は変わりません。試しにこの記事の実行例でmaxを100000にしてみましたので動作をご確認ください。
    [返信]
  • 早速のご回答ありがとうございます。

    すみません、maxではなくvalueが初期値だったんですね。
    valueとmaxを3000に設定したところ、良いスピードにできたのですが、やはりアクセス時にスライダー部分だけ読み込みが遅い状態です。
    それぞれの画像自体もリサイズして容量をかなり抑えてはいるのですが、何か可能性のある
    原因はありますでしょうか?

    分かりずらい説明で申しわけございませんが、何卒よろしくお願い致します。
    [返信]
    • 下記のとおり、ページのロード完了後にスライダーを開始しているため、ページ自体が重いのではないでしょうか。

      window.addEventListener('load', function () {
      viewSlide('.slide img');
      });

      ページのロードを待たずにスライダーを開始する場合はaddEventListnerを排除し、任意の位置(なるべくページ下部が良いとは思います)で viewSlide('.slide img'); を実行すれば改善されるかと思います。
      [返信]

新しいコメントを投稿する

[新規投稿]
 
TOP