ズームイン、ズームアウトしながら画像が切り替わるスライドショーと、流れるスライドショーについて、jQueryなどのライブラリはおろかjavaScriptなしで作る方法についてご紹介します。一部は本サイトのトップページでも使っているものとなります。

一気に説明せず、ひとつひとつの要素に分けてご説明していきます。

スライドショーをCSSのみで作る/ボタン付きの場合の解説も

画像が切り替わるスライドショー

(1)基本形

次のようなスライドショーをCSSだけで作成できます。

ソースコード

HTML
<style><div class="img-frame">
   <div class="img-01"></div>
   <div class="img-02"></div>
   <div class="img-03"></div>
</div>
CSS
.img-frame{
position: relative;
width: 70%;
height: 300px;
overflow: hidden;
margin: 0 auto;
}
.img-01, .img-02, .img-03{
position: absolute;
top:0;
left:0;
width: 100%;
height: 100%;
background-size: cover;
background-repeat: no-repeat;
}

.img-01{
background-image: url('画像の場所');
animation: slide-animation-01 24s infinite;
}
.img-02{
background-image: url('画像の場所');
animation: slide-animation-02 24s infinite;
}
.img-03{
background-image: url('画像の場所');
animation: slide-animation-03 24s infinite;
}

@keyframes slide-animation-01 {
0% {opacity: 1; transform: scale(1.0);}
30% {opacity: 1;}
40% {opacity: 0; transform: scale(1.15);}
90% {opacity: 0}
100% {opacity: 1; transform: scale(1.0);}
}
@keyframes slide-animation-02 {
0% {opacity: 0;}
30% {opacity: 0; transform: scale(1.1);}
40% {opacity: 1;}
60% {opacity: 1;}
70% {opacity: 0; transform: scale(1.0);}
100% {opacity: 0;}
}
@keyframes slide-animation-03 {
0% {opacity: 0;}
60% {opacity: 0;  transform: scale(1.0);}
70% {opacity: 1;}
90% {opacity: 1;}
100% {opacity: 0; transform: scale(1.1);}
}

解説

以下、CSSセレクタで対象要素を説明します。

  • .img-frameで外枠を作っています。外枠の大きさをwidth: 70%height: 300pxとしていますが、そこは好きな大きさにできるところです。
  • 画像3枚は.img-01.img-02.img-03のそれぞれに背景画像として指定しています。ここはimg要素を使って普通に画像にしても実現可能なのですが、背景画像にした方がカスタマイズ性が高くできます。どのようにカスタマイズ性が違うのかは後述します。
  • .img-frameoverflow: hiddenを指定して、内枠の背景画像がはみ出したぶんを非表示にします。
  • .img-01.img-02.img-03はそれぞれ、position: absoluteとして、外枠に対して同じ位置で表示されるようにします。
  • .img-01.img-02.img-03それぞれに同じ時間(この例では24秒間ですが、好きな長さに設定可能)のanimationをつけています。3枚それぞれをCSSのanimationで、拡大縮小、透明度の変化をつけることでこのスライドショーが実現できます。

(2)上に半透明の矩形を重ねる

次のように上に半透明の矩形を乗せることもCSSで可能です。

ソースコード

先ほどの(1)のCSSに対して、以下の追記をすればこうなります。

CSS
.img-frame::after{
   content: '';
   position: absolute;
   top: 0;
   left: 0;
   width: 100%;
   height: 100%;
   background-color: rgba(0, 0, 0, .5);
}

解説

外枠に疑似要素を指定して、position: absolute;で外枠と同じ位置に半透明の矩形を乗せています。

(3)テキストを乗せる

次のようなこともCSSだけでできます。

京都

横浜

良い街

ソースコード

(1)のHTMLを次のように変え、疑似要素で付けている半透明の上に乗せた矩形は、外枠ではなく.img-03につける形に変更です。それ以外のCSSは(1)に対する追記です。

HTML
<div class="img-frame">
   <div class="img-01"><p class="msg msg-01">京都</p></div>
   <div class="img-02"><p class="msg msg-02">横浜</p></div>
   <div class="img-03 cover"><p class="msg msg-03">良い街</p></div>    
</div>
CSS
.msg{
   font-size: 20px;
   color: #fff;
   position: absolute;
   top: 50%;
   left: 50%;
   transform: translate(-50% , -50%);
}

.msg-01, .msg-02{
    text-shadow: 2px 2px 3px #000, -1px -1px 3px #000;
}

.img-03.cover::after{
   content: '';
   position: absolute;
   top: 0;
   left: 0;
   width: 100%;
   height: 100%;
   background-color: rgba(0, 0, 0, .7);
}

.msg-03{
   z-index:1;
}

解説

半透明の矩形を外枠に対してつけるのではなく、内枠の背景画像の3番目に対して付けてます。

テキストの位置は、position: absolute;で外枠に対して中央に配置しています。

(4)角丸をつける、画像の大きさを変える

京都

横浜

良い街

ソースコード

(3)のソースコードのCSSに以下の変更/追記をするだけです。

CSS
.img-frame{
   width: 100%;
   height: 200px;
   clip-path: inset(0 round 0 0 0 50px);
} 

解説

外枠のwidthを70%から100%に、heightを300pxから200pxに変えています。

また、外枠にclip-pathで角丸をつけています。

こういうのが、img要素ではなく背景画像を使ったときにカスタマイズ性が高くなるところです。

角丸はborder-radiusでも同様に外枠に対して指定すれば付けられるのですが、border-radiusだとiOSでは現時点、つきません。なので、clip-pathにしています。
こういうの最近多いですね、Appleさん。

(5)画像の表示位置を変える

スマホだと調整が大変なので、ここではPCでだけ変わるようにしています。PCで違いをご確認ください

京都

横浜

良い街

ソースコード

(4)のソースコードのCSSに以下の追記をするだけです。上述の通り、ここではあえてPCでだけ変わるようにしています。

CSS
@media screen and (min-width:768px){
   .img-01{
      background-position: 0 -250px;
   }
   .img-02{
      background-position: 0 -200px;
   }
   .img-03{
      background-position: 0 -200px;
   }
}

解説

背景画像の位置はbackground-positionで変更できるので、それを利用しています。

これもimage要素を使うとできないことです。image要素を使った場合はtransformプロパティを使ってトライすることになると思うんですが、思うようにいかないと思います(私はそうでした)。

これも注意点があって、iOSとAndroidで大きく表示位置が異なります・・なので、ここまでカスタマイズしようと思うと、ちょっと検証が大変ではあります。

画像が流れるスライドショー

縦に流れるスライドショー

次のような流れるスライドショーもCSSだけでできてしまいます。

京都 横浜 良い街
京都 横浜 良い街
京都 横浜 良い街

ソースコード

HTML
<div class="slide-container">
   <div class="slide-wrapper">
      <img class="slide" src="画像の場所" alt="京都">
      <img class="slide" src="画像の場所" alt="横浜">
      <img class="slide" src="画像の場所" alt="良い街">
   </div>
   <div class="slide-wrapper">
      <img class="slide" src="画像の場所" alt="京都">
      <img class="slide" src="画像の場所" alt="横浜">
      <img class="slide" src="画像の場所" alt="良い街">
   </div>
   <div class="slide-wrapper">
      <img class="slide" src="画像の場所" alt="京都">
      <img class="slide" src="画像の場所" alt="横浜">
      <img class="slide" src="画像の場所" alt="良い街">
   </div>
</div>
CSS
.slide-container {
  width: 700px;
  display: flex;
  align-items: center;
  height: 340px;
  overflow: hidden;
  flex-direction: column;
}

.slide-wrapper {
  display: flex;
  flex-direction: column;
  animation: slide-flow 20s infinite linear 1s both;
}

.slide{
  width: 300px;
  object-fit: cover;
  border: 1px solid #ddd;
}

@keyframes slide-flow {
     0% {transform: translateY(0);}
 100% {transform: translateY(-100%);}
}

解説

外枠をoverflow: hidden;にしてはみ出す部分を表示させないようにし、3×3で9枚の画像をループさせて3枚の画像だけがループしているように見せるという方法です。

横に流れるスライドショー

上述のCSSの中で.slide-container.slide-wrapperにつけているflex-direction: column;を削り(flex-direciton: row;にする)、animationの最終地点のところをtransform: translateY(-100%);からtransform: translateX(-100%);にすれば、横に流れる形になります。

スライド全体の幅は、.slide-container-hwidthで指定します。

京都 横浜 良い街
京都 横浜 良い街
京都 横浜 良い街
.slide-container {
    max-width: 700px;
    margin: 50px auto;
    display: flex;
    align-items: center;
    overflow: hidden;
}

.slide-wrapper {
  display: flex;
  animation: slide-flow-h 20s infinite linear 1s both;
}

.slide{
  width: 300px;
  object-fit:cover;
  border: 1px solid #ddd;
}

@keyframes slide-flow {
     0% {transform: translateX(0);}
 100% {transform: translateX(-100%);}

マウスオーバー(ホバー)時に止める

.slide-containerの要素に.slide-paused(名称は自由)などとクラス名を付与し、ホバー時に

animation-play-state: paused;

を指定することで、マウスオーバー(ホバー)時に動きを止めることができます。

ontouchstart=""はスマホのタップ時の挙動を決めるための記述です。

.slide-paused:hover .slide-wrapper img:hoverへのopacityとcursorの指定は、動きを止める部分ではなく、見た目の変更です。なくても動きは止まります。

HTML

<div class="slide-container slide-paused" ontouchstart="">
</div>

CSS

 .slide-paused:hover .slide-wrapper {
   animation-play-state: paused;
 }

 .slide-paused:hover .slide-wrapper img:hover {
   opacity: .8;
   cursor: grabbing;
 }
京都 横浜 良い街
京都 横浜 良い街
京都 横浜 良い街

ボタンを付ける場合

本記事は最初は「スライドショーをCSSのみ(JavaScriptなし)で作る」でしたが、それなのに何故か「ボタン付き」の検索ワードでも上位に表示されていて、それで見ていただいている方も多いようなので、いっそのことタイトルに「ボタン付き」と加えて解説することにしました。

クリックで動作させる場合の動作内容について、画面遷移とそうでないものとに分けた場合に、前者はa要素を用いればJavaScriptなしで動作するものの、後者は現状、JavaScriptを用いるしかありません。

addEventListener()のメソッドを用います。

対象要素.addEventListener( 種類, 関数, false )

のように記述するもので、種類のところを’click’とすれば、対象要素をクリックしたときの動作を決めることができます。

スライドショーを1枚ずつ動かすボタンを付ける場合、ここでご紹介したCSSでの実装方法だと、JavaScriptを用いたとしても難しいので、それであれば最初からJavaScriptで実装するということになります。そうなってくるとそもそも、JavaScriptのライブラリを使った方法が良いと思います。

ニーズがあるかは分かりませんが、スライドショーの動きの停止、再生は、ここでご紹介したCSSによる実装をベースに、JavaScriptで簡単に実装可能です。

京都 横浜 良い街
京都 横浜 良い街
京都 横浜 良い街

ソースコード

HTML

<div class="slider-wrapper">
   <div class="slide-container">
      <div class="slide-wrapper">
         <img class="slide" src="画像の場所" alt="京都">
         <img class="slide" src="画像の場所" alt="横浜">
         <img class="slide" src="画像の場所" alt="良い街">
      </div>
      <div class="slide-wrapper">
         <img class="slide" src="画像の場所" alt="京都">
         <img class="slide" src="画像の場所" alt="横浜">
         <img class="slide" src="画像の場所" alt="良い街">
      </div>
      <div class="slide-wrapper">
         <img class="slide" src="画像の場所" alt="京都">
         <img class="slide" src="画像の場所" alt="横浜">
         <img class="slide" src="画像の場所" alt="良い街">
      </div>
   </div>
   <div class="btns-wrapper">
      <button id="stopBtn" class="slider-btn">STOP</button>
      <button id="startBtn" class="slider-btn">START</button>
   </div>
</div>

JavaScript

const stopBtn = document.getElementById('stopBtn')
const startBtn = document.getElementById('startBtn')
const sliders = document.querySelectorAll('.slide-wrapper')

stopBtn.addEventListener('click', function() {
   sliders.forEach( function(slider){
      slider.style.animation = 'none';
});
}, false);

startBtn.addEventListener('click', function() {
   sliders.forEach( function(slider){
      slider.style.animation = 'slide-flow 20s infinite linear 1s both';
});
}, false);

まとめ

CSSだけでスライドショー作れちゃうよシリーズでした。
ライブラリを使った方が実装は早いというケースももちろんあるとは思いますが、基本的にはJavaScriptを使うよりCSSのみの処理速度が速いと思います。また、ライブラリだと何か思ったように動かないというときに、環境のバグなのかカスタマイズの仕方が悪いのかの特定が難しくなりますし、ちゃんと動きの理屈を理解したコードの方が思ったようにいきやすかったりすると思います。

著者のイメージ画像

BringFlower
稲田 高洋(Takahiro Inada)

2003年から大手総合電機メーカーでUXデザインプロセスの研究、実践。UXデザイン専門家の育成プログラム開発。SEOにおいても重要なW3Cが定めるWeb標準仕様策定にウェブアクセシビリティの専門家として関わる。2010~2018年に人間中心設計専門家を保有。その後、不動産会社向けにSaaSを提供する企業の事業開発部で複数サービスを企画、ローンチ。CMSを提供し1000以上のサイトを分析。顧客サポート、サイト運営にも関わる。2022年3月にBringFlowerを開業し、SEOコンサル、デザイン、ウェブ制作を一手に受ける。グッドデザイン賞4件、ドイツユニバーサルデザイン賞2件、米国IDEA賞1件の受賞歴あり。