MARQUEEタグとは
MARQUEEタグは、大昔に廃止されたタグです。
この機能は廃止されました。まだいくつかのブラウザーで動作するかもしれませんが、いつ削除されてもおかしくないので、使わないようにしましょう。
これは昔に繁華街に溢れていた電光掲示板よろしく、
要素内の文字を永遠にスクロールさせながら流し続ける、という代物です。
このタグは非推奨になったのはhtmlで修飾を行ってはいけない(修飾はCSSに任せろ)というHTML5の基本理念からです。
そこで、MARQUEEタグの機能を継承しつつ、HTML5の理念にも沿った、ナウい(死語)マーキーを作ってみたいと思います。
ナウいマーキーの仕様
シームレスにループさせる
元祖のMARQUEEタグは基本的に左まで文字を流したあと、何も表示されない時間を挟んで、また右端から文字が現れる、という仕様でした。
これだと何も表示していない時間が寂しいので、常に文字が表示されているように、シームレスなループに変更します。
文字をループさせるためだけに文字を要素に直接流し込まない。
簡単にシームレスなループを作る方法として、要素内の文字列を二重にする方法が考えられます。
例えば「アイウエオ」を「アイウエオアイウエオ」として、-50%左方向にアニメーションすればそれで完成なのですが、修飾のためだけに重複した文字列を作るのは良くないので、これを疑似要素を使って実現するようにします。
アニメーションを停止できるようにする。
W3C(のWCAG2.0)によれば、アニメーションされるコンテンツは停止する方法をユーザーに提供するべき、だそうなので、マーキーにマウスを乗せるとアニメーションが一時停止するようにします。
文字幅によってアニメーションが発動するかどうかを判断する
文字が1行に収まるのなら、何も無理にマーキーさせる必要はありません。
なので、jsで文字がはみ出すかどうかを判断し、はみ出す時だけアニメーションするようにします。
ナウいMARQUEEのコーディング
<div class="marq" data-marquee="">
<p class="marq__inner">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Est sint recusandae illo voluptatibus hic rem magnam error eius enim, nobis perferendis cupiditate vel. Quo reprehenderit.</p>
</div>
HTMLはいたって普通です。
二重構造で、cssで利用することになる、data-marquee属性を空で指定しておきます。
.marq {
background-color: #f00;
color: #fff;
white-space: nowrap;
width: 100%;
height: 30px;
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: center;
overflow: hidden;
&::after {
content: '';
}
&__inner {
width: auto;
min-width: 100%;
text-align: center;
}
&::after,
&__inner {
padding: 0 10px;
display: inline-block;
white-space: nowrap;
width: auto;
flex-grow: 0;
flex-shrink: 0;
box-sizing: border-box;
}
&.is-marquee {
&::after {
content: attr(data-marquee);
}
&::after,
& .marq__inner {
animation: marqMove 5s linear 0s infinite normal;
}
}
&:hover {
&::after,
& .marq__inner {
animation-play-state: paused;
}
}
}
@keyframes marqMove {
0% {
transform: translate(0);
}
100% {
transform: translate(-100%);
}
}
scss(css)は少し複雑です。
自動折り返しをなくすためにflexを利用しています。
ポイントとしては::after
疑似要素と.marq__inner
要素が全く同じ見た目になるようにしています。
また、自要素の幅を100%として使えるtranslate
を使ってアニメーションするようにしています。
::after
疑似要素と.marq__inner
要素を同じ量だけ左に動かすことで、シームレスな動きに見えるようにできます。
またanimation-play-state: paused;
でマウスオーバーでアニメーションが止まるようにしています。
Array.prototype.forEach.call(
document.querySelectorAll('.marq'),
item => {
const itemInner = item.querySelector('.marq__inner');
const itemText = itemInner.innerText;
item.dataset.marquee = itemText;
['load', 'resize'].forEach(handle => window.addEventListener(handle, () => {
if (this.innerWidth < itemInner.clientWidth) {
item.classList.add('is-marquee');
} else {
item.classList.remove('is-marquee');
}
}));
},
);
javascriptもそんなに複雑ではありません。やっていることは基本的に2つです。
まず、.marq
要素のdata-marquee属性に中のテキストを挿入しています(::after
疑似要素で利用するため)。
また、ロードイベント、リサイズイベントを監視し、ページ幅より、.marq__inner
要素が大きい時だけ.is-marquee
クラスを付与します。
これによって、アニメーションの有無を決定し、cssのmarqMoveアニメーションが動くようになります。
ナウいデモ
See the Pen PUSEUDO MARQUEE by ichimonzi (@ichimonzi) on CodePen.
複数のマーキーを設置できるように書いたので、文字列の長さが違うマーキーを複数設置してみました。
ウィンドウをリサイズすれば、ウィンドウ幅と文字列の長さによってマーキーの状態が変わるのがわかると思います。
結論
ナウくしてもマーキーはやはりウザい。
改善したい点として、
-
::after
疑似要素だと中にタグ入れられないから結局は普通にdomクローンして挿入したほうがいいんじゃないの? -
animation-duration
が一定だと、長い文字列が入った時流れが超速い - 文字列応じてdurationの秒数を制御して同じ速さにしたい
- 一時停止じゃなくてクリックで完全に止めたい
などいろいろありますが、とりあえず満足はしました。
余談
ちなみに、overflow時の動作を決める、overflow-style
というプロパティの値としてmarquee
が提唱されたことがあったようですが、
2019年現在、overflow-styleプロパティに対応しているブラウザは確認できませんでした。