CSSの「:active」はIE(Edge)で重い

データテーブルなど要素が大量にある画面をIEで開いている時、スクロールが妙に重いので調査したところ、ボタンにかけていた擬似要素「:active」の存在が重くしていると分かりました。

「:active」の中のCSSプロパティではなく、「:active」の擬似要素がCSSに存在するだけで重くなっていました。

しかも最新のEdgeバージョンで。

経緯と状況

下記のデモページをIEで開いてみてください。

デモページ

重さを体感できるようにするため膨大な行のテーブルを overflow:scroll のレイヤーで囲ってますが、中身はどうでもいいです。

クリックしてからすぐスクロールしたり、スクロールバーのツマミからスクロールしようとすると一瞬引っかかると思います。これは「:active」が原因でIE内でCPU使用率が高まっているためです。

下図はIEのDevツールでUIの応答速度を計測したものです。

赤枠を付けてる箇所はクリックした時に発生した処理です。

クリックごとに「スタイル指定」の処理が1秒ほど走っているのですが、その詳細を見ると<body>から始まり全てのタグを走査していました。HTMLタグが多いほどチリツモで重くなっている状態です。

最初はこれがなぜ発生しているのかが理解できず、JSとCSSの両方でシラミ潰ししていました。

原因の「:active」について

デモページでは下記のCSSを設定しています。

.btn:active {
}

中身のプロパティはどうでもよく、.btn 自体もHTMLの中で使っておらず、「:active」がCSSの中に存在することで重さを引き起こしています。

そこで下記のように a タグのセレクタを明示的に書きます。

a.btn:active {
}

そうすると重さが解消されます。
UIの応答速度計測でも、クリックしした時の走査処理が無くなっています。

明示的にタグを指定したのでaタグ以外で走査しなくなったからと思えたのですが、下記のようにaタグ以外を指定するとまた重くなってしまいました。明示的な指定かどうかは関係ないと分かります。

input.btn:active {
}

ここで思い当たるのがCSS2とCSS3による仕様の違いです。

「:active」の擬似要素はCSS2ではaタグのみに使え、CSS3からはあらゆるタグに使えるようになりました。

その経緯を考えると、あくまで推測ですがIEのレンダリングはCSS2の仕様のまま、力技でCSS3の振る舞いをしているのではと思えます。つまり、IEが「なんちゃってCSS3」をやってるのが原因。

デモページはタグの量を増やすため膨大なテーブルで組みましたが、事の発端は文字やinputなど要素の多い100行程度のテーブルだったので、行数ではなくタグの量に比例して重くなるのでテーブルに限った話でもありません。

対策

  • 「:active」をCSSから排除して問題なければ排除する。
  • 表現上排除できないなら「:active」は排除して同様の処理をJSでやる。

Gmailなんかはソース見た感じ、この問題を把握しているのか「:active」に頼らずJSでのクラスのトグルして表現を切り替えてます。

 

 

 

とりあえずな、Edge(笑)って何だよ。おまえいい加減にしろよ。
IE開発者はタンスの角に小指ぶつけてSHINE(輝け)

筆者について

KaBuKi
ゲームとジョジョを愛するファミッ子世代。好きな言葉は「機能美」。
公私ともにWebサービスを作る系男子。