毎度のごとく記事のタイトルが長いですね。ラノベかな?
今年の目標はブログタイトルを簡潔に表現する力を身につける事にしようと思います。
本題
下記のような動作を実装したいという相談があり、CSS+jQueryでザックリと作ったのでメモで残しておきます。
- 左側にコンテンツのブロック、右側に画像のブロックを配置
- コンテンツのみスクロールし、画像は位置を固定。
コンテンツの切り替えに合わせて画像をフェードイン・アウトで切り替え。
本当にザックリなので色々と粗があるかもしれませんがとりあえず動きます。
動きはデモページからご確認ください。
※スクロール距離を確保する為ヘッダーとフッターを入れています。あとPCのみでしか見れません。
html
ラッパー要素の中にコンテンツ用のブロック、画像用のブロックを作成します。
contentsの中のdivとimagesの中のpに連番class(scroll-box01,scroll-box02,scroll-box03...)を付けます。
スクロールしてscroll-box02のコンテンツが表示されたらscroll-box02の画像を表示、scroll-box03のコンテンツが表示されたらscroll-box03の画像を表示...という感じの処理をjQueryで書くので、その下準備です。
<div class="wrapper">
<!-- コンテンツのブロック -->
<div class="contents">
<div class="scroll-box01">
<h2>見出し-1</h2>
<p>文字文字文字文字文字文字文字文字文字文字...</p>
</div>
<div class="scroll-box02">
<h2>見出し-2</h2>
<p>文字文字文字文字文字文字文字文字文字文字...</p>
</div>
<div class="scroll-box03">
<h2>見出し-3</h2>
<p>文字文字文字文字文字文字文字文字文字文字...</p>
</div>
<div class="scroll-box04">
<h2>見出し-4</h2>
<p>文字文字文字文字文字文字文字文字文字文字...</p>
</div>
</div>
<!-- 画像のブロック -->
<div class="images">
<p class="scroll-box01"><img src="img/test01.png" alt=""></p>
<p class="scroll-box02"><img src="img/test02.png" alt=""></p>
<p class="scroll-box03"><img src="img/test03.png" alt=""></p>
<p class="scroll-box04"><img src="img/test04.png" alt=""></p>
</div>
</div>
</div>
CSS
- ラッパー要素にdisplay: flex;を指定してコンテンツ用のブロックと画像用のブロックを左右に並べます。
- 画像を配置している親ブロックにheight: 100vh;とposition: sticky;を指定します。
各画像のブロックにはvisibility: hidden;とopacity: 0;を指定しておきます。
position: absolute;等は画像を上下中央に配置するための記述です。 - pにactiveのclassが付いた時visibility: visible;とopacity: 1;にする事で画像を表示します。
first-childにも指定しているのは最初のスクロール時に1枚目の画像を表示しておくためです。
ザックリこんな感じで書いています。
/*ラッパー要素*/
.wrapper{
display: flex;
justify-content: space-between;
position: relative;
}
/*コンテンツのブロック*/
.contents{ width: 60vw; }
.contents div{ padding-top: 50vh; }
.contents div:last-child{ padding-bottom: 50vh; }
/*画像のブロック*/
.images{
width: 40vw;
height: 100vh;
display: flex;
align-items: center;
position: sticky;
position: -webkit-sticky;
top:0;
}
.images p {
height: 400px;
margin: auto;
display: block;
visibility: hidden;
/* 画像が透過pngの時は背景色が必要です */
background: #5bd2d2;
position: absolute;
top: 0;
bottom: 0;
/* フェード速度 */
transition: .8s;
opacity: 0;
}
.images p:first-child,
.images p.active {
visibility: visible;
opacity: 1;
}
jQuery
- '.contents div(scroll-box0*)'ごとにclass名を取得
- '.contents div(scroll-box0*)'が表示されたら同じclass名の画像を表示/それ以外の画像は非表示
という感じの処理を行っています。
$(function(){
$(window).scroll(function () {
$('.contents div').each(function () {
boxNum = $(this).attr("class"),
scrollTop = $(window).scrollTop();
areaTop = $(this).offset().top;
if (scrollTop > areaTop) {
$('.images .' + boxNum).addClass('active');
} else{
$('.images .' + boxNum).removeClass('active');
}
});
});
});