LoginSignup
58
23

More than 5 years have passed since last update.

ナウい(死語)MARQUEE(死語)を考えてみる

Last updated at Posted at 2019-02-28

MARQUEEタグとは

MARQUEEタグは、大昔に廃止されたタグです。

この機能は廃止されました。まだいくつかのブラウザーで動作するかもしれませんが、いつ削除されてもおかしくないので、使わないようにしましょう。

MDN <marquee>: マーキー要素 (廃止)より

これは昔に繁華街に溢れていた電光掲示板よろしく、
要素内の文字を永遠にスクロールさせながら流し続ける、という代物です。

このタグは非推奨になったのはhtmlで修飾を行ってはいけない(修飾はCSSに任せろ)というHTML5の基本理念からです。

そこで、MARQUEEタグの機能を継承しつつ、HTML5の理念にも沿った、ナウい(死語)マーキーを作ってみたいと思います。

ナウいマーキーの仕様

シームレスにループさせる

元祖のMARQUEEタグは基本的に左まで文字を流したあと、何も表示されない時間を挟んで、また右端から文字が現れる、という仕様でした。
これだと何も表示していない時間が寂しいので、常に文字が表示されているように、シームレスなループに変更します。

文字をループさせるためだけに文字を要素に直接流し込まない。

簡単にシームレスなループを作る方法として、要素内の文字列を二重にする方法が考えられます。

例えば「アイウエオ」を「アイウエオアイウエオ」として、-50%左方向にアニメーションすればそれで完成なのですが、修飾のためだけに重複した文字列を作るのは良くないので、これを疑似要素を使って実現するようにします。

アニメーションを停止できるようにする。

W3C(のWCAG2.0)によれば、アニメーションされるコンテンツは停止する方法をユーザーに提供するべき、だそうなので、マーキーにマウスを乗せるとアニメーションが一時停止するようにします。

文字幅によってアニメーションが発動するかどうかを判断する

文字が1行に収まるのなら、何も無理にマーキーさせる必要はありません。
なので、jsで文字がはみ出すかどうかを判断し、はみ出す時だけアニメーションするようにします。

ナウいMARQUEEのコーディング

HTML
<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属性を空で指定しておきます。

SCSS
.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;でマウスオーバーでアニメーションが止まるようにしています。

javascript
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プロパティに対応しているブラウザは確認できませんでした。

58
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
58
23