CSSでスライドショーをつくる(SCSS)

#CSSスライドショー

JSを一切使わない、フェードアニメーションによるスライドショーを作成しました。

##使用言語

- HTML
- CSS(時短のためSCSSを使用、CSSでもできます。)



##完成系です。いろいろと見た目もつけてます。

<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="result" data-user="k1-web" data-slug-hash="xxxomJO" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="xxxomJO">
  <span>See the Pen <a href="https://codepen.io/k1-web/pen/xxxomJO">
  xxxomJO</a> by k1-web (<a href="https://codepen.io/k1-web">@k1-web</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>


##内容の解説


###まずはHTMLでスライドショーのDOMから。
```slideshow.html
<div class="slideshow">
	<input type="radio" name="slideshow" id="s-1" checked>
	<input type="radio" name="slideshow" id="s-2">
	<input type="radio" name="slideshow" id="s-3">
	<input type="radio" name="slideshow" id="s-4">
	<input type="radio" name="slideshow" id="s-5">
	<ul class="slideshow_list">
		<li class="item-1" style="background:#ff7f7f;"></li>
		<li class="item-2" style="background:#bf7fff;"></li>
		<li class="item-3" style="background:#7fffff;"></li>
		<li class="item-4" style="background:#7fff7f;"></li>
		<li class="item-5" style="background:#ffbf7f;"></li>
	</ul>
	<div class="slideshow_label">
		<label for="s-1"></label>
		<label for="s-2"></label>
		<label for="s-3"></label>
		<label for="s-4"></label>
		<label for="s-5"></label>
	</div>
	<div class="slideshow_page">
		<label for="s-1"></label>
		<label for="s-2"></label>
		<label for="s-3"></label>
		<label for="s-4"></label>
		<label for="s-5"></label>
	</div>
</div>
```
HTMLですが、PHPとかPugとかで個数分forなどで回すと簡単に制御できます。
例えば、PHPでやるとすると下記のように枚数を簡単に制御できます。

```slideshow.php
<?php $slideNum = 5 ; ?>
<div class="slideshow">
	<?php for($i=1;$i<=$slideNum;$i++): ?>
	<input type="radio" name="slideshow" id="s-<?php echo $i; ?>"<?php echo $i == '1' ? ' checked': ''; ?>>
	<?php endfor; ?>
	<ul class="slideshow_list">
		<?php for($i=1;$i<=$slideNum;$i++): ?>
		<li class="item-<?php echo $i; ?>"></li>
		<?php endfor; ?>
	</ul>
	<div class="slideshow_label">
		<?php for($i=1;$i<=$slideNum;$i++): ?>
		<label for="s-<?php echo $i; ?>"></label>
		<?php endfor; ?>
	</div>
	<div class="slideshow_page">
		<?php for($i=1;$i<=$slideNum;$i++): ?>
		<label for="s-<?php echo $i; ?>"></label>
		<?php endfor; ?>
	</div>
</div>
```

####解説-スライド画像の部分
```slideshow.html
	<ul class="slideshow_list">
		<li class="item-1" style="background:#ff7f7f;"></li>
		<li class="item-2" style="background:#bf7fff;"></li>
		<li class="item-3" style="background:#7fffff;"></li>
		<li class="item-4" style="background:#7fff7f;"></li>
		<li class="item-5" style="background:#ffbf7f;"></li>
	</ul>
```
スライドショーの画像とかを入れる部分、スライドの枚数分、<li>タグを作成。
本来は<li>タグの中に<img>タグなどをいれますが、今回は画像添付が面倒なので、背景色を指定しているだけです。


####解説-<input>タグの部分
```slideshow.html
	<input type="radio" name="slideshow" id="s-1" checked>
	<input type="radio" name="slideshow" id="s-2">
	<input type="radio" name="slideshow" id="s-3">
	<input type="radio" name="slideshow" id="s-4">
	<input type="radio" name="slideshow" id="s-5">
```
スライドショーのうち、どこが今見えている所かを判定するためのラジオボタンになります。
スライドの枚数分<input>を作成し、一番上位の親要素の直下に<input>を指定してください。
CSSセレクタの「~」という、隣接する要素を指定できるセレクタを使用するので、
スライドの<li>タグや、<label>タグの親要素が<input>タグに隣接していないとスタイルをあてられません。

また、見た目上には非表示にしていますが、<label>要素で選択し、2番目の画像なら2番目にチェックみたいな感じで動作しています。


####解説-左右の矢印ボタンとぺジテーション
```slideshow.html
	<div class="slideshow_label">
		<label for="s-1"></label>
		<label for="s-2"></label>
		<label for="s-3"></label>
		<label for="s-4"></label>
		<label for="s-5"></label>
	</div>
	<div class="slideshow_page">
		<label for="s-1"></label>
		<label for="s-2"></label>
		<label for="s-3"></label>
		<label for="s-4"></label>
		<label for="s-5"></label>
	</div>
```
先程のラジオボタンに対応するラベルです。2つ存在しても同じ#s-Nのラジオボタンに対応しています。
今回は.slideshow_labelの中の<label>タグは進む・戻るボタンとして、.slideshow_pageはぺジテーションとして動作します。


###本題のCSS(SCSS)です
codepenから説明に必要部分だけ抜粋しています。

```slideshow.scss
@mixin slideLength($length, $show){
	$page: ceil($length / $show);
	content: $page;
	@for $i from 1 through $page {
		&:nth-of-type(#{$i}):checked {
			& ~ .slideshow_list {
				> li:nth-of-type(n+#{$i * $show - $show + 1}):nth-of-type(-n+#{$i * $show}) {
					opacity: 1;
					z-index: 10;
					> a::before {
						z-index: 11;
					}
				}
			}
			& ~ .slideshow_label {
				$prev: $i - 1;
				$next: $i + 1;
				@if $prev < 1 {
					$prev: $prev + $page;
				}
				@if $next > $page {
					$next: $next - $page;
				}
				> label:nth-of-type(#{$prev}) {
					display: block;
					right: auto;
					&::before {
						right: auto;
						-webkit-transform: rotate(45deg);
						transform: rotate(45deg);
					}
				}
				> label:nth-of-type(#{$next}) {
					display: block;
					left: auto;
					&::before {
						left: auto;
						-webkit-transform: rotate(-135deg);
						transform: rotate(-135deg);
					}
				}
			}
			& ~ .slideshow_page {
				> label:nth-of-type(#{$i})::before {
					content: '';
				}
			}
		}
	}
}

.slideshow {
  position: relative;
    input[type="radio"] {
      display: none;
      opacity: 0;
      width: 0;
      height: 0;
      margin: 0;
      padding: 0;

      $length: 5; //合計の枚数
      $show: 1; //1ページあたりに見せる数
      @include slideLength($length, $show);
  }
  .slideshow_list {
    > li {
      display: block;
      width: 300px;
      height: 150px;
      //~~
      opacity: 0;
      -webkit-transition: opacity 0.3s ease-in-out;
      transition: opacity 0.3s ease-in-out;
    }
  }    
  .slideshow_label {
    > label {
      display: none;
      width: 40px;
      height: 40px;
      background-color: #fff;
      border: 1px solid #f30;
      border-radius: 50%;
      cursor: pointer;
      position: absolute;
      top: 52px;
      left: 20px;
      right: 20px;
    }
  }
  .slideshow_page {
    > label {
      display: inline-block;
      width: 10px;
      height: 10px;
      background-color: #a8b7c6;
      border-radius: 50%;
      cursor: pointer;
      position: relative;
      &::before {
        display: inline-block;
        width: 10px;
        height: 10px;
        background-color: #777;
        cursor: pointer;
        position: relative;
        border-radius: 50%;
        position: absolute;
        top: 0;
        left: 0;
      }
    }
  }
}
```

####解説-スライド画像の部分
```slideshow.scss
  .slideshow_list {
    > li {
      display: block;
      width: 300px;
      height: 150px;
      //~~
      opacity: 0;
      -webkit-transition: opacity 0.3s ease-in-out;
      transition: opacity 0.3s ease-in-out;
    }
  }
```
opacityを0にしていて、transitionでopacityの透過をアニメーションにしています。
後ほど解説するラジオボタンのチェックを判定してopacityを1にしています。

####解説-inputタグの部分
```slideshow.scss
@mixin slideLength($length, $show){
	$page: ceil($length / $show);
	content: $page;
	@for $i from 1 through $page {
		&:nth-of-type(#{$i}):checked {
			& ~ .slideshow_list {
				> li:nth-of-type(n+#{$i * $show - $show + 1}):nth-of-type(-n+#{$i * $show}) {
					opacity: 1;
					z-index: 10;
					> a::before {
						z-index: 11;
					}
				}
			}
			& ~ .slideshow_label {
				$prev: $i - 1;
				$next: $i + 1;
				@if $prev < 1 {
					$prev: $prev + $page;
				}
				@if $next > $page {
					$next: $next - $page;
				}
				> label:nth-of-type(#{$prev}) {
					display: block;
					right: auto;
					&::before {
						right: auto;
						-webkit-transform: rotate(45deg);
						transform: rotate(45deg);
					}
				}
				> label:nth-of-type(#{$next}) {
					display: block;
					left: auto;
					&::before {
						left: auto;
						-webkit-transform: rotate(-135deg);
						transform: rotate(-135deg);
					}
				}
			}
			& ~ .slideshow_page {
				> label:nth-of-type(#{$i})::before {
					content: '';
				}
			}
		}
	}
}

.slideshow {
    input[type="radio"] {
      display: none;
      opacity: 0;
      width: 0;
      height: 0;
      margin: 0;
      padding: 0;

      $length: 5; //合計の枚数
      $show: 1; //1ページあたりに見せる数
      @include slideLength($length, $show);
  }
}
```
input:nth-of-type(1)がチェック付いた時には、.slideshow_list > li:nth-of-type(1)をopacity: 1;にして表示、
input:nth-of-type(2)がチェック付いた時には、.slideshow_list > li:nth-of-type(2)をopacity: 1;にして表示...
のようにラジオボタンでnth-of-typeを利用し、何番目にチェックついたら何番目のスタイルを変更するという動作にしています。

左右の矢印部分は、input:nth-of-type(2)だったら.slideshow_label>label:nth-of-type(1)を戻るボタンとして表示、
.slideshow_label>label:nth-of-type(3)を進むボタンとして表示、というようにチェックした数値の前後を表示としています。

ぺジテーションはそれぞれに対応したラベルに対してチェックを付けるようになっています。

SCSSの場合は上記らを自動的に計算できるので、関数化して「$length」に応じた枚数分スライドできるようになっています。


##あとがき

フェードアニメーションのスライドショーはラジオボタンで認識して表示非表示で切り替える簡単な仕組みで作れます。
これが左右に動くスライドショーとなると、なかなか難しくなるので次回挑戦してみたいと思います。