Tìm hiểu sâu về RenderingNG: Phân đoạn khối LayoutNG

Quá trình phân mảnh khối trong LayoutNG hiện đã hoàn tất. Hãy tìm hiểu cách hoạt động và lý do tại sao nó quan trọng trong bài viết này.

Morten Stenshorne
Morten Stenshorne

Tôi là Morten Stenshorne, một kỹ sư bố cục thuộc nhóm kết xuất Blink tại Google. Tôi đã tham gia phát triển công cụ trình duyệt từ đầu những năm 2000 và tôi rất vui, chẳng hạn như giúp kiểm thử acid2 vượt qua được trong công cụ Presto (Opera 12 trở về trước) cũng như thiết kế đảo ngược các trình duyệt khác để sửa bố cục bảng trong Presto. Tôi cũng đã dành nhiều thời gian trong số đó hơn tôi muốn thừa nhận về việc phân đoạn khối và đặc biệt là nhiều cột trong Presto, WebKit và Blink. Trong vài năm qua tại Google, tôi chủ yếu tập trung vào việc thêm tính năng hỗ trợ phân mảnh khối vào LayoutNG. Hãy cùng tôi tìm hiểu sâu hơn về việc triển khai phân mảnh khối, vì đây có thể là lần cuối cùng tôi triển khai việc phân mảnh khối. :)

Phân mảnh khối là gì?

Phân mảnh chặn là quá trình chia một hộp cấp khối CSS (chẳng hạn như một phần hoặc đoạn) thành nhiều mảnh khi nó không vừa với toàn bộ bên trong một vùng chứa mảnh được gọi là fragmentainer. Phân đoạn không phải là một phần tử mà đại diện cho một cột trong bố cục nhiều cột hoặc một trang trong nội dung nghe nhìn được phân trang. Để tình trạng phân mảnh xảy ra, nội dung cần nằm trong ngữ cảnh phân mảnh. Ngữ cảnh phân mảnh thường được thiết lập nhất bằng vùng chứa nhiều cột (nội dung sẽ được chia thành các cột) hoặc khi in (nội dung sẽ được chia thành các trang). Một đoạn dài có nhiều dòng có thể cần được chia thành nhiều mảnh để các dòng đầu tiên được đặt trong mảnh đầu tiên và các dòng còn lại được đặt trong các mảnh tiếp theo.

Một đoạn văn bản được chia thành hai cột.
Trong ví dụ này, một đoạn văn được chia thành hai cột bằng bố cục nhiều cột. Mỗi cột là một mảnh, đại diện cho một mảnh của luồng phân mảnh.

Phân mảnh khối tương tự như một loại phân mảnh phổ biến khác: phân mảnh đường (còn được gọi là "gãy dòng"). Bất kỳ phần tử cùng dòng nào có chứa nhiều từ (bất kỳ nút văn bản, phần tử <a> nào, v.v.) và có thể ngắt dòng đều có thể được chia thành nhiều mảnh. Mỗi mảnh được đặt vào một hộp dòng khác nhau. Hộp dòng là phân mảnh cùng dòng tương đương với trình phân mảnh dành cho cột và trang.

Phân mảnh khối LayoutNG là gì?

LayoutNGBlockFragmentation là một công cụ viết lại công cụ phân mảnh cho LayoutNG và sau nhiều năm làm việc, phần đầu tiên cuối cùng đã được đưa vào Chrome 102 vào đầu năm nay. Khắc phục các vấn đề tồn tại lâu dài mà về cơ bản không thể khắc phục trong công cụ "cũ" của chúng tôi. Về cấu trúc dữ liệu, công cụ này thay thế nhiều cấu trúc dữ liệu trước NG bằng các mảnh NG được biểu thị trực tiếp trong cây mảnh.

Ví dụ: chúng tôi hiện hỗ trợ giá trị 'tránh' cho các thuộc tính CSS 'Break-before' và 'Break-after', để cho phép tác giả tránh những điểm chèn ngay sau tiêu đề. Nhìn chung, trang này sẽ không đẹp nếu mục cuối cùng được đặt trên một trang là tiêu đề, trong khi nội dung của phần đó lại bắt đầu ở trang tiếp theo. Thay vào đó, bạn nên ngắt trước tiêu đề. Xem hình minh hoạ dưới đây.

Ví dụ đầu tiên cho thấy tiêu đề ở cuối trang, ví dụ thứ hai hiển thị tiêu đề ở đầu trang tiếp theo cùng với nội dung liên quan.

Chrome 102 cũng hỗ trợ tính năng tràn phân mảnh để nội dung nguyên khối (được cho là không thể phá vỡ) không bị cắt thành nhiều cột, đồng thời các hiệu ứng tô màu như đổ bóng và biến đổi được áp dụng chính xác.

Quá trình phân mảnh khối trong LayoutNG hiện đã hoàn tất

Tại thời điểm này, chúng tôi đã hoàn tất việc hỗ trợ phân mảnh toàn bộ khối trong LayoutNG. Phân mảnh cốt lõi (vùng chứa khối, bao gồm bố cục đường, độ chính xác đơn và vị trí ngoài luồng) được vận chuyển trong Chrome 102. Phân mảnh linh hoạt và phân mảnh lưới được chuyển trong Chrome 103 và phân mảnh bảng được cung cấp trong Chrome 106. Cuối cùng, bản in được chuyển trong Chrome 108. Phân mảnh khối là tính năng cuối cùng phụ thuộc vào công cụ cũ để thực hiện bố cục. Điều này có nghĩa là kể từ Chrome 108, công cụ cũ sẽ không còn được dùng để thực hiện bố cục nữa.

Ngoài việc bố trí nội dung, cấu trúc dữ liệu LayoutNG cũng hỗ trợ tính năng vẽ và kiểm thử nhấn, nhưng chúng tôi vẫn dựa vào một số cấu trúc dữ liệu cũ cho các API JavaScript đọc thông tin bố cục, chẳng hạn như offsetLeftoffsetTop.

Việc triển khai mọi thứ bằng NG sẽ giúp bạn có thể triển khai và gửi các tính năng mới chỉ triển khai LayoutNG (và không có các công cụ tương ứng cũ), chẳng hạn như truy vấn vùng chứa CSS, định vị neo, MathMLbố cục tuỳ chỉnh (Houdini). Đối với các truy vấn liên quan đến vùng chứa, chúng tôi đã gửi nội dung này trước một chút, kèm theo cảnh báo dành cho các nhà phát triển về việc tính năng in chưa được hỗ trợ.

Chúng tôi đã vận chuyển phần đầu tiên của LayoutNG vào năm 2019, bao gồm bố cục vùng chứa khối thông thường, bố cục cùng dòng, độ chính xác đơn và vị trí ngoài luồng, nhưng không hỗ trợ tính năng linh hoạt, lưới hoặc bảng và hoàn toàn không hỗ trợ phân mảnh khối. Chúng tôi sẽ quay lại sử dụng công cụ bố cục cũ cho tính năng linh hoạt, lưới, bảng và mọi tính năng liên quan đến việc phân mảnh khối. Điều đó đúng ngay cả đối với các thành phần khối, cùng dòng, nổi và ngoài luồng trong nội dung phân mảnh — như bạn có thể thấy, việc nâng cấp một công cụ bố cục phức tạp như vậy tại chỗ là một công việc vô cùng tinh tế.

Ngoài ra, bạn có thể tin hay không, vào giữa năm 2019, phần lớn chức năng cốt lõi của bố cục phân mảnh khối LayoutNG đã được triển khai (đằng sau một lá cờ). Vậy tại sao thời gian giao hàng lại lâu như vậy? Câu trả lời ngắn gọn là: sự phân mảnh phải cùng tồn tại chính xác với nhiều phần cũ của hệ thống, không thể xoá hoặc nâng cấp các phần này cho đến khi tất cả các phần phụ thuộc được nâng cấp. Để có câu trả lời dài, hãy xem thông tin chi tiết sau đây.

Tương tác với công cụ cũ

Cấu trúc dữ liệu cũ vẫn chịu trách nhiệm về các API JavaScript đọc thông tin bố cục, vì vậy, chúng ta cần ghi lại dữ liệu vào công cụ cũ theo cách mà công cụ đó hiểu được. Trong đó bao gồm việc cập nhật chính xác cấu trúc dữ liệu nhiều cột cũ, chẳng hạn như LayoutMultiColumnFlowThread.

Phát hiện và xử lý tính năng dự phòng cho công cụ cũ

Chúng tôi phải quay lại sử dụng công cụ bố cục cũ khi có nội dung bên trong chưa thể xử lý bằng tính năng phân mảnh khối LayoutNG. Tại thời điểm vận chuyển phân mảnh khối LayoutNG cốt lõi (mùa xuân năm 2022), bao gồm cả linh hoạt, lưới, bảng và mọi nội dung được in ra. Điều này đặc biệt khó khăn vì chúng tôi cần phát hiện nhu cầu dự phòng cũ trước khi tạo đối tượng trong cây bố cục. Ví dụ: chúng tôi cần phát hiện trước khi biết có phải có đối tượng cấp trên của vùng chứa nhiều cột hay không và trước khi biết nút DOM nào sẽ trở thành ngữ cảnh định dạng hay không. Đây là vấn đề về trứng và trứng chưa có giải pháp hoàn hảo, chỉ cần hành vi sai trái duy nhất của vấn đề đó là dương tính giả (dự phòng khi thực sự không cần thiết) thì không sao cả. Mọi lỗi trong hành vi bố cục đó đều là lỗi mà Chromium đã có, chứ không phải lỗi mới.

Đi bộ lên cây trước khi sơn

Sơn trước là việc chúng tôi làm sau khi sắp xếp bố cục, nhưng trước khi sơn. Thách thức chính là chúng ta vẫn cần đi bộ trên cây đối tượng bố cục, nhưng giờ chúng ta đã có các mảnh NG – vậy làm cách nào để xử lý vấn đề này? Chúng ta triển khai cả đối tượng bố cục và cây mảnh NG cùng một lúc! Điều này khá phức tạp vì việc ánh xạ giữa hai cây không hề đơn giản. Mặc dù cấu trúc cây đối tượng bố cục gần giống với cấu trúc cây DOM, nhưng cây mảnh là đầu ra của bố cục chứ không phải đầu vào cho bố cục. Ngoài việc phản ánh thực tế tác động của bất kỳ sự phân mảnh nào, bao gồm phân mảnh cùng dòng (mảnh dòng) và phân mảnh khối (mảnh cột hoặc trang), cây phân mảnh cũng có mối quan hệ mẹ con trực tiếp giữa khối chứa và con cháu DOM có mảnh đó là khối chứa chúng. Ví dụ: trong cây mảnh, một mảnh do một phần tử có vị trí tuyệt đối tạo ra là phần tử con trực tiếp của mảnh khối chứa, ngay cả khi có các nút khác trong chuỗi cấp trên giữa thành phần con có vị trí ngoài luồng và khối chứa nó.

Nó thậm chí còn phức tạp hơn khi có một phần tử được đặt ngoài luồng bên trong phân mảnh, vì sau đó các mảnh ngoài luồng trở thành phần tử con trực tiếp của fragmentainer (và không phải là phần tử con của CSS mà cho là khối chứa). Rất tiếc, đây là một vấn đề cần phải giải quyết để cùng tồn tại với công cụ cũ mà không gặp quá nhiều rắc rối. Trong tương lai, chúng ta có thể đơn giản hoá rất nhiều mã này, vì LayoutNG được thiết kế để hỗ trợ linh hoạt tất cả các chế độ bố cục hiện đại.

Các vấn đề với công cụ phân mảnh cũ

Công cụ cũ, được thiết kế trong thời đại trước đây của web, không thực sự có khái niệm phân mảnh, ngay cả khi về mặt kỹ thuật phân mảnh cũng tồn tại vào thời điểm đó (để hỗ trợ hoạt động in). Tính năng hỗ trợ phân mảnh chỉ là một tính năng được cố định ở trên cùng (in) hoặc được trang bị thêm (nhiều cột).

Khi bố trí nội dung có thể phân mảnh, công cụ cũ bố trí mọi thứ thành một dải cao có chiều rộng bằng kích thước cùng dòng của cột hoặc trang và chiều cao cần thiết để chứa nội dung. Dải cao này không được hiển thị cho trang — hãy coi nó như là hiển thị cho một trang ảo mà sau đó được sắp xếp lại để hiển thị cuối cùng. Về mặt lý thuyết, phương pháp này tương tự như in toàn bộ một bài viết trên báo giấy thành một cột, rồi dùng kéo để cắt thành nhiều cột ở bước thứ hai. (Ngày trước, một số tờ báo thực sự sử dụng các kỹ thuật tương tự như thế này!)

Công cụ cũ theo dõi ranh giới cột hoặc trang ảo trong dải ô. Nhờ vậy, tiện ích này có thể đưa nội dung không vượt quá ranh giới vào trang hoặc cột tiếp theo. Ví dụ: nếu chỉ có nửa trên của đường thẳng vừa với những gì mà công cụ cho là phù hợp với trang hiện tại, nó sẽ chèn một "thanh chống phân trang" để đẩy trang xuống vị trí mà công cụ giả định rằng đầu trang tiếp theo. Sau đó, phần lớn công việc phân mảnh thực tế ("cắt bằng kéo và vị trí") sẽ diễn ra sau bố cục trong khi vẽ và cắt, bằng cách cắt lát các trang nội dung hoặc trang cao thành các trang đã được dịch hoặc cắt thành nhiều trang. Điều này đã khiến một vài điều về cơ bản là không thể làm được, chẳng hạn như áp dụng biến đổi và vị trí tương đối sau phân mảnh (đây là yêu cầu của thông số kỹ thuật). Hơn nữa, mặc dù công cụ cũ vẫn có tính năng hỗ trợ phân mảnh bảng, nhưng hệ thống không hỗ trợ phân mảnh linh hoạt hoặc lưới.

Sau đây là hình minh hoạ cách thể hiện bố cục 3 cột trong công cụ cũ, trước khi dùng kéo, vị trí và keo dán (chúng tôi có chiều cao được chỉ định, để chỉ có 4 dòng vừa khít, nhưng có một phần dư thừa ở dưới cùng):

Bản trình bày nội bộ dưới dạng một cột với các thanh phân trang khi nội dung bị ngắt và bản trình bày trên màn hình dưới dạng 3 cột.

Công cụ bố cục cũ không thực sự phân mảnh nội dung trong quá trình bố cục, nên có nhiều thành phần lạ, chẳng hạn như vị trí tương đối và biến đổi áp dụng không chính xác, và bóng đổ bị cắt ở cạnh cột.

Dưới đây là một ví dụ đơn giản với hiệu ứng bóng văn bản:

Công cụ cũ không xử lý tốt vấn đề này:

Bóng văn bản đã bị cắt được đặt vào cột thứ hai.

Bạn có thấy bóng văn bản trên dòng trong cột đầu tiên bị cắt bớt mà được đặt ở đầu cột thứ hai không? Đó là vì công cụ bố cục cũ không hiểu được quá trình phân mảnh!

Mã này sẽ có dạng như sau (và đây là cách hiển thị với NG):

2 cột văn bản có bóng được hiển thị chính xác.

Tiếp theo, hãy làm cho yếu tố phức tạp hơn một chút, với hiệu ứng biến đổi và bóng đổ. Lưu ý rằng trong công cụ cũ, việc cắt xén và hiển thị cột không chính xác. Đó là vì các phép biến đổi được áp dụng theo thông số kỹ thuật dưới dạng hiệu ứng sau bố cục, sau phân mảnh. Với tính năng phân mảnh LayoutNG, cả hai đều hoạt động chính xác. Điều này làm tăng khả năng tương tác với Firefox, vốn có hỗ trợ phân mảnh tốt trong một thời gian với hầu hết các thử nghiệm trong lĩnh vực này cũng được chuyển sang.

Các hộp bị chia nhỏ trên hai cột một cách không chính xác.

Công cụ cũ cũng gặp vấn đề với nội dung nguyên khối cao. Nội dung là nguyên khối nếu không đủ điều kiện để chia thành nhiều mảnh. Các phần tử có tính năng cuộn tràn là một khối nguyên khối, vì người dùng sẽ không hợp lý khi cuộn trong một vùng không phải hình chữ nhật. Các hộp dòng và hình ảnh là các ví dụ khác về nội dung nguyên khối. Ví dụ:

Nếu phần nội dung nguyên khối quá cao nên không vừa với một cột, thì công cụ cũ sẽ cắt phần nội dung đó một cách thô lỗ (dẫn đến hành vi rất "thú vị" khi cố gắng cuộn vùng chứa có thể cuộn):

Thay vì để cột này tràn vào cột đầu tiên (như với tính năng phân mảnh khối LayoutNG):

ALT_TEXT_HERE

Công cụ cũ hỗ trợ các điểm chèn quảng cáo bắt buộc. Ví dụ: <div style="break-before:page;"> sẽ chèn một dấu ngắt trang trước DIV. Tuy nhiên, tính năng này chỉ hỗ trợ hạn chế để tìm các điểm ngắt tối ưu không bắt buộc. Chế độ này hỗ trợ break-inside:avoid cũng như trẻ em mồ côi và góa phụ, nhưng không hỗ trợ việc tránh điểm chèn giữa các khối, nếu bạn yêu cầu qua break-before:avoid chẳng hạn. Hãy xem xét ví dụ sau:

Văn bản được chia thành hai cột.

Ở đây, phần tử #multicol có chỗ cho 5 dòng trong mỗi cột (vì cao 100px và chiều cao dòng là 20px), do đó, tất cả #firstchild có thể nằm vừa trong cột đầu tiên. Tuy nhiên, phiên bản đồng cấp của nó #secondchild có break-before:tránh, nghĩa là nội dung mong muốn không có một khoảng nghỉ nào đó xảy ra giữa chúng. Vì giá trị của widows là 2, nên chúng ta cần đẩy 2 dòng #firstchild sang cột thứ hai để đáp ứng mọi yêu cầu tránh điểm chèn. Chromium là công cụ trình duyệt đầu tiên hỗ trợ đầy đủ sự kết hợp của các tính năng này.

Cách hoạt động của tính năng phân mảnh NG

Công cụ bố cục NG thường bố trí tài liệu bằng cách truyền tải chiều sâu cây hộp CSS trước. Khi tất cả các thành phần con cháu của một nút được bố trí, bố cục của nút đó có thể được hoàn tất bằng cách tạo NGPhysicalFragment và quay lại thuật toán bố cục mẹ. Thuật toán đó sẽ thêm mảnh vào danh sách các mảnh con và sau khi tất cả các mảnh con hoàn tất, sẽ tạo một mảnh cho chính nó chứa tất cả các mảnh con bên trong. Bằng phương pháp này, hệ thống sẽ tạo cây phân đoạn cho toàn bộ tài liệu. Tuy nhiên, đây là sự đơn giản hoá quá mức: ví dụ: các phần tử được định vị ngoài luồng sẽ phải bong bóng từ vị trí chúng tồn tại trong cây DOM đến khối chứa của chúng trước khi có thể bố trí. Để đơn giản, tôi sẽ bỏ qua thông tin nâng cao này.

Cùng với hộp CSS, LayoutNG cung cấp một không gian ràng buộc cho thuật toán bố cục. Việc này cung cấp cho thuật toán các thông tin như không gian có sẵn cho bố cục, liệu ngữ cảnh định dạng mới đã được thiết lập hay chưa và kết quả thu gọn lề trung gian từ nội dung trước đó. Không gian ràng buộc cũng biết kích thước khối được bố trí của mảnh rời và độ lệch khối hiện tại vào đó. Cột này cho biết vị trí ngắt.

Khi liên quan đến quá trình phân mảnh khối, bố cục của các thành phần con cháu phải dừng tại một điểm ngắt. Lý do dẫn đến lỗi bao gồm hết dung lượng trong trang hoặc cột, hoặc một điểm chèn bắt buộc. Sau đó, chúng ta tạo các mảnh cho các nút mà chúng ta đã truy cập và trả về toàn bộ gốc ngữ cảnh phân mảnh (vùng chứa nhiều cột hoặc thư mục gốc của tài liệu trong trường hợp in). Sau đó, ở gốc ngữ cảnh phân mảnh, chúng ta chuẩn bị cho mảnh tạo mảnh mới và đi xuống cây một lần nữa, tiếp tục từ nơi đã dừng lại trước khi ngắt.

Cấu trúc dữ liệu quan trọng dùng để cung cấp phương thức để tiếp tục bố cục sau một điểm ngắt có tên là NGBlockBreakToken. Lớp này chứa tất cả thông tin cần thiết để tiếp tục bố cục chính xác trong mảnh tiếp theo. Một NGBlockBreakToken được liên kết với một nút và nút này tạo thành một cây NGBlockBreakToken để đại diện cho mỗi nút cần được tiếp tục. Một NGBlockBreakToken được đính kèm vào NGPhysicalBoxFragment được tạo cho các nút đột nhập bên trong. Mã thông báo ngắt được truyền đến thành phần mẹ, tạo thành một cây mã thông báo điểm chèn. Nếu chúng ta cần ngắt trước một nút (thay vì bên trong nút đó), thì sẽ không có mảnh nào được tạo, nhưng nút mẹ vẫn cần tạo một mã thông báo ngắt "trước" cho nút đó, để chúng ta có thể bắt đầu bố trí khi đến cùng một vị trí trong cây nút trong mảnh tiếp theo.

Các điểm chèn được chèn khi chúng ta hết không gian mảnh (một điểm chèn không bắt buộc) hoặc khi một điểm ngắt bắt buộc được yêu cầu.

Có các quy tắc trong phần đặc tả về điểm chèn không bắt buộc tối ưu và việc chèn điểm chèn chính xác vào vị trí hết dung lượng không phải lúc nào cũng đúng. Ví dụ: có nhiều thuộc tính CSS như break-before ảnh hưởng đến lựa chọn vị trí chèn. Do đó, trong quá trình bố cục, để triển khai chính xác phần thông số kỹ thuật điểm ngắt không bắt buộc, chúng ta cần theo dõi những điểm ngắt có thể phù hợp. Bản ghi này có nghĩa là chúng ta có thể quay lại và sử dụng điểm ngắt tốt nhất có thể được tìm thấy, nếu hết dung lượng tại điểm mà chúng ta vi phạm yêu cầu tránh ngắt (ví dụ: break-before:avoid hoặc orphans:7). Mỗi điểm ngắt sẽ được cho một điểm số, trong khoảng từ "chỉ làm điều này như phương án cuối cùng" đến "điểm ngắt hoàn hảo", với một số giá trị ở giữa. Nếu điểm số của điểm chèn quảng cáo là "hoàn hảo", điều đó có nghĩa là sẽ không có quy tắc nào vi phạm nếu chúng tôi phá vỡ điểm đó (và nếu chúng tôi đạt được điểm số này chính xác tại thời điểm hết chỗ, thì không cần quay lại để tìm thứ gì khác tốt hơn). Nếu điểm số là "Last-resort", điểm ngắt thậm chí không phải là điểm hợp lệ, nhưng chúng ta vẫn có thể phá vỡ ở đó nếu không tìm thấy kết quả nào tốt hơn, để tránh tình trạng tràn mảnh.

Các điểm ngắt hợp lệ thường chỉ xảy ra giữa các thành phần đồng cấp (hộp dòng hoặc khối) chứ không phải giữa thành phần mẹ và thành phần con đầu tiên của thành phần mẹ đó (điểm ngắt lớp C là một ngoại lệ, nhưng chúng ta không cần thảo luận về điểm ngắt đó ở đây). một điểm ngắt hợp lệ, chẳng hạn như trước một khối đồng cấp có break-before:abort, nhưng điểm ngắt đó nằm ở đâu đó giữa "perfect" và "last-resort" (kết hợp cuối cùng).

Trong quá trình bố cục, chúng tôi theo dõi điểm ngắt tốt nhất tìm thấy cho đến nay trong một cấu trúc có tên là NGEarlyBreak. Điểm ngắt sớm là điểm ngắt có thể xảy ra trước hoặc bên trong một nút khối hoặc trước một dòng (dòng vùng chứa khối hoặc dòng linh hoạt). Chúng ta có thể tạo một chuỗi hoặc đường dẫn của đối tượng NGEarlyBreak, trong trường hợp điểm ngắt tốt nhất nằm ở đâu đó sâu bên trong thứ chúng ta đã đi qua trước đó khi hết dung lượng. Ví dụ:

Trong trường hợp này, chúng ta sẽ hết dung lượng ngay trước #second, nhưng có sự kiện " break-before:avoid" để nhận điểm vị trí chèn quảng cáo là "tránh vi phạm". Tại thời điểm đó, chúng ta có một chuỗi NGEarlyBreak " bên trong #outer > bên trong #middle > bên trong #inner > trước "dòng 3"", với giá trị "hoàn hảo" nên chúng tôi muốn dừng ở đó. Vì vậy, chúng ta cần trả về và chạy lại bố cục từ đầu #outer (và lần này vượt qua NGEarlyBreak mà chúng ta tìm thấy), để có thể ngắt trước "dòng 3" trong #inner. (Chúng ta ngắt trước "dòng 3", để 4 dòng còn lại kết thúc trong mảnh tiếp theo và để tôn trọng widows:4.)

Thuật toán được thiết kế để luôn ngắt tại điểm ngắt tốt nhất có thể (như đã xác định trong spec) bằng cách bỏ các quy tắc theo đúng thứ tự, nếu không phải tất cả các quy tắc đều được đáp ứng. Lưu ý rằng chúng ta chỉ phải bố cục lại tối đa một lần cho mỗi quy trình phân mảnh. Vào thời điểm chúng ta đang truyền bố cục thứ hai, vị trí chèn tốt nhất đã được chuyển đến thuật toán bố cục. Đây là vị trí chèn được phát hiện trong lần truyền bố cục đầu tiên và được cung cấp như một phần của đầu ra bố cục trong vòng đó. Trong lượt bố cục thứ hai, chúng ta không bố trí cho đến khi hết dung lượng — trên thực tế, chúng ta không được phép hết dung lượng (việc này thực sự là một lỗi), vì chúng tôi đã được chuẩn bị một nơi siêu ngọt ngào (ngầu như có sẵn) để chèn một điểm chèn quảng cáo sớm, nhằm tránh vi phạm các quy tắc không cần thiết. Chúng tôi trình bày đến điểm đó và giải lao.

Xin lưu ý rằng đôi khi, chúng ta cần vi phạm một số yêu cầu tránh ngắt nếu điều đó giúp tránh tình trạng tràn mảnh (fragmentainer overflow). Ví dụ:

Ở đây, chúng ta đã hết dung lượng ngay trước #second, nhưng có "break-before:avoid". Cụm từ này được dịch là "tránh vi phạm", giống như ví dụ trước. Chúng ta cũng có một NGEarlyBreak với "những trẻ mồ côi và góa phụ bị vi phạm" (bên trong #first > trước "dòng 2"), vẫn không hoàn hảo nhưng vẫn tốt hơn "tránh vi phạm". Vậy nên chúng ta sẽ ngắt trước "dòng 2", vi phạm yêu cầu về trẻ mồ côi / góa phụ. Quy cách này đề cập đến vấn đề này trong 4.4. Điểm ngắt không bắt buộc, trong đó nó xác định quy tắc vi phạm nào sẽ bị bỏ qua trước tiên nếu chúng ta không có đủ điểm ngắt để tránh tràn mảnh (fragmentainer overflow).

Tóm tắt

Mục tiêu chức năng chính của dự án phân mảnh khối LayoutNG là cung cấp khả năng triển khai hỗ trợ kiến trúc LayoutNG cho mọi thứ mà công cụ cũ hỗ trợ và ít nội dung khác nhất có thể, ngoài các bản sửa lỗi. Ngoại lệ chính ở đây là tính năng hỗ trợ tránh phá vỡ tốt hơn (ví dụ: break-before:avoid), vì đây là một phần cốt lõi của công cụ phân mảnh, vì vậy nó phải nằm trong đó ngay từ đầu, vì việc thêm nó vào sau này sẽ đồng nghĩa với việc viết lại.

Giờ đây, quá trình phân mảnh khối LayoutNG đã hoàn tất, chúng ta có thể bắt đầu bổ sung chức năng mới, chẳng hạn như hỗ trợ kích thước trang hỗn hợp khi in, hộp lề @page khi in, box-decoration-break:clone, v.v. Và cũng như LayoutNG nói chung, chúng tôi dự kiến tỷ lệ lỗi và gánh nặng bảo trì của hệ thống mới sẽ giảm đáng kể theo thời gian.

Cảm ơn bạn đã đọc!

Xác nhận

  • Una Kravets để có "ảnh chụp màn hình thủ công" đẹp mắt.
  • Chris Harrelson để hiệu đính, nhận ý kiến phản hồi và đưa ra đề xuất.
  • Philip Jägenstedt chia sẻ ý kiến phản hồi và đề xuất.
  • Rachel Andrew là người biên tập và hình minh hoạ đầu tiên cho nhiều cột.