Tại sao trình duyệt khớp với bộ chọn CSS từ phải sang trái?


560

Bộ chọn CSS được kết hợp bởi các công cụ trình duyệt từ phải sang trái. Vì vậy, trước tiên họ tìm thấy những đứa trẻ và sau đó kiểm tra cha mẹ của chúng để xem chúng có khớp với phần còn lại của quy tắc không.

  1. Tại sao lại thế này?
  2. Có phải chỉ vì thông số kỹ thuật nói?
  3. Nó có ảnh hưởng đến bố cục cuối cùng nếu nó được đánh giá từ trái sang phải?

Đối với tôi cách đơn giản nhất để làm điều đó là sử dụng các bộ chọn với số lượng phần tử ít nhất. Vì vậy, ID đầu tiên (vì họ chỉ nên trả về 1 phần tử). Sau đó, có thể các lớp hoặc một phần tử có số lượng nút ít nhất - ví dụ: chỉ có thể có một nhịp trên trang, vì vậy hãy truy cập trực tiếp vào nút đó với bất kỳ quy tắc nào tham chiếu một khoảng.

Dưới đây là một số liên kết sao lưu yêu cầu của tôi

  1. http://code.google.com.vn/speed/page-speed/docs/rendering.html
  2. https://developer.mozilla.org/en/Writing_E enough_CSS

Có vẻ như nó được thực hiện theo cách này để tránh phải nhìn vào tất cả con cái của cha mẹ (có thể là nhiều) chứ không phải tất cả cha mẹ của một đứa trẻ phải là một. Ngay cả khi DOM sâu, nó sẽ chỉ nhìn vào một nút trên mỗi cấp chứ không phải nhiều nút trong kết hợp RTL. Là dễ dàng hơn / nhanh hơn để đánh giá các bộ chọn CSS LTR hoặc RTL?


5
3. Không - cho dù bạn đọc nó như thế nào, bộ chọn luôn khớp với cùng một bộ phần tử.
Vidime Vidas

39
Đối với những gì nó có giá trị, một trình duyệt không thể cho rằng ID của bạn là duy nhất. Bạn có thể dán cùng id = "foo" trên DOM của mình và một #foobộ chọn sẽ cần khớp với tất cả các nút đó. jQuery có tùy chọn nói rằng $ ("# foo") sẽ luôn trả về chỉ một phần tử, vì chúng xác định API của riêng chúng bằng các quy tắc riêng. Nhưng các trình duyệt cần triển khai CSS và CSS cho biết phải khớp mọi thứ trong tài liệu với ID đã cho.
Boris Zbarsky

4
@Quentin Trong ID tài liệu "không phù hợp" (với HTML) có thể không phải là duy nhất và trong các tài liệu đó, CSS yêu cầu khớp tất cả các yếu tố với ID đó. Bản thân CSS không đặt các yêu cầu quy phạm về ID là duy nhất; các văn bản bạn trích dẫn là thông tin.
Boris Zbarsky

5
@Boris Zbarsky jQuery làm gì phụ thuộc vào đường dẫn mã trong jQuery. Trong một số trường hợp, jQuery sử dụng API NodeSelector (nguyên gốc querySelectorAll). Trong các trường hợp khác, Sizzle được sử dụng. Sizzle không khớp với nhiều ID nhưng QSA thì có (AYK). Đường dẫn được thực hiện tùy thuộc vào bộ chọn, ngữ cảnh và trình duyệt và phiên bản của nó. API truy vấn của jQuery sử dụng cái mà tôi đã gọi là "Cách tiếp cận gốc, cách tiếp cận kép". Tôi đã viết một bài báo về điều đó, nhưng nó là xuống. Mặc dù bạn có thể tìm thấy ở đây: fifbelow.ca/hosted/dhtmlkove/JavaScript-Query-Engines.html
Garrett

5
Tôi thậm chí không chắc ai ngoài hai bạn có thể hiểu chuyện gì đang xảy ra với cuộc trò chuyện dài này. Chúng tôi có trò chuyện cho các cuộc thảo luận mở rộng này. Bất cứ điều gì bạn thực sự muốn giữ xung quanh nên được đưa vào câu hỏi hoặc câu trả lời, đặc biệt là nếu nó làm rõ thông tin. Stack Overflow không xử lý tốt các cuộc thảo luận trong các bình luận.
George Stocker

Câu trả lời:


824

Hãy nhớ rằng khi trình duyệt thực hiện chọn công cụ khớp, nó có một yếu tố (yếu tố mà nó đang cố xác định kiểu cho) và tất cả các quy tắc của bạn cũng như bộ chọn của chúng và nó cần tìm quy tắc nào phù hợp với yếu tố đó. Điều này khác với điều jQuery thông thường, giả sử, nơi bạn chỉ có một bộ chọn và bạn cần tìm tất cả các phần tử khớp với bộ chọn đó.

Nếu bạn chỉ có một bộ chọn và chỉ có một yếu tố để so sánh với bộ chọn đó, thì từ trái sang phải có ý nghĩa hơn trong một số trường hợp. Nhưng đó không phải là tình huống của trình duyệt. Trình duyệt đang cố gắng kết xuất Gmail hoặc bất cứ điều gì và có một <span>quy tắc mà nó đang cố gắng tạo kiểu và hơn 10.000 quy tắc mà Gmail đưa vào biểu định kiểu của nó (Tôi không tạo ra số đó).

Đặc biệt, trong tình huống trình duyệt đang xem xét hầu hết các công cụ chọn mà nó đang xem xét không khớp với yếu tố được đề cập. Vì vậy, vấn đề trở thành một trong những quyết định rằng bộ chọn không khớp nhanh nhất có thể; nếu điều đó đòi hỏi một chút công việc phụ trong các trường hợp khớp bạn vẫn thắng do tất cả công việc bạn lưu trong các trường hợp không khớp.

Nếu bạn bắt đầu bằng cách chỉ khớp phần bên phải của bộ chọn với phần tử của bạn, thì rất có thể nó sẽ không khớp và bạn đã hoàn thành. Nếu nó phù hợp, bạn phải làm nhiều công việc hơn, nhưng chỉ tỷ lệ thuận với độ sâu cây của bạn, điều này không lớn trong hầu hết các trường hợp.

Mặt khác, nếu bạn bắt đầu bằng cách khớp phần ngoài cùng bên trái của bộ chọn ... bạn khớp với cái gì? Bạn phải bắt đầu đi bộ DOM, tìm kiếm các nút có thể khớp với nó. Chỉ cần khám phá ra rằng không có gì phù hợp với phần ngoài cùng bên trái có thể mất một lúc.

Vì vậy, các trình duyệt khớp từ bên phải; nó đưa ra một điểm khởi đầu rõ ràng và cho phép bạn thoát khỏi hầu hết các công cụ chọn ứng viên rất nhanh. Bạn có thể xem một số dữ liệu tại http://groups.google.com/group/mozilla.dev.tech.layout/browse_thread/thread/b185e455a0b3562a/7db34de545c17665 (mặc dù ký hiệu này gây nhầm lẫn) hai năm trước, đối với 70% các cặp (quy tắc, phần tử), bạn có thể quyết định rằng quy tắc không khớp sau khi chỉ kiểm tra các phần thẻ / lớp / id của bộ chọn ngoài cùng bên phải cho quy tắc. Con số tương ứng cho bộ kiểm tra hiệu năng tải trang của Mozilla là 72%. Vì vậy, thật đáng để thử loại bỏ 2/3 tất cả các quy tắc đó nhanh nhất có thể và sau đó chỉ lo lắng về việc khớp 1/3 còn lại.

Cũng lưu ý rằng có những trình duyệt tối ưu hóa khác đã làm để tránh thậm chí cố gắng khớp các quy tắc chắc chắn không khớp. Ví dụ: nếu bộ chọn ngoài cùng bên phải có id và id đó không khớp với id của phần tử, thì sẽ không có bất kỳ nỗ lực nào khớp với bộ chọn đó với phần tử đó trong Gecko: tập hợp "bộ chọn có ID" đã được thử xuất phát từ việc tra cứu hashtable trên ID của phần tử. Vì vậy, đây là 70% các quy tắc có cơ hội khớp khá tốt mà vẫn không khớp sau khi chỉ xem xét thẻ / lớp / id của bộ chọn ngoài cùng bên phải.


5
Như một phần thưởng nhỏ, sẽ có ý nghĩa hơn khi đọc nó RTL so với LTR ngay cả bằng tiếng Anh. Một ví dụ: stackoverflow.com/questions/3851635/css-combinator-precedence/ trên
BoltClock

6
Lưu ý rằng kết hợp RTL chỉ áp dụng trên các tổ hợp . Nó không đi sâu vào cấp độ chọn đơn giản. Đó là, một trình duyệt có bộ chọn hợp chất ngoài cùng bên phải hoặc chuỗi các bộ chọn đơn giản và cố gắng khớp với nó một cách nguyên tử. Sau đó, nếu có một kết quả khớp, nó sẽ đi theo bộ kết hợp sang trái đến bộ chọn hợp chất tiếp theo và kiểm tra phần tử ở vị trí đó, v.v. Không có bằng chứng cho thấy trình duyệt đọc từng phần của bộ chọn ghép RTL; trong thực tế, đoạn cuối hiển thị chính xác khác (kiểm tra id luôn luôn đến trước).
BoltClock

5
Trên thực tế, vào thời điểm bạn kết hợp các bộ chọn, ít nhất là trong Gecko, tên thẻ và không gian tên xuất hiện trước. Id (cũng như tên thẻ và tên lớp) được xem xét trong bước lọc trước loại bỏ hầu hết các quy tắc mà không thực sự cố gắng khớp với các bộ chọn.
Boris Zbarsky

Điều đó có thể giúp tùy thuộc vào việc tối ưu hóa UA đang làm gì, nhưng nó sẽ không giúp ích cho bước lọc trước trong Gecko mà tôi mô tả ở trên. Có một bước lọc thứ hai hoạt động trên ID và các lớp được sử dụng cho các tổ hợp con cháu chỉ có thể giúp ích.
Boris Zbarsky

@Benito Ciaro: Không đề cập đến vấn đề cụ thể là tốt.
BoltClock

33

Phân tích cú pháp từ phải sang trái, còn được gọi là phân tích từ dưới lên thực sự hiệu quả cho trình duyệt.

Hãy xem xét những điều sau đây:

#menu ul li a { color: #00f; }

Trình duyệt trước tiên kiểm tra a, sau đó li, sau đó ulvà sau đó #menu.

Điều này là do trình duyệt đang quét trang, nó chỉ cần nhìn vào phần tử / nút hiện tại và tất cả các nút / phần tử trước đó mà nó đã quét.

Điều cần lưu ý là trình duyệt bắt đầu xử lý thời điểm nó nhận được một thẻ / nút hoàn chỉnh và không cần phải đợi toàn bộ trang trừ khi tìm thấy tập lệnh, trong trường hợp đó, nó tạm thời dừng và hoàn thành việc thực thi tập lệnh và sau đó đi về phía trước.

Nếu làm theo cách khác, nó sẽ không hiệu quả vì trình duyệt tìm thấy phần tử mà nó đã quét trong lần kiểm tra đầu tiên, nhưng sau đó buộc phải tiếp tục xem qua tài liệu cho tất cả các bộ chọn bổ sung. Đối với điều này, trình duyệt cần phải có toàn bộ html và có thể cần quét toàn bộ trang trước khi bắt đầu vẽ css.

Điều này trái với cách mà hầu hết libs phân tích dom. Ở đó, dom được xây dựng và nó không cần quét toàn bộ trang chỉ cần tìm phần tử đầu tiên và sau đó tiếp tục khớp với các phần tử khác bên trong nó.


20

Nó cho phép xếp tầng từ cụ thể hơn đến ít cụ thể hơn. Nó cũng cho phép ngắn mạch trong ứng dụng. Nếu quy tắc cụ thể hơn áp dụng trong tất cả các khía cạnh mà quy tắc cha mẹ áp dụng, tất cả các quy tắc cha mẹ sẽ bị bỏ qua. Nếu có các bit khác trong cha, chúng được áp dụng.

Nếu bạn đi theo cách khác, bạn sẽ định dạng theo cha mẹ và sau đó ghi đè lên mỗi khi trẻ có điều gì đó khác biệt. Về lâu dài, đây là công việc nhiều hơn nhiều so với việc bỏ qua các mục trong các quy tắc đã được quan tâm.


11
Đó là một vấn đề riêng biệt. Bạn thực hiện xếp tầng bằng cách sắp xếp các quy tắc theo tính cụ thể và sau đó khớp với chúng theo thứ tự cụ thể. Nhưng câu hỏi ở đây là tại sao đối với một quy tắc nhất định, bạn khớp với các bộ chọn của nó theo một cách cụ thể.
Boris Zbarsky
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.