2012-11-14 29 views
6

Đây không phải là lỗi vì hành vi nhất quán trên FF, Chrome, IE9 và Safari trên Win7.jQuery offset() bị phá vỡ bởi vị trí cơ thể: tương đối kết hợp với phần tử margin

Ứng dụng tôi đang làm việc là bên thứ 3 vào trang lưu trữ, do đó CSS ​​không thay đổi. Tập lệnh cố gắng căn chỉnh div mới với phần tử hiện có.

  • Cơ thể là position: relative
  • Có một H1 ở phía trên cùng của trang
  • Khoản chênh lệch H1 dường như thay đổi nơi 0,0 cơ thể được tính từ - mặc dù nền trên cơ thể mở rộng tất cả các cách để cạnh, và nó offsetTop báo cáo tài sản 0
  • Thiết lập một biên giới trên cơ thể giải quyết vấn đề - có vẻ lạ hành vi nhưng là nhất quán trên các trình duyệt? (Không phải là một giải pháp khả thi)
  • Loại bỏ lề H1 giải quyết vấn đề (không phải là một giải pháp khả thi)

Ví dụ ở đây, JS là nhận xét cho tái tạo từng trường hợp:
http://codepen.io/anon/pen/EGvlb

I don' t nghĩ rằng đây là một lỗi với jQuery - nó có vẻ là xuống đến một mối quan hệ hợp pháp giữa lợi nhuận H1 và yếu tố cơ thể?

$(function(){ 

    /* Setting body to position:relative breaks offset() 
    because H1 margin moves body down */ 
    $(document.body).css({position: "relative"}); 

    /* Strange: putting a border on body fixes things? */ 
    //$(document.body).css({border: "1px solid #000"}); 

    /* Removing H1 margin removes problem */ 
    //$("h1").css({margin: 0}); 

    $("#overlay").css({ 
     left: $("#existing").offset().left, 
     top: $("#existing").offset().top 
    }) 
}); 
+0

Gắn dấu sao này vì tôi vô tình ở lại quá lâu để tìm ra điều này. Cảm ơn. Tôi thực sự nên nhấn bao giờ :) – BoltClock

Trả lời

4

Tôi không nghĩ đây là lỗi với jQuery - dường như nó có mối quan hệ hợp pháp giữa lề H1 và phần tử cơ thể?

Vâng: lề của cơ thể và h1 là collapsing, vì vậy không chỉ h1 bị dịch chuyển theo lề mặc định của nó, mà còn cơ thể. Đây là lý do tại sao bạn đã có thể thực hiện những quan sát:

  • Thiết lập một biên giới trên cơ thể giải quyết vấn đề - dường như hành vi kỳ lạ nhưng là nhất quán trên các trình duyệt? (Không phải là một giải pháp khả thi)
  • Loại bỏ lề H1 giải quyết vấn đề (không phải là một giải pháp khả thi)

Dù sao, bằng cách thiết lập cơ thể để position: relative, bạn đang nói #overlay để hoàn toàn vị trí chính nó với cơ thể của đầu bù đắp như nguồn gốc. Kịch bản của bạn sau đó di chuyển nó tương ứng với độ lệch của #existing. Giá trị của offsetTop của nó có liên quan đến khung nhìn, được tính toán dựa trên vị trí của hộp này ... mà chính nó là tương đối so với h1 vì nó trực tiếp theo sau h1 trong luồng thông thường.

Do lề của các phần tử h1 và thân bị sụp đổ, chúng có cùng tỷ lệ kết xuất.Điều gì xảy ra sau đó là gấp đôi:

  1. #existing được đẩy xuống bởi h1 như anh chị em sau đây của nó trong luồng thông thường. Điều này làm tăng sự bù đắp của nó từ khung nhìn (trong trường hợp kiểm tra CodePen của bạn, nó là phần trên cùng của ngăn xem trước), dẫn đến số lượng offsetTop lớn hơn.

  2. Khi cơ thể được thiết lập để position: relative, #overlay kết thúc lên nhận vị trí với nguồn gốc của nó đặt cho cơ thể, mà bản thân nó cũng đã được đẩy xuống do bị sụp đổ với lề của h1. Điều này làm tăng phần bù đầu của nguồn gốc của nó, điều này sẽ không xảy ra nếu bạn không định vị cơ thể, bởi vì sau đó #overlay sử dụng nguồn gốc của khung nhìn thay thế, không bao giờ di chuyển.

Khoảng cách của #existing từ phía trên cùng của khung nhìn được thêm vào để bù đắp của #overlay từ nguồn gốc của nó, mà là cơ thể, dẫn đến hiệu ứng này.

Tóm lại: do sự sụp đổ lề, trình duyệt kết thúc phải tính đến các thay đổi giảm ở cả h1 và nội dung. Các h1 ảnh hưởng đến #existing và lần lượt của nó offsetTop, trong khi cơ thể ảnh hưởng đến #overlay khi bạn vị trí của nó tương đối. Vì vậy, hiệu ứng chuyển dịch xuất hiện gấp đôi.

Là một workaround nhanh chóng, bạn có thể trừ đi lợi nhuận h1 từ offsets của #existing nhằm mục đích bù đắp #overlay:

$("#overlay").css({ 
     left: $("#existing").offset().left - $("h1").offset().left, 
     top: $("#existing").offset().top - $("h1").offset().top 
    }) 

Updated example

Chú ý rằng việc sử dụng $(document.body) thay vì $("h1") trên sẽ không công việc. Điều này là do sự sụp đổ lề chỉ đơn thuần là hiệu ứng dựng hình, và không thực sự ảnh hưởng đến độ lệch của cơ thể cho đến khi bạn tạo ra biên độ riêng của nó (nói cách khác, lề cơ thể vẫn tính bằng không, vì vậy DOM vẫn không còn khôn ngoan hơn).


Không liên quan trực tiếp đến vấn đề trước mắt, nhưng giá trị giải quyết anyway:

  • Khoản chênh lệch H1 dường như thay đổi nơi 0,0 cơ thể được tính từ - mặc dù nền trên cơ thể mở rộng tất cả các cách để cạnh, và đó là offsetTop báo cáo tài sản 0

Phần đầu tiên và cuối cùng của điểm này có ong n giải quyết ở trên.

Đối với nền nội dung: trong khi nó dường như mở rộng tất cả các cách để cạnh, nền mở rộng này không thực sự thuộc về cơ thể - nó được truyền từ cơ thể đến, và do đó thuộc về, phần tử gốc (html) và chế độ xem. Xem this answer để được giải thích.

Oh và điều này:

Đây không phải là một lỗi vì hành vi này là nhất quán trên FF, Chrome, IE9 và Safari trên Win7.

Làm tôi mỉm cười.Bởi vì một lần, ai đó nói đúng.

+0

Cảm ơn câu trả lời tuyệt vời! Tôi đã đưa ra một giải pháp chung chung hơn, một 'điểm không' div tại 0,0: http://codepen.io/anon/pen/IdhoK. Tôi vẫn không hiểu tại sao việc thêm một đường biên vào cơ thể sẽ loại bỏ nó? – robC

+0

@robC: Bởi vì từ spec, nó nói rằng lợi nhuận chỉ đủ điều kiện để sụp đổ nếu không có đệm, biên giới hoặc giải phóng mặt bằng tách chúng. Bằng cách thêm một đường viền, bạn ngăn không cho các lề bị sụp đổ, vì vậy lề của h1 không được áp dụng cho phần thân. – BoltClock

+0

Wow rằng spec là một số đọc bí truyền, tôi không thể không cảm thấy loại tính năng này là ít hơn rất nhiều hữu ích hơn nó là khó hiểu. Cảm ơn bạn đã giải thích :) – robC

0

Nếu bạn thay đổi vị trí của overlay từ absolute để fixed sau đó nó làm việc tốt. điều đó có nghĩa là giá trị bù đắp là chính xác. Tôi nghĩ rằng đó là một cái gì đó liên quan đến vị trí của overlay yếu tố liên quan đến yếu tố trước đó của nó.

Các vấn đề liên quan