Bố cục giống tạp chí dành cho web với các khu vực và tuỳ chọn loại trừ CSS

Christian Cantrell
Christian Cantrell

Giới thiệu

Web là một nền tảng cực kỳ mạnh mẽ dành cho văn bản, lĩnh vực mà Adobe có rất nhiều kinh nghiệm và chuyên môn. Khi Adobe tìm cách giúp phát triển web, do đó, việc cải tiến các tính năng văn bản của web thậm chí còn dường như là một điểm bắt đầu rõ ràng để chúng tôi bắt đầu. Web thường giả định một cột duy nhất, hướng dọc cho văn bản. Mặc dù bạn có thể truyền văn bản xung quanh đồ hoạ và thậm chí định dạng văn bản thành nhiều cột bằng CSS, nhưng vẫn rất khó để có được bố cục giống như tạp chí trên web. Với Khu vực CSSLoại trừ CSS, Adobe đang dẫn đầu nỗ lực mang sức mạnh của chế độ xuất bản trên máy tính đến các trình duyệt hiện đại. Ví dụ: trong ảnh chụp màn hình bên dưới, tiêu chí Loại trừ CSS sẽ được dùng để truyền văn bản dọc theo đường bao của núi:

Ví dụ về tiêu chí Loại trừ CSS trong thực tế
Ví dụ về tiêu chí Loại trừ CSS trong thực tế

Tài liệu trong ảnh chụp màn hình dưới đây cũng sử dụng tính năng Loại trừ CSS để cho phép văn bản bao bọc hình dạng trong hình ảnh, cũng như Vùng CSS để định dạng văn bản thành cột và quanh dấu trích dẫn:

Ví dụ về các khu vực CSS đang hoạt động
Ví dụ về khu vực có Dịch vụ so sánh giá (CSS) đang hoạt động

Các khu vực của Dịch vụ so sánh giá (CSS)

Trước khi đi vào thông tin chi tiết về Khu vực CSS, tôi muốn tìm hiểu cách bật các khu vực trong Google Chrome. Khi đã bật Khu vực CSS, bạn có thể thử một số mẫu được tham chiếu trong bài viết này và tạo khu vực của riêng mình.

Bật khu vực CSS trong Google Chrome

Kể từ phiên bản 20 của Chrome (chính xác là phiên bản 20.0.1132.57), Khu vực CSS được bật thông qua giao diện chrome://flags. Để bật khu vực CSS, hãy làm theo các bước sau:

  1. Mở một thẻ hoặc cửa sổ mới trong Chrome.
  2. Nhập chrome://flags vào thanh vị trí.
  3. Dùng giá trị tìm trong trang (control/command + f) rồi tìm phần "các tính năng của Nền tảng web thử nghiệm".
  4. Nhấp vào đường liên kết Bật.
  5. Nhấp vào nút Khởi chạy lại ngay ở dưới cùng.

Để biết thêm thông tin về cờ của Chrome, hãy xem bài đăng trên blog của tôi về Tất cả thông tin về cờ của Chrome.

Khi đã chạy lại trình duyệt của mình, bạn có thể bắt đầu thử nghiệm các khu vực CSS.

Tổng quan về các khu vực của Dịch vụ so sánh giá (CSS)

Khu vực CSS cho phép một khối văn bản được đánh dấu có ngữ nghĩa tự động chuyển vào "hộp" (hiện là các phần tử). Sơ đồ dưới đây minh hoạ sự phân tách văn bản (luồng) và hộp (các vùng mà văn bản chuyển vào):

Nội dung chuyển sang các khu vực xác định
Nội dung di chuyển đến các khu vực xác định

Hãy cùng xem một trường hợp sử dụng thực tế về Khu vực CSS. Ngoài việc là nhà phát triển tại Adobe, tôi còn là một nhà văn khoa học viễn tưởng. Tôi thường xuyên xuất bản tác phẩm của mình trực tuyến theo giấy phép Creative Commons và để cho phép tác phẩm hoạt động trên số lượng thiết bị và trình duyệt tối đa, tôi thường sử dụng định dạng cực kỳ đơn giản tương tự như sau:

Ví dụ về dự án di sản do con người chưa định kiểu
Ví dụ về dự án cũ do con người chưa định kiểu

Khi sử dụng CSS Khu vực, tôi đã có thể tạo ra một trải nghiệm thú vị hơn về mặt hình ảnh và chức năng hơn nhiều vì nó dễ điều hướng và thoải mái hơn khi đọc:

Dự án cũ do con người thực hiện cho thấy Khu vực
Dự án cũ do con người thực hiện với các khu vực.

Để minh hoạ, tôi đã thêm khả năng hiển thị các Khu vực CSS trong nguyên mẫu này. Ảnh chụp màn hình dưới đây minh hoạ cách các khu vực được sắp xếp sao cho chúng tạo ấn tượng là các cột bao quanh đồ hoạ và trích dẫn ở giữa:

Dự án cũ do con người thực hiện hiển thị các khu vực
Dự án cũ do con người thực hiện cho thấy các khu vực

Bạn có thể thử nghiệm với nguyên mẫu này (cũng như xem mã nguồn) tại đây. Hãy sử dụng các phím mũi tên để di chuyển và nhấn phím Esc để hiển thị các khu vực. Bạn cũng có thể xem các nguyên mẫu trước đó tại đây.

Tạo một Luồng được đặt tên

CSS cần thiết để có được một khối văn bản truyền qua các khu vực cực kỳ đơn giản. Đoạn mã dưới đây chỉ định flow được đặt tên có tên là "article" cho một div có id "content" và gán flow có tên "article" đó cho bất kỳ phần tử nào có lớp "region". Kết quả là văn bản có bên trong phần tử "content" sẽ tự động chuyển qua bất kỳ phần tử nào có lớp "region".

<!DOCTYPE html>
<html>
<head>
    <style>
    #content {
        { % mixin flow-into: article; % }
    }

    .region {
        { % mixin flow-from: article; % }
        box-sizing: border-box;
        position: absolute;
        width: 200px;
        height: 200px;
        padding: 10px;
    }

    #box-a {
        border: 1px solid red;
        top: 10px;
        left: 10px;
    }

    #box-b {
        border: 1px solid green;
        top: 210px;
        left: 210px;
    }

    #box-c {
        border: 1px solid blue;
        top: 410px;
        left: 410px;
    }
    </style>
</head>
<body>
    <div id="box-a" class="region"></div>
    <div id="box-b" class="region"></div>
    <div id="box-c" class="region"></div>
    <div id="content">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eleifend dapibus felis, a consectetur nisl aliquam at. Aliquam quam augue, molestie a scelerisque nec, accumsan non metus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin cursus euismod nisi, a egestas sem rhoncus eget. Mauris non tortor arcu. Pellentesque in odio at leo volutpat consequat....
    </div>
</body>
</html>

Kết quả sẽ có dạng như sau:

Kết quả của mã ở trên
Kết quả của mã ở trên

Lưu ý rằng văn bản bên trong div "nội dung" không có bất kỳ kiến thức nào về cách trình bày của nó. Nói cách khác, ngôn ngữ này có thể vẫn hoàn toàn nguyên vẹn về mặt ngữ nghĩa ngay cả khi nó truyền qua các khu vực khác nhau. Ngoài ra, vì khu vực chỉ là các phần tử nên chúng được xác định vị trí và định kích thước bằng CSS cũng như mọi phần tử khác và do đó hoàn toàn tương thích với các nguyên tắc thiết kế thích ứng. Việc chỉ định các phần tử như một phần của một luồng được đặt tên chỉ đơn giản có nghĩa là văn bản được chỉ định sẽ tự động chuyển qua các phần tử đó.

Mô hình đối tượng CSS

Mô hình đối tượng CSS hay CSSOM xác định các API JavaScript để hoạt động với CSS. Dưới đây là danh sách các API mới liên quan đến các khu vực CSS:

  • document.webkitGetNamedFlows(): Một hàm trả về tập hợp các luồng được đặt tên có trong tài liệu.
  • document.webkitGetNamedFlows().namedItem("article"): Một hàm trả về tham chiếu đến một flow được đặt tên cụ thể. Đối số tương ứng với tên được chỉ định làm giá trị của các thuộc tính CSS flow-intofrom-from. Để tham chiếu đến luồng được đặt tên được chỉ định trong đoạn mã ở trên, bạn cần chuyển vào chuỗi "bài viết".
  • WebKitNamedFlow: Một đối tượng đại diện của floe được đặt tên với các thuộc tính và hàm sau:
    • firstEmptyRegionIndex: Một giá trị số nguyên trỏ đến chỉ mục của vùng trống đầu tiên liên kết với luồng được đặt tên. Hãy xem getRegions() bên dưới để tìm hiểu cách tải tập hợp các khu vực.
    • name: Một giá trị chuỗi có tên của luồng.
    • overset: Một thuộc tính boolean:
      • false khi nội dung của luồng được đặt tên phù hợp với các khu vực liên kết
      • true khi nội dung không phù hợp và cần có nhiều khu vực hơn để chứa tất cả nội dung.
    • getContent(): Một hàm trả về một tập hợp có tham chiếu đến các nút chuyển vào luồng được đặt tên.
    • getRegions(): Một hàm trả về một tập hợp có tham chiếu đến các vùng lưu giữ nội dung của flow được đặt tên.
    • getRegionsByContentNode(node): Một hàm trả về tham chiếu đến vùng chứa nút đã chỉ định. Điều này đặc biệt hữu ích khi tìm các khu vực chứa những mục như các neo được đặt tên.
  • webkitregionoversetchange sự kiện. Sự kiện này được kích hoạt trên WebkitNamedFlow bất cứ khi nào bố cục của nội dung liên kết thay đổi vì bất kỳ lý do gì (nội dung được thêm hoặc bị xoá, kích thước phông chữ thay đổi, hình dạng của khu vực thay đổi, v.v.) làm cho thuộc tính webkitRegionOverset của một khu vực thay đổi. Sự kiện này rất hữu ích khi theo dõi các thay đổi tương đối về bố cục. Đây là chỉ báo cho biết có điều gì đó quan trọng đã xảy ra và bạn có thể cần chú ý đến bố cục, chẳng hạn như: cần có thêm khu vực, một số khu vực có thể trống, v.v.
  • webkitregionfragmentchange sự kiện. Chưa được triển khai tại thời điểm chỉnh sửa này. Sự kiện này được kích hoạt trên WebkitNamedFlow bất cứ khi nào bố cục của nội dung được liên kết thay đổi vì bất kỳ lý do nào, tương tự như webkitregionoversetchange, nhưng bất kể có thay đổi nào trong thuộc tính webkitRegionOverset. Sự kiện này giúp ích khi bạn theo dõi các thay đổi chi tiết về bố cục mà không ảnh hưởng nhất thiết đến toàn bộ bố cục của quy trình được đặt tên, ví dụ: nội dung di chuyển từ khu vực này sang khu vực khác nhưng nội dung tổng thể vẫn phù hợp với tất cả các khu vực.
  • Element.webkitRegionOverset: Các phần tử trở thành khu vực khi được chỉ định thuộc tính CSS flow-from. Các phần tử này có thuộc tính webkitRegionOverset. Nếu thuộc tính này thuộc một luồng được đặt tên thì thuộc tính này sẽ cho biết liệu nội dung của một luồng có tràn vùng đó hay không. Các giá trị webkitRegionOverset có thể có là:
    • "overflow" (tràn) nếu có nhiều nội dung hơn mức mà khu vực có thể chứa
    • "fit" nếu nội dung dừng trước khi hết vùng
    • "trống" nếu nội dung chưa đạt đến vùng

Một trong những mục đích chính của CSSOM là theo dõi các sự kiện webkitregionoversetchange và tự động thêm hoặc xoá các khu vực để phù hợp với lượng văn bản khác nhau. Ví dụ: nếu số lượng văn bản cần định dạng không thể dự đoán được (có thể do người dùng tạo), nếu cửa sổ trình duyệt thay đổi kích thước hoặc nếu cỡ chữ thay đổi, thì có thể cần phải thêm hoặc xoá các vùng để phù hợp với thay đổi trong luồng. Ngoài ra, nếu muốn tổ chức nội dung của mình thành các trang, bạn sẽ cần có một cơ chế để sửa đổi DOM một cách linh động cũng như các khu vực của bạn.

Đoạn mã JavaScript sau đây minh hoạ việc sử dụng CSSOM để tự động thêm các khu vực khi cần. Xin lưu ý rằng để đơn giản, phương pháp này không xử lý việc xoá các khu vực hoặc xác định kích thước cũng như vị trí của các khu vực, mà chỉ dành cho mục đích minh hoạ.

var flow = document.webkitGetNamedFlows().namedItem("article")
flow.addEventListener("webkitregionoversetchange", onLayoutUpdate);

function onLayoutUpdate(event) {
    var flow = event.target;
    
    // The content does not fit
    if (flow.overset === true) {
    addRegion();
    } else {
    regionLayoutComplete();
    }
}

function addRegion() {
    var region = document.createElement("div");
    region.style = "flow-from: article";
    document.body.appendChild(region);
}

function regionLayoutComplete() {
    // Finish up your layout.
}

Bạn có thể xem các bản minh hoạ khác trên trang mẫu Khu vực của Dịch vụ so sánh giá (CSS).

Mẫu trang CSS

Sử dụng CSSOM có lẽ là cách hiệu quả và linh hoạt nhất để triển khai những nội dung như phân trang và bố cục thích ứng, nhưng Adobe đã và đang làm việc với các công cụ xuất bản văn bản và máy tính đủ lâu để biết rằng các nhà thiết kế và nhà phát triển cũng sẽ muốn có một cách dễ dàng hơn để có được các tính năng phân trang tương đối chung chung. Do đó, chúng tôi đang làm việc với một đề xuất có tên là Mẫu trang CSS cho phép xác định hành vi phân trang hoàn toàn theo cách khai báo.

Hãy cùng xem một trường hợp sử dụng phổ biến cho Mẫu trang CSS. Đoạn mã dưới đây cho thấy việc sử dụng CSS để tạo hai luồng có tên: "article-flow" và "timeline-flow". Ngoài ra, nó xác định một bộ chọn thứ ba được gọi là "các bài viết kết hợp" mà bên trong đó sẽ chứa hai luồng. Việc đưa thuộc tính overflow-style vào bên trong bộ chọn "combined-articles" cho biết rằng nội dung sẽ được tự động phân trang dọc theo trục x hoặc theo chiều ngang:

<style>
    #article {
    { % mixin flow-into: article-flow; % }
    }

    #timeline {
    { % mixin flow-into: timeline-flow; % }
    }

    #combined-articles {
    overflow-style: paged-x;
    }
</style>

Bây giờ, các luồng đã được xác định và hành vi tràn mong muốn đã được chỉ định, chúng ta có thể tạo chính mẫu trang đó:

@template {
    @slot left {
    width: 35%;
    float: left;
    { % mixin flow-from: article-flow; % }
    }

    @slot time {
    width: 25%;
    float: left;
    { % mixin flow-from: timeline-flow; % }
    }

    @slot right {
    width: 35%;
    float: left;
    { % mixin flow-from: article-flow; % }
    }
}

Các mẫu trang được xác định bằng cú pháp "at" mới. Trong đoạn mã trên, chúng ta xác định 3 vùng, mỗi vùng tương ứng với một cột. Văn bản trong "luồng bài viết" sẽ chuyển qua các cột ở bên trái và bên phải, còn văn bản từ "luồng dòng thời gian" sẽ được điền vào cột ở giữa. Kết quả có thể có dạng như sau:

Ví dụ về mẫu trang
Ví dụ về mẫu trang

Xin lưu ý rằng nội dung của bài viết (nội dung ở các cột bên trái và bên phải) là tiếng Anh và dòng thời gian ở giữa là tiếng Đức. Ngoài ra, các trang tài liệu theo chiều ngang mà không cần phải có bất kỳ mã JavaScript nào. Mọi thứ đều được thực hiện hoàn toàn theo cách khai báo trong CSS.

Mẫu trang CSS vẫn là một đề xuất, tuy nhiên chúng tôi có một nguyên mẫu sử dụng "shim" JavaScript (còn gọi là polyfill) để cho phép bạn thử nghiệm với các mẫu này ngay bây giờ.

Để tìm hiểu thêm về Khu vực CSS nói chung, hãy xem trang Khu vực của CSS trên html.adobe.com.

Loại trừ CSS

Để có được bố cục giống như tạp chí, thì việc truyền văn bản qua các khu vực là chưa đủ. Một yếu tố quan trọng của phiên bản dành cho máy tính để bàn chất lượng cao và thú vị là khả năng làm cho văn bản xoay quanh hoặc bên trong các hình ảnh và đồ hoạ không theo quy tắc. Loại trừ CSS sẽ đưa mức chất lượng sản xuất này lên web.

Ảnh chụp màn hình dưới đây là từ một nguyên mẫu Loại trừ CSS và cho thấy văn bản tự động chạy quanh một đường dẫn khớp với đường viền của một khối đá lớn:

Ví dụ về tiêu chí Loại trừ CSS trong thực tế
Ví dụ về tiêu chí Loại trừ CSS trong thực tế

Điều ngược lại được minh hoạ trong ảnh chụp màn hình tiếp theo: văn bản chạy bên trong các đa giác có hình dạng không đều:

Văn bản đổ thành các hình đa giác không đều
Văn bản đổ thành các hình đa giác không đều

Bước đầu tiên để có thể di chuyển văn bản xung quanh hoặc bên trong các hình dạng tuỳ ý là phát triển và tối ưu hoá các thuật toán cần thiết. Adobe hiện đang nghiên cứu các triển khai sẽ được đóng góp trực tiếp vào WebKit. Sau khi được tối ưu hoá, các thuật toán này sẽ trở thành nền tảng để xây dựng phần còn lại của Loại trừ CSS.

Để biết thêm thông tin về Loại trừ CSS, hãy xem trang Loại trừ CSS trên html.adobe.com và để biết chi tiết hơn về công việc của Adobe trong công nghệ cơ bản dành cho Loại trừ CSS, hãy xem bài đăng trên blog của Hans Muller có tiêu đề Horizontal Box: Polygon Intersection for CSS Exclude.

Trạng thái hiện tại của các khu vực CSS và tiêu chí loại trừ CSS

Lần đầu tiên tôi nói chuyện công khai về Khu vực CSS và Loại trừ CSS là tại Nhóm nhà phát triển Adobe tại Google I/O 2011. Lúc đó, tôi trình bày các bản minh hoạ trong trình duyệt tạo nguyên mẫu tuỳ chỉnh của riêng chúng tôi. Tôi rất nhiệt tình tiếp nhận. Tuy nhiên, họ có cảm giác thất vọng khi họ phát hiện ra rằng chưa có tính năng nào mà tôi trình bày trên trình duyệt chính.

Tôi lại tham dự Google I/O năm nay (2012), lần này là người trình bày cùng với đồng nghiệp Vincent HardyAlex Danilo đến từ Google (bạn có thể xem bản trình bày tại đây). Chỉ một năm sau, khoảng 80% đặc tả Khu vực CSS đã được triển khai bằng WebKit và hiện đã có trong phiên bản Google Chrome mới nhất (lưu ý rằng Khu vực CSS hiện phải được bật thông qua chrome://flags). Hỗ trợ sơ bộ cho các Khu vực CSS thậm chí đã có trong Chrome dành cho Android:

Các khu vực trên Chrome dành cho Android
Các khu vực trên Chrome dành cho Android

Ngoài ra, cả Khu vực CSS và Loại trừ CSS đều được triển khai trong bản xem trước của Internet Explorer 10 và hiện đang nằm trong lộ trình triển khai Firefox vào năm 2012 của Mozilla. Phiên bản chính tiếp theo của Safari sẽ hỗ trợ phần lớn thông số kỹ thuật của Khu vực CSS và các bản cập nhật tiếp theo sẽ bao gồm phần còn lại.

Dưới đây là tiến trình chi tiết mà chúng tôi đã đạt được với các khu vực CSS và loại trừ CSS kể từ đề xuất ban đầu của chúng tôi cho W3C vào tháng 4 năm 2011:

Tiến trình loại trừ và khu vực
Tiến trình loại trừ và khu vực

Kết luận

Adobe có nhiều kinh nghiệm về văn bản, phông chữ và hoạt động xuất bản trên máy tính nói chung thông qua các công cụ như InDesign. Mặc dù web đã là một nền tảng rất mạnh mẽ dành cho văn bản, nhưng chúng tôi muốn vận dụng kiến thức và kinh nghiệm của mình để đưa việc trình bày văn bản đi xa hơn nữa. Khu vực CSS và Loại trừ CSS cho phép nội dung duy trì được cấu trúc về mặt ngữ nghĩa, trong khi vẫn hỗ trợ bố cục giống như tạp chí thực sự và cuối cùng là một trang web ấn tượng hơn nhiều.