2012-07-02 28 views
14

Tôi đã gặp phải sự cố trong phiên bản webkit trên thiết bị di động (cụ thể là Webkit 534.46 trên iOS 5.1.1 dưới dạng Safari trên thiết bị di động và giờ đây là Chrome dành cho iOS). đã từng thấy. (tức là các bản trình diễn bên dưới sẽ được xem trên phiên bản webkit di động.)Mobile Webkit reflow issue

Here is a live example of the issue. Cốt lõi của CSS cực kỳ thẳng về phía trước. Nó định vị một chỉ mục bảng chữ cái dọc theo bên trái của trang:

#index { 
    left:0; margin:0; padding:0; position:fixed; top:0; width:3em; 
} 

Sự cố xảy ra khi một phần tử được cố định trên đầu thân. Nó hoàn toàn có thể được tương tác với cho đến khi các thay đổi cuộn và sau đó nó dừng chấp nhận đầu vào. Nếu tôi (theo cách thủ công) hãy xáo trộn cuộn giấy ngay cả một pixel thì nó sẽ hoạt động trở lại. Ví dụ được giữ đơn giản nhất có thể và không sử dụng bất kỳ JavaScript nào. Sau khi thực sự búa vào nó, tôi đã phát hiện ra rằng nó xuất hiện rằng các yếu tố nghĩ rằng nó được cuộn nhưng đã được sửa chữa trực quan. Nói cách khác, nếu bạn nhấp vào 'A', sau đó thử nhấp vào 'A' một lần nữa, đôi khi bạn sẽ nhận được nhấp chuột thứ hai nhưng nó sẽ tiếp tục trong danh sách. Điều này có vẻ giống như một vấn đề CSS reflow với tôi. Tôi biết rằng webkit di động cố gắng giảm số lượng các phản hồi.

Here is a live example of the workaround.

tôi có thể sử dụng JS để buộc các CSS của toàn bộ tài liệu reflow trên cuộn (với van tiết lưu, giúp ngăn chặn nó xảy ra cho đến khi 100ms sau khi di chuyển) mà dường như để workaround vấn đề này trong đơn giản thí dụ. Thật không may, điều này không giúp được phiên bản thế giới thực của vấn đề này.

This is the code for the issue page and the workaround script.

Câu hỏi của tôi là những gì đang xảy ra ở đây và có một workaround CSS mà tôi đang thiếu? Cụ thể, tôi tò mò liệu bất kỳ guru CSS nào có thể tìm ra tình huống bố cục nào ngăn cản các nhấp chuột chạm vào vị trí chính xác trên phần tử cố định? Một sự hiểu biết tốt hơn có thể giúp tìm một sửa chữa thực sự.

Chỉnh sửa: Tôi quên đề cập đến ví dụ rõ ràng buộc khung nhìn đến kích thước của cửa sổ. Vì vậy, người dùng không thể phóng to/thu nhỏ, có nghĩa là vị trí: cố định nên neo phần tử vào bên trái của cửa sổ.

Cập nhật (2012-09-20): Điều này dường như được khắc phục trong Mobile Safari trên iOS 6 (cũng như UIWebView). Bất kỳ workaround đầu tiên nên kiểm tra để chắc chắn rằng nó là trên iOS < 6. Ví dụ, sử dụng CssUserAgent này sẽ như thế nào:

if (parseFloat(cssua.ua.ios) < 6) { /* ... */ } 
+0

Tôi vẫn đang giải quyết các cách giải quyết khác nhau trong hai câu trả lời để tìm "tốt nhất". Tôi đã đưa cả hai bạn một +1 cho các liên kết. Tôi sẽ trao tiền thưởng cho bất kỳ điều gì thực sự khắc phục vấn đề của tôi. Cảm ơn! – mckamey

+0

Tôi vẫn đang tìm kiếm giải pháp hoạt động trong trường hợp cụ thể của mình, nhưng cửa sổ tiền thưởng đang cạn dần nên tôi sẽ trao giải thưởng cho @Paul Sweatte kể từ khi anh ấy trả lời đầu tiên và liên kết của anh ấy có nhiều giải pháp khác nhau. Cảm ơn mọi người! – mckamey

Trả lời

9

Câu trả lời mà thực sự giải quyết vấn đề cụ thể của tôi là một biến thể của một giải pháp tìm thấy in one of @Paul Sweatte's links:

Về cơ bản, một div đơn giản đó là cao hơn cơ thể được bổ sung. Khi nó được lấy ra, nó làm cho cơ thể có hiệu quả di chuyển hoặc reflow. Việc đặt độ trễ thành 0ms giữa việc thêm/xóa là đủ để cho phép DOM tính toán lại mà không gây ra bất kỳ nhấp nháy nào. Đây là kịch bản tối thiểu tôi có thể tìm thấy giải quyết được hoàn toàn vấn đề cho tất cả các thành phần position:fixed trên trường hợp cụ thể của tôi của sự cố này.

var hack = document.createElement("div"); 
hack.style.height = "101%"; 
document.body.appendChild(hack); 
setTimeout(function(){ 
    document.body.removeChild(hack); 
    hack = null; 
}, 0); 
2

Hình như đây là một known bug:

vấn đề cốt lõi là: nếu trang di chuyển theo chương trình (tức là người dùng không gây ra cuộn) thì các phần tử bên trong phần tử sửa lỗi không khả dụng.

Sử dụng định vị tuyệt đối, change the markup hoặc sử dụng một trong số lai workarounds.

+0

Lưu ý rằng ví dụ tôi đăng cụ thể không sử dụng JavaScript để cuộn. Vì vậy, đây hoàn toàn là một vấn đề CSS. – mckamey

+0

Cảm ơn. Tôi đã cập nhật câu trả lời của mình với thông tin mới. –

2

Cài đặt iWebInspector của tôi hiện đang bị hỏng, nhưng sau khi làm rối tung với jsfiddle và iOS sim, có vẻ như linh cảm của bạn là chính xác - mặc dù là vị trí: cố định, trình duyệt cho rằng trang đã cuộn và vít lên nhấp vào mục tiêu.

Có vẻ như đây là vấn đề tương tự như iOS Safari: Anchors within a fixed positioned element only work once, cũng chưa được giải quyết bằng CSS thuần túy. Cũng liên quan: Fixed position navbar only clickable once in Mobile Safari on iOS5.

Tiếp theo, và tôi chắc chắn nó đã được chú ý rồi, không thể cuộn sang bên trái, vì vậy trên iPhone chỉ mục chỉ hiển thị A-M.

+1

Cảm ơn. Có, tôi không bận tâm đến bố cục đáp ứng bên trái, tôi đã cố xóa mọi thứ không liên quan đến lỗi. – mckamey

+0

Vâng, có ý nghĩa. Vui mừng bạn đã tìm thấy một giải pháp khả thi. – egid

6

Trớ trêu thay, sửa lỗi chỉnh sửa ban đầu của tôi (hiện được liên kết trong câu hỏi) hiện đang hoạt động trong ứng dụng thực của tôi. Đặt một biến thể của nó ở đây trong trường hợp là hữu ích cho bất cứ ai khác. Nó có thể được gọi trên bất kỳ phần tử container nào, hoặc nếu không có gì được truyền trong nó, hãy phản ánh toàn bộ tài liệu.

var forceReflow = function(elem){ 
    elem = elem || document.documentElement; 

    // force a reflow by increasing size 1px 
    var width = elem.style.width, 
     px = elem.offsetWidth+1; 

    elem.style.width = px+'px'; 

    setTimeout(function(){ 
     // undo resize, unfortunately forces another reflow 
     elem.style.width = width; 
     elem = null; 
    }, 0); 
}; 

Điều thú vị là không cần tạo/thêm/xóa phần tử, chỉ cần chỉnh sửa vùng chứa.

+0

Bạn có biết cách ngăn không cho hiển thị nội dung bị hỏng trước khi chỉnh lại không? Nó có thể nhìn thấy trong một thời gian rất ngắn ~ 50ms, nhưng đáng chú ý cho người dùng. –

+0

Bạn có thấy nội dung bị hỏng ngay cả khi 'setTimeout' sử dụng giá trị' 0' không? Nếu có, bạn có thể cần phải thực hiện tối ưu hóa chung để cải thiện tốc độ hiển thị của trang. [Hãy thử một số gợi ý ở đây.] (Https://developers.google.com/speed/pagespeed/) Thông thường những gì tôi đã thấy là những người sử dụng sự kiện sẵn sàng jQuery để xây dựng UI của họ. – mckamey

+0

IIRC, thêm một lớp giả vào một phần tử (ví dụ: ''foo' + Date.now()') sẽ gây ra một sự đảo ngược, và bạn không cần phải loại bỏ lớp đó (trừ khi bạn quan tâm đến tidiness). – hayavuk

0

Tôi tin rằng điều này tốt hơn và đạt được hiệu quả tương tự, cho phép các liên kết có thể nhấp được ở chân trang cố định. Bằng cách nào đó, làm ẩn urlbar khiến các liên kết trong chân trang cố định không thể nhấp được cho đến khi bạn cuộn một chút. Tôi cũng đã thấy điều này khi tập trung đầu vào, và tôi đính kèm một trình xử lý sự kiện cho tất cả các sự kiện tập trung để kích hoạt tính năng này. Tôi làm điều này với dojo để đính kèm các sự kiện.

 if(navigator.userAgent.match(/iPhone/i)){ 
     /* The famous iOS can't-click-links until touch fix, I attach onfocus */ 
      query('input,textarea,select', this.domNode).on('focus', function(el){ 
       document.documentElement.style.paddingRight = '1px'; 
       setTimeout(function() { 
       document.documentElement.style.paddingRight = ''; 
       }, 0); 
      }); 
     } 
+1

Tốt hơn cái gì? Đó là giải pháp tương tự như [gốc của tôi] (http: // stackoverflow.com/a/11479118/43217) nhưng có giá trị mã hóa cứng. Những gì cần phải xảy ra là buộc reflow. – mckamey

0

Đây là một biến thể của giải pháp của McKamey. Nó tránh tái tạo hai lần và có thể giúp nhấp nháy (tùy thuộc vào ứng dụng của bạn):

setTimeout(function(){ 
    document.body.style.borderBottom = 
     document.body.style.borderBottom === 'none' ? '1px solid white' : 'none'; 
}, 0); 
+0

Bạn vẫn không cần xóa đường trắng (đặc biệt trên nền không phải màu trắng)? Đó sẽ là lần thứ 2 của bạn. – mckamey

+0

Bạn có thể đặt màu thành trong suốt trên nền không phải màu trắng để tránh hiện tượng lùi lại thứ hai. – csytan