非常に、非常に、非常に大きなdiv


109

私のプロジェクト(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>

54
[OT] 600Kフォントサイズ。視力が非常に悪い人のためのアクセシビリティ機能でなければなりませんか?;-)
geert3 2014

61
@ geert3これは月周回ウェブブラウザ用だと思います
David Wilkins 14

3
Chrome 41.0.2236.0 dev-mでのデモはスムーズです
Pier-Luc Gendreau 2014

11
私はカナリア(41.0.2241.0カナリア)にいますが、まだ遅延が発生しています。
ゲームリグで

3
一般的な考えに反して、IEはほとんどのページをレンダリングするために実際にはChromeよりも高速です。ただし、JavaScriptエンジンは少し遅いです。
Falanwe

回答:


62

に変更するposition: fixedと、スピードが上がります。


27
これは彼の質問に対する直接の回答ではありませんが、彼の最初の問題(Chromeでの応答が遅い)に対する潜在的な解決策です。私見、ボックスの外側を考えることは奨励されるべきです。
geert3 2014

ここでは完全に動作しているようです:gget.it/e0ubdh67/big-div-test_fixed.html。なぜなのかご存知ですか ?:)
Basj

2
推測しかできません。fixedレイアウトは明らかに複雑ではなく、おそらくより多くの最適化を行うことができます。しかし、もしあなたがそれを意味しているのであれば、私はレンダリングエンジンのソースコードを見ていません;-)
geert3

1
この回答とViliusLによって提供された回答はどちらも、異なる「コメントを残す」コメントを持っています。なんてクールなの?
Joe

2
@Joeこれらは、モデレーターが使用するためにStackOverflowによって提供される一連の標準的な回答からのものです。いくつかはしかしより適度にモデレートする必要があります。
geert3 2014

42

transform代わりに使用top/left

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

jsFiddleでのライブデモ


2
非常に奇妙な事は:あなたのjsFiddleで、それは確かにChromeで高速です。私がここで私の元のコードで提案した修正を正確に行いました:gget.it/1owxq8kr/big-div-test_transform.html、そしてこの最後のリンクはChromeでは遅いです:(これはどのように可能ですか?jsFiddleと同じように見えます![注:奇跡的に、geert3の回答は機能するようですが、理由はわかりませんが、機能します:gget.it/e0ubdh67/big-div-test_fixed.html]
Basj

@Basjたぶんバージョンに依存しているかもしれませんが、私のChrome(39.0.2171.71 m)は、コメントでリンクされているページをFFと同じくらいスムーズで高速にパンします。とにかく、位置を設定しfixedて要素をテキストフローから外し、再レンダリングを大幅に節約します。transformMDN のドキュメントでは、「...スタッキングコンテキストが作成されます。その場合、オブジェクトは位置の包含ブロックとして機能します:含まれている固定要素です。」
Teemu

2
奇妙なことに、私はChrome 39.0.2171.71 mも持っています...そして、gget.it / 1owxq8kr / big-div-test_transform.htmlパンが遅くなります。元のバージョンと同じくらい遅くなります(質問自体)。おそらく、ハードウェアアクセラレーションに依存している可能性があります。グラフィックチップが不良なラップトップを持っているため、おそらくハードウェアアクセラレーションはありません...
Basj

1
ラッパー追加@Basj <div style="position:relative;min-height: 900px;">Your's divs</div>jsFiddleがそう
アルフォンソRubalcava

1
@AlfonsoRubalcavaわかりました... jsfiddleがスムーズで直接リンクがスムーズではない理由(Chrome)を説明しています:gget.it/1owxq8kr/big-div-test_transform.html!ありがとう!したがって、パフォーマンスの向上はposition:relativeおそらくgeert3の回答と同様です
Basj

22
  1. 最初のクエスト「なぜ」に答えてください。問題の1つはフォントサイズです。フォントサイズが600000pxの場合、ほとんどのブラウザではフォントサイズが高すぎて小さく表示されますが、クロムは元のサイズを表示しようとします。クロームはあなたが要求したスタイルでそのような大きな文字を非常に速く再描画できないように見えます。

しかし、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

6
実際にはそうです。OPは2つの質問をし、前者は「FF、IEはChromeではなく正しく処理するのはなぜですか?」
Hans Roerdinkholder 2014

面白い。Firefoxが10kで停止し、Chromeが元のサイズをレンダリングしようとすることを示すいくつかの要素を覚えていますか?(それは将来の参照のために興味深いでしょう)。よろしくお願いします@ViliusL!
Basj

1
@Basjは各ブラウザーに最大フォントサイズを追加し(今日テスト済み)、Firefoxでは2kです。
ViliusL 2014

@ViliusLに感謝します!確かに、FFはを制限しfont-size、これがFFのノースローネスの理由である可能性があります。しかし、IEでも非常に遅いはずですが、それは…奇妙です!
Basj

4

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です。


ここであなたが言ったことを追加しようとしました:gget.it/0ufheqmt/big-div-test_prisonersolution.html、それはあなたが何を意味したのですか?ここでは、Chromeでのドラッグがまだ遅いです。あなたにとっても同じですか?(PS:理解できませんでした。これらのCSSの変更、?使用しstyle.transformたりtransform使用したりする代わりに行うことをお勧めします)。ところで@Prisonerの回答ありがとうございます!
Basj

2

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

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

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

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

jsFiddleでのライブデモ


1

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

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

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

これはChromeのバグとして報告することをお勧めします。


1

使用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」の両方)は、自動テーブルレイアウトアルゴリズムを使用することを意味します。ただし、テーブルが通常のフローでブロックレベルのテーブル( 'display:table')である場合、UAは10.3.3のアルゴリズムを使用して幅を計算し、固定テーブルレイアウトを適用することができます(必須ではありません)。指定された幅は「自動」です。

参考文献

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.