Div yang sangat, sangat, sangat besar

109

Untuk proyek saya (lihat BigPictu.re atau bigpicture.js proyek GitHub ), saya harus berurusan dengan potensi yang sangat, sangat, sangat besar <div>kontainer.

Saya tahu ada risiko kinerja yang buruk dengan pendekatan sederhana yang saya gunakan, tetapi saya tidak berharap sebagian besar terjadi dengan ... Chrome saja!

Jika Anda menguji halaman kecil ini (lihat kode di bawah), panning (klik + drag) akan menjadi:

  • Normal / mulus di Firefox
  • Normal / mulus bahkan di Internet Explorer
  • Sangat lambat (hampir mogok) di Chrome!

Tentu saja, saya dapat menambahkan beberapa kode (dalam proyek saya) untuk melakukan itu ketika Anda banyak memperbesar, teks dengan ukuran font yang berpotensi sangat besar akan disembunyikan. Tapi tetap saja, mengapa Firefox dan Internet Explorer menanganinya dengan benar dan bukan Chrome?

Apakah ada cara dalam JavaScript, HTML, atau CSS untuk memberi tahu browser agar tidak mencoba merender seluruh halaman (yang lebarnya 10.000 piksel di sini) untuk setiap tindakan? (hanya membuat viewport saat ini!)


<!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>
Basj
sumber
54
[OT] Ukuran font 600K. Haruskah menjadi fitur aksesibilitas untuk orang dengan penglihatan mata yang sangat buruk? ;-)
geert3
61
@ geert3 Saya yakin ini untuk peramban web yang mengorbit bulan
David Wilkins
3
Demo Anda lancar di Chrome 41.0.2236.0 dev-m
Pier-Luc Gendreau
11
Saya menggunakan kenari (41.0.2241.0 kenari) dan saya masih mendapatkan lag. Kalian harus mencobanya di laptop daripada di rig gaming, Anda akan melihatnya
markasoftware
3
Berlawanan dengan kepercayaan populer, IE sebenarnya lebih cepat daripada Chrome untuk merender sebagian besar halaman. Mesin javascript-nya sedikit lebih lambat.
Falanwe

Jawaban:

62

Mengubah menjadi position: fixedtampaknya mempercepat segalanya.

geert3
sumber
27
Ini bukan jawaban langsung atas pertanyaannya, tetapi ini adalah solusi potensial untuk masalah awalnya (respons lambat di Chrome). Berpikir di luar kotak harus didorong, IMHO.
geert3
Di sini tampaknya berfungsi dengan sempurna: gget.it/e0ubdh67/big-div-test_fixed.html . Apa kamu tahu kenapa ? :)
Basj
2
Saya hanya bisa menebak. fixedjelas tidak terlalu rumit untuk ditata dan mungkin mereka dapat melakukan lebih banyak pengoptimalan. Tetapi saya belum melihat kode sumber mesin rendering jika yang Anda maksud ;-)
geert3
1
Jawaban ini, dan yang diberikan oleh ViliusL, sama-sama memiliki komentar "tinggalkan komentar" yang sama, oleh orang yang berbeda. Betapa kerennya itu?
Joe
2
@Joe ini adalah dari serangkaian jawaban standar yang disediakan oleh StackOverflow untuk digunakan oleh moderator. Beberapa perlu memoderasi lebih moderat.
geert3
42

Gunakan transformalih-alih top/left:

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

Demo langsung di jsFiddle .

Teemu
sumber
2
Hal yang sangat aneh : di jsFiddle Anda, memang cepat dengan Chrome. Saya melakukan modifikasi persis seperti yang Anda usulkan dalam kode asli saya di sini: gget.it/1owxq8kr/big-div-test_transform.html , dan tautan terakhir ini lambat di Chrome :( Bagaimana ini mungkin? Ini terlihat sama dengan jsFiddle Anda ! [Catatan: secara ajaib, jawaban geert3 tampaknya berhasil, saya tidak tahu mengapa tetapi berhasil: gget.it/e0ubdh67/big-div-test_fixed.html]
Basj
@Basj Mungkin tergantung versinya, Chrome saya (39.0.2171.71 m) memindai halaman yang ditautkan dalam komentar Anda sehalus dan secepat FF. Bagaimanapun, mengatur posisi untuk fixedmengeluarkan elemen dari aliran teks dan menghemat banyak rendering ulang. Dalam dokumentasi transformMDN mengatakan: "... konteks yang bertumpuk akan dibuat. Dalam hal ini objek akan bertindak sebagai blok berisi untuk posisi: elemen tetap yang dikandungnya."
Teemu
2
Aneh, saya memiliki Chrome 39.0.2171.71 m juga ... dan gget.it/1owxq8kr/big-div-test_transform.html panci lambat, lambat seperti versi asli saya (dalam pertanyaan itu sendiri). Oohhh mungkin itu tergantung pada akselerasi perangkat keras: Saya mungkin tidak memiliki akselerasi perangkat keras, karena saya memiliki laptop dengan chip grafis yang buruk ...
Basj
1
@Basj menambahkan pembungkus <div style="position:relative;min-height: 900px;">Your's divs</div>jsFiddle begitu juga
Alfonso Rubalcava
1
@AlfonsoRubalcava Oh ok ... Ini menjelaskan mengapa jsfiddle mulus dan tautan langsung tidak mulus (Chrome): gget.it/1owxq8kr/big-div-test_transform.html ! Terima kasih! Jadi peningkatan kinerja berasal dari kemungkinan position:relative, yang mirip dengan jawaban
geert3
22
  1. Jawaban untuk pertanyaan pertama "mengapa". Salah satu masalahnya adalah ukuran font . Anda memiliki ukuran font 600000px, kebanyakan browser akan melihatnya sebagai terlalu tinggi dan membuat lebih kecil, sementara chrome mencoba untuk membuat ukuran aslinya. Sepertinya chrome tidak dapat mengecat ulang huruf besar dengan gaya yang Anda minta dengan sangat cepat.

Tetapi menggabungkan jawaban Teemu dan geert3 - menggunakan transform dan position: fixed, membuat chrome bekerja lebih cepat bahkan dengan font besar.

  1. Jawaban untuk pertanyaan kedua: "Adakah cara ... untuk tidak mencoba merender seluruh halaman" - Anda dapat mencoba menerapkan tindakan mouse untuk elemen dalam penampung, bukan untuk seluruh penampung.

Ukuran font maksimum: 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
ViliusL
sumber
6
Memang benar. OP mengajukan dua pertanyaan, yang pertama dijawab: "mengapa FF, IE menanganinya dengan benar dan bukan Chrome?"
Hans Roerdinkholder
Menarik. Apakah Anda memiliki beberapa elemen dalam pikiran yang menunjukkan bahwa Firefox berhenti pada 10k dan bahwa Chrome mencoba membuat ukuran aslinya? (Ini akan menarik untuk referensi di masa mendatang). Terima kasih sebelumnya @ViliusL!
Basj
1
@Basj menambahkan ukuran font maksimum untuk setiap browser (diuji hari ini), dan itu adalah 2k untuk firefox.
ViliusL
Terima kasih banyak @ViliusL! Memang, FF membatasi font-sizedan ini bisa menjadi alasan tidak adanya kelambatan pada FF. Tapi seharusnya juga sangat lambat di IE, tapi tidak ... Aneh!
Basj
4

Selain jawaban Teemu tentang penggunaan terjemahan:

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

Yang mana Anda juga harus menggunakan prefiks vendor lain, Anda dapat memperbaikinya dengan menggunakan ini di bagian tubuh:

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

dan ini di html:

height: 100%;

ini akan, bagaimanapun, menonaktifkan pengguliran. Jadi apa yang akan saya lakukan adalah, menambahkan mousedownacara ke tubuh dan menerapkan gaya tersebut menggunakan kelas css setiap kali mousedowndipicu, dan menghapus kelas itu pada mouseup.

Tawanan
sumber
Saya mencoba menambahkan apa yang Anda sebutkan di sini: gget.it/0ufheqmt/big-div-test_prisonersolution.html , apakah itu yang Anda maksud? Di sini masih lambat menyeret dengan Chrome. Yang sama untuk Anda? (PS: Saya tidak mengerti: Anda menyarankan untuk melakukan modifikasi CSS ini daripada menggunakan style.transformatau dengan menggunakan transform?). Terima kasih atas jawaban Anda @Prisoner!
Basj
2

Jawaban @Teemus hampir melakukan semuanya.

Gunakan transform dengan,translate3d bukan top/left.

translate3d mengaktifkan akselerasi perangkat keras.

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

Demo langsung di jsFiddle .

Koen.
sumber
1

Saya menganalisis ini dan saya menemukan bahwa masalah asli terkait dengan arsitektur tampilan Chrome, dan penggunaan utas latar belakang untuk merender halaman.

Jika Anda ingin rendering yang cepat, buka chrome: flags, gulir ke setelan Impl-side painting, dan setel "Disabled", lalu mulai ulang browser - gerakan mouse akan lancar.

Apa yang saya temukan adalah jika Anda mengaktifkan penghitung FPS, FPS yang dilaporkan dalam skenario ini masih sangat tinggi, meskipun kinerja layar sebenarnya sangat rendah. Penjelasan tentatif saya (bukan ahli arsitektur tampilan Chrome) adalah bahwa jika utas UI dan tampilan berada di utas terpisah, maka mungkin ada perselisihan dalam rendering div - dalam kasus di mana utas UI dan utas rendering ada di utas yang sama, utas UI tidak dapat mengirim pesan lebih cepat dari yang dapat dirender oleh utas UI.

Saya menyarankan bahwa ini harus diajukan sebagai bug Chrome.

Theodore Ferro
sumber
1

Gunakan display: tabledan table-layout:fixedpada div, atau tabel yang membungkus div. Dalam HTML:

Model tabel HTML telah dirancang sehingga, dengan bantuan penulis, agen pengguna dapat merender tabel secara bertahap (yaitu, saat baris tabel tiba) daripada harus menunggu semua data sebelum mulai merender.

Agar agen pengguna memformat tabel dalam sekali jalan, penulis harus memberi tahu agen pengguna:

Jumlah kolom dalam tabel. Silakan baca bagian tentang menghitung jumlah kolom dalam tabel untuk mengetahui detail tentang cara memberikan informasi ini. Lebar kolom ini. Silakan baca bagian tentang menghitung lebar kolom untuk mengetahui detail tentang cara memberikan informasi ini.

Lebih tepatnya, agen pengguna dapat merender tabel dalam sekali jalan ketika lebar kolom ditentukan menggunakan kombinasi elemen COLGROUP dan COL. Jika ada kolom yang ditentukan dalam istilah relatif atau persentase (lihat bagian tentang menghitung lebar kolom), penulis juga harus menentukan lebar tabel itu sendiri.

Untuk tampilan inkremental, browser membutuhkan jumlah kolom dan lebarnya. Lebar default tabel adalah ukuran jendela saat ini (lebar = "100%"). Ini dapat diubah dengan mengatur atribut lebar elemen TABLE. Secara default, semua kolom memiliki lebar yang sama, tetapi Anda dapat menentukan lebar kolom dengan satu atau beberapa elemen COL sebelum data tabel dimulai.

Masalah yang tersisa adalah jumlah kolom. Beberapa orang menyarankan menunggu sampai baris pertama dari tabel telah diterima, tapi ini bisa memakan waktu lama jika selnya memiliki banyak konten. Secara keseluruhan lebih masuk akal, ketika tampilan inkremental diinginkan, untuk membuat penulis secara eksplisit menentukan jumlah kolom dalam elemen TABLE.

Penulis masih memerlukan cara untuk memberi tahu agen pengguna apakah akan menggunakan tampilan tambahan atau menyesuaikan ukuran tabel secara otomatis agar sesuai dengan konten sel. Dalam mode penentuan ukuran otomatis dua lintasan, jumlah kolom ditentukan oleh lintasan pertama. Dalam mode inkremental, jumlah kolom harus disebutkan di depan (dengan elemen COL atau COLGROUP).

dan CSS:

17.5.2.1 Tata letak tabel tetap

Dengan algoritme (cepat) ini, tata letak horizontal tabel tidak bergantung pada konten sel; itu hanya bergantung pada lebar tabel, lebar kolom, dan batas atau spasi sel.

Lebar tabel dapat ditentukan secara eksplisit dengan properti 'width'. Nilai 'auto' (untuk 'display: table' dan 'display: inline-table') berarti menggunakan algoritma tata letak tabel otomatis. Namun, jika tabel adalah tabel tingkat blok ('display: table') dalam aliran normal, UA dapat (tetapi tidak harus) menggunakan algoritme 10.3.3 untuk menghitung lebar dan menerapkan tata letak tabel tetap meskipun lebar yang ditentukan adalah 'otomatis'.

Referensi

Paul Sweatte
sumber