完成デモ
とりあえず、完成形を見てもらったほうがわかりやすいので、以下のデモを御覧ください。AbcdefgHijklmn-
ソースコード
demo.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
<script src="main.js"></script>
</head>
<body>
<div class="telop-scroll">
<p>AbcdefgHijklmn-</p>
</div>
</body>
</html>
style.css
html,body{
overflow:hidden;
}
*, :after, :before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-o-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
}
.telop-scroll p{
margin:0;
font-size:8em;
white-space:nowrap;
}
.telop-scroll{
display:flex;
gap:0;
}
.telop-scroll > *{
animation-name: anim-telop-scroll;
animation-duration: 10s;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-fill-mode : forwards;
}
.telop-scroll[data-direction="reverse"] > *{
animation-direction:reverse;
}
@keyframes anim-telop-scroll{
from{
transform:translateX(0);
}
to{
transform:translateX(-100%);
}
}
main.js
/**
* # Title
* - 1要素を横無限スクロールさせるスニペット
*
* # Summary
* - 文字を無限スクロール
* - 写真などのを無限スクロール
*
* # Howto
* - <div class="telop-scroll">~</div>で単一要素を囲う
* - 自動で、内部要素(単一要素)が画面幅に合わせて複製される。
*/
function Main(){
window.addEventListener("resize" , this.set_copy.bind(this))
this.set_copy()
}
// telop-scrollクラスを全て抽出
Main.prototype.set_copy = function(){
const elms = document.querySelectorAll(`.telop-scroll`)
for(const elm of elms){
this.copy(elm)
}
}
// telop-scrollの内部をスクロールサイズに合わせて複製
// - root要素の2倍以上になるように、内部要素(単一要素)をコピーする(既にコピーされていて多い場合は削除する)
Main.prototype.copy = function(root){
const root_width = root.offsetWidth
const elm = root.firstElementChild
const elm_width = elm.offsetWidth
const elm_count = root.children.length
let need_count = Math.ceil((root_width * 2) / elm_width)
need_count = need_count > 2 ? need_count : 2
console.log(root_width,elm_width,elm_count,need_count)
if(elm_count < need_count){
for(let i=0; i<need_count - elm_count; i++){
const node = root.firstElementChild.cloneNode(true)
root.appendChild(node)
}
}
else if(elm_count > need_count){
for(let i=0; i< elm_count - need_count; i++){
root.removeChild(root.lastElementChild)
}
}
}
switch(document.readyState){
case "complete":
case "interactive":
new Main()
break
default:
window.addEventListener("DOMContentLoaded", (()=> new Main()))
}
解説
簡単なように見えて、結構ハマりました。 かつて、ガラケー時代に良く使われたmarqueeという、文字をスクロールさせる機能がHTMLにありました。 参考 : https://developer.mozilla.org/ja/docs/Web/HTML/Element/marquee でも、これはIE専用として作られたもので、今現在使うことは推奨されていないようです。 今回の基本的な仕様として、無限ループなので、marqueeのように、文字がスクロールするだけではなく、繰り返しのタイリングパターンみたいになる必要がありました。 そこで、繰り返したい要素を、必要な個数分コピーする必要があります。スクロール要素が画面より大きい場合
画面サイズ(スクロールエリア)よりも大きい要素の場合は、後ろにひとつだけ同じ要素をコピーします。スクロール要素が画面より小さい場合
要素が小さい場合は、必要なサイズに達する(サイズよりも1個多く)まで、要素をコピーする必要があります。 ※計算式としては、エリアサイズ / 要素サイズ(少数値繰り上げ) + 1で考えると簡単に計算できます。cssとjavascriptの併用
できるだけCSSでやりたかったんですが、要素をコピーするという任意の処理がどうしてもJavascripを必要としました。 アニメーションの設定などは、CSSで行い、要素コピーのみjavascriptに徹すればシンプルにできるかと思いますね。画面リサイズ対応
Javascriptがもう一箇所必要でした。 パソコンブラウザの場合に、ブラウザサイズを任意に変更した場合の、onresizeイベントで、要素のコピー数を変更しなければいけないという点です。 これも、イベント操作で、効率的に画面サイズに応じてコピー数(多い場合は削除数)などを割り出して追加と削除処理を行っています。いろいろなデモ
今回のプログラムを使って、いろいろな応用の表現ができるので、サンプルを掲載しておきます。画像のスクロール
<div class="telop-scroll" style="--telop-time:20.0s;">
...
</div>
逆スクロール
文字が逆に流れますよ!!!
<div class="telop-scroll" data-direction="reverse" >
...
</div>
0 件のコメント:
コメントを投稿