web-dev-qa-db-ja.com

非常に、非常に大きなdiv

私のプロジェクト( BigPictu.re または bigpicture.js GitHubプロジェクト を参照)の場合、潜在的に非常に、非常に、非常に大きな<div>コンテナ。

私が使用する単純なアプローチではパフォーマンスが低下するリスクがあることは知っていましたが、ほとんどの場合、... Chromeのみ!

この小さなページ (以下のコードを参照)をテストすると、パン(クリック+ドラッグ)は次のようになります。

  • Firefoxで通常/スムーズ
  • Internet Explorerでも通常/スムーズ
  • Chromeで非常に遅い(ほぼクラッシュする)!

もちろん、(私のプロジェクトで)コードを追加して、ズームインすると、非常に大きなフォントサイズのテキストが非表示になる可能性があります。それでも、FirefoxとInternet ExplorerはChromeではなく正しく処理するのはなぜですか?

JavaScript、HTML、またはCSSにブラウザに指示する方法はありますか試行しないすべてのアクションに対してページ全体(ここでは10000ピクセル)をレンダリングする方法?(現在のビューポートのみをレンダリングします!)


<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <style>
            html, body {
                overflow: hidden;
                min-height: 100%; }

            #container {
                position: absolute;
                min-height: 100%;
                min-width: 100%; }

            .text {
                font-family: "Arial";
                position: absolute;
            }
        </style>
    </head>

    <body>
        <div id="container">
            <div class="text" style="font-size: 600px; left:100px; top:100px">Small text</div>
            <div class="text" style="font-size: 600000px; left:10000px; top:10000px">Very big text</div>
        </div>

        <script>
            var container = document.getElementById('container'), dragging = false, previousmouse;
            container.x = 0; container.y = 0;

            window.onmousedown = function(e) { dragging = true; previousmouse = {x: e.pageX, y: e.pageY}; }

            window.onmouseup = function() { dragging = false; }

            window.ondragstart = function(e) { e.preventDefault(); }

            window.onmousemove = function(e) {
                if (dragging) {
                    container.x += e.pageX - previousmouse.x; container.y += e.pageY - previousmouse.y;
                    container.style.left = container.x + 'px'; container.style.top = container.y + 'px';
                    previousmouse = {x: e.pageX, y: e.pageY};
                }
            }
        </script>
    </body>
</html>
106
Basj

position: fixedに変更すると、速度が向上するようです。

60
geert3

top/leftの代わりに transform を使用します。

container.style.transform = 'translate(' + container.x + 'px, ' + container.y + 'px)';

jsFiddleでのライブデモ

42
Teemu
  1. 最初のクエスト「なぜ」に答えてください。問題の1つはfont sizeです。フォントサイズが600000pxの場合、ほとんどのブラウザは高すぎると見なして小さくレンダリングしますが、chromeは元のサイズをレンダリングしようとします。chrome要求されたスタイルのこのような大きな文字は非常に高速です。

しかし、Teemuとgeert3の答えを組み合わせて、transformとposition:fixedを使用すると、大きなフォントでもchromeがはるかに高速に動作します。

  1. 2番目の質問への回答:「ページ全体をレンダリングしようとしない方法があります」-コンテナ全体ではなく、コンテナ内の要素にマウスアクションを適用することができます。

最大フォントサイズ: http://jsfiddle.net/74w7yL0a/

firefox 34 - 2 000 px
chrome 39 - 1 000 000 px
safari 8 - 1 000 000 px
ie 8-11 - 1 431 700 px
22
ViliusL

翻訳を使用するというTeemuの答えに加えて:

container.style.transform = 'translate(' + container.x + 'px, ' + container.y + 'px)';

他のベンダープレフィックスも使用する必要があります。これを本体で使用することで簡単に修正できます。

height: 100%;
width: 100%;
position: relative;
overflow: hidden;

そしてこれはhtmlで:

height: 100%;

ただし、これはスクロールを無効にします。それで、私がやることは、mousedownイベントを本体に追加し、mousedownがトリガーされるたびにcssクラスを使用してそれらのスタイルを適用し、mouseupでそのクラスを削除することです。

4
Prisoner

@Teemusの答えはほとんどすべてを行います。

translate3dの代わりにtransformwith top/leftを使用します。

translate3dはハードウェアアクセラレーションを有効にします。

container.style.transform = 'translate3d(' + container.x + 'px, ' + container.y + 'px, 0)';

jsFiddleでのライブデモ

2
Koen.

つかいます display: tableおよびtable-layout:fixed div、またはdivをラップするテーブル。 HTMLの場合:

HTMLテーブルモデルは、作成者の支援により、ユーザーエージェントが、レンダリングを開始する前にすべてのデータを待機するのではなく、インクリメンタルにテーブルをレンダリングできるように設計されています。

ユーザーエージェントが1つのパスでテーブルをフォーマットするには、作成者はユーザーエージェントに次のことを伝える必要があります。

テーブル内の列の数。この情報を提供する方法の詳細については、表の列数の計算に関するセクションを参照してください。これらの列の幅。この情報を提供する方法の詳細については、列の幅の計算に関するセクションを参照してください。

より正確には、COLGROUP要素とCOL要素の組み合わせを使用して列幅が指定されている場合、ユーザーエージェントは1回のパスで表をレンダリングできます。列のいずれかが相対またはパーセンテージで指定されている場合(列の幅の計算に関するセクションを参照)、作成者は表自体の幅も指定する必要があります。

インクリメンタル表示の場合、ブラウザには列の数と幅が必要です。テーブルのデフォルトの幅は、現在のウィンドウサイズ(width = "100%")です。これは、TABLE要素のwidth属性を設定することにより変更できます。デフォルトでは、すべての列の幅は同じですが、テーブルデータが開始される前に1つ以上のCOL要素で列の幅を指定できます。

残りの問題は、列の数です。テーブルの最初の行が受信されるまで待つことを提案する人もいますが、セルに多くのコンテンツがある場合、これには長い時間がかかる可能性があります。全体として、インクリメンタル表示が必要な場合、作成者がTABLE要素の列数を明示的に指定できるようにする方が理にかなっています。

作成者は、セルの内容に合わせてインクリメンタル表示を使用するか、テーブルのサイズを自動的に変更するかをユーザーエージェントに伝える方法が必要です。 2パス自動サイズ変更モードでは、列の数は最初のパスによって決定されます。増分モードでは、列数を前もって指定する必要があります(COLまたはCOLGROUP要素を使用)。

およびCSS:

17.5.2.1固定表レイアウト

この(高速)アルゴリズムを使用すると、テーブルの水平レイアウトはセルの内容に依存しません。テーブルの幅、列の幅、境界線またはセルの間隔のみに依存します。

テーブルの幅は、「width」プロパティで明示的に指定できます。 「auto」の値(「display:table」と「display:inline-table」の両方)は、自動テーブルレイアウトアルゴリズムを使用することを意味します。ただし、通常のフローでテーブルがブロックレベルのテーブル(「表示:テーブル」)である場合、UAは10.3.3のアルゴリズムを使用して幅を計算し、固定テーブルレイアウトを適用しても指定された幅は「auto」です。

参考文献

1
Paul Sweatte

これを分析したところ、元の問題はChrome=表示アーキテクチャ、およびページをレンダリングするためのバックグラウンドスレッドの使用に関連していることがわかりました。

レンダリングを高速にしたい場合は、chrome:flagsに移動し、Impl-side paintingの設定までスクロールし、「Disabled」に設定してからブラウザを再起動します-マウスムーブはスムーズになります。

私が見つけたのは、FPSカウンターを有効にした場合、実際の画面上のパフォーマンスは非常に低くても、このシナリオで報告されるFPSは依然として非常に高いことです。私の暫定的な説明(Chromeディスプレイアーキテクチャの専門家ではない)は、UIスレッドとディスプレイが別々のスレッド上にある場合、divのレンダリングに競合がある可能性があるということです- UIスレッドとレンダリングスレッドが同じスレッド上にある場合、UIスレッドはUIスレッドがレンダリングできるよりも速くメッセージを送信できません。

これをChromeバグとして提出することをお勧めします。

1
Theodore Ferro