Cú pháp quy định

Phần tử <picture> không tự kết xuất mà đóng vai trò là công cụ quyết định cho phần tử <img> bên trong, cho biết phần tử nào cần kết xuất. <picture> theo sau một tiền lệ đã được thiết lập bởi các phần tử <audio><video>: một phần tử trình bao bọc chứa các phần tử <source> riêng lẻ.

<picture>
   <source …>
   <source …>
    <img …>
</picture …>

<img> bên trong đó cũng cung cấp cho bạn một mẫu dự phòng đáng tin cậy cho các trình duyệt cũ không hỗ trợ hình ảnh thích ứng: nếu trình duyệt của người dùng không nhận dạng được phần tử <picture>, thì phần tử đó sẽ bị bỏ qua. Sau đó, các phần tử <source> cũng bị loại bỏ, vì trình duyệt sẽ không nhận ra các phần tử đó hoặc sẽ không có ngữ cảnh có ý nghĩa cho các phần tử đó khi không có phần tử mẹ <video> hoặc <audio>. Tuy nhiên, mọi trình duyệt đều nhận dạng được phần tử <img> bên trong và nguồn được chỉ định trong src của thành phần này sẽ hiển thị như dự kiến.

Hình ảnh "hướng dẫn nghệ thuật" có <picture>

Việc thay đổi nội dung hoặc tỷ lệ khung hình của một hình ảnh dựa trên kích thước của hình ảnh trên trang thường được gọi là hình ảnh thích ứng "theo hướng nghệ thuật". srcsetsizes được thiết kế để hoạt động rõ ràng, hoán đổi liền mạch các nguồn theo lệnh mà trình duyệt của người dùng yêu cầu. Tuy nhiên, cũng có lúc bạn muốn thay đổi nguồn trên các điểm ngắt để làm nổi bật nội dung hiệu quả hơn, giống như cách bạn điều chỉnh bố cục trang. Ví dụ: hình ảnh tiêu đề có chiều rộng đầy đủ có tiêu điểm nhỏ ở giữa có thể hoạt động tốt trên khung nhìn lớn:

Hình ảnh có chiều rộng tiêu đề là một bông hoa dừa cạn nằm giữa thân và lá đang được một chú ong mật ghé thăm.

Nhưng khi được thu nhỏ cho phù hợp với khung nhìn nhỏ, tiêu điểm chính của hình ảnh có thể bị mất:

Hình ảnh có chiều rộng tiêu đề của một bông hoa màu tím được thu nhỏ. Ong mật ong hầu như không thấy rõ.

Chủ đề của các nguồn hình ảnh này là như nhau, nhưng để tập trung tốt hơn vào chủ thể đó một cách trực quan, bạn nên thay đổi tỷ lệ của nguồn hình ảnh trên các điểm ngắt. Ví dụ: thu phóng chặt chẽ hơn ở tâm hình ảnh và một số chi tiết ở các cạnh bị cắt:

Một bức ảnh cắt phóng to của hoa màu tím.

Kiểu "cắt" này có thể được thực hiện thông qua CSS, nhưng sẽ khiến người dùng yêu cầu tất cả dữ liệu tạo nên hình ảnh đó, mặc dù họ có thể không bao giờ nhìn thấy hình ảnh đó.

Mỗi phần tử source có các thuộc tính xác định điều kiện để lựa chọn source đó: media (chấp nhận truy vấn nội dung nghe nhìn) và type chấp nhận loại nội dung nghe nhìn (trước đây gọi là "loại MIME"). <source> đầu tiên trong thứ tự nguồn để khớp với ngữ cảnh duyệt web hiện tại của người dùng sẽ được chọn và nội dung của thuộc tính srcset trên source đó sẽ được dùng để xác định những đề xuất phù hợp cho ngữ cảnh đó. Trong ví dụ này, source đầu tiên có thuộc tính media khớp với kích thước khung nhìn của người dùng sẽ là thuộc tính được chọn:

<picture>
  <source media="(min-width: 1200px)" srcset="wide-crop.jpg">
  <img src="close-crop.jpg" alt="…">
</picture>

Bạn phải luôn chỉ định img bên trong cuối cùng theo thứ tự — nếu không có phần tử source nào khớp với tiêu chí media hoặc type, thì hình ảnh sẽ đóng vai trò là nguồn "mặc định". Nếu đang sử dụng truy vấn phương tiện min-width, trước tiên, bạn muốn có các nguồn lớn nhất, như đã thấy trong mã trước. Khi sử dụng truy vấn phương tiện max-width, bạn nên đặt nguồn nhỏ nhất trước.

<picture>
   <source media="(max-width: 400px)" srcset="mid-bp.jpg">
   <source media="(max-width: 800px)" srcset="high-bp.jpg">
   <img src="highest-bp.jpg" alt="…">
</picture>

Khi một nguồn được chọn dựa trên các tiêu chí bạn đã chỉ định, thuộc tính srcset trên source sẽ được chuyển đến <img> như thể nó được xác định trên chính <img>, nghĩa là bạn cũng có thể sử dụng sizes để tối ưu hoá các nguồn hình ảnh chỉ dẫn nghệ thuật.

<picture>
   <source media="(min-width: 800px)" srcset="high-bp-1600.jpg 1600w, high-bp-1000.jpg 1000w">
   <source srcset="lower-bp-1200.jpg 1200w, lower-bp-800.jpg 800w">
   <img src="fallback.jpg" alt="…" sizes="calc(100vw - 2em)">
</picture>

Tất nhiên, một hình ảnh có tỷ lệ có thể thay đổi tuỳ thuộc vào phần tử <source> đã chọn sẽ gây ra vấn đề về hiệu suất: <img> chỉ hỗ trợ một thuộc tính widthheight, nhưng việc bỏ qua các thuộc tính đó có thể dẫn đến trải nghiệm người dùng kém hơn đáng kể. Để tính đến vấn đề này, việc bổ sung tương đối mới (nhưng được hỗ trợ tốt) vào quy cách HTML sẽ cho phép sử dụng thuộc tính heightwidth trên các phần tử <source>. Các đối tượng này hoạt động để giảm sự thay đổi bố cục giống như trên <img>, với không gian thích hợp dành riêng trong bố cục cho bất kỳ phần tử <source> nào được chọn.

<picture>
   <source
      media="(min-width: 800px)"
      srcset="high-bp-1600.jpg 1600w, high-bp-1000.jpg 1000w"
      width="1600"
      height="800">
   <img src="fallback.jpg"
      srcset="lower-bp-1200.jpg 1200w, lower-bp-800.jpg 800w"
      sizes="calc(100vw - 2em)"
      width="1200"
      height="750"
      alt="…">
</picture>

Điều quan trọng cần lưu ý là bạn có thể sử dụng hướng nghệ thuật trong nhiều quyết định dựa trên kích thước khung nhìn. Vì phần lớn các trường hợp đó có thể được xử lý hiệu quả hơn bằng srcset/sizes. Ví dụ: chọn nguồn hình ảnh phù hợp hơn với bảng phối màu do người dùng lựa chọn ưu tiên:

<picture>
   <source media="(prefers-color-scheme: dark)" srcset="hero-dark.jpg">
   <img srcset="hero-light.jpg">
</picture>

Thuộc tính type

Thuộc tính type cho phép bạn sử dụng công cụ quyết định một yêu cầu duy nhất của phần tử <picture> để chỉ phân phát các định dạng hình ảnh cho các trình duyệt hỗ trợ các định dạng hình ảnh đó.

Như bạn đã tìm hiểu trong phần Định dạng và nén hình ảnh, chế độ mã hoá mà trình duyệt không thể phân tích cú pháp thậm chí sẽ không thể nhận dạng được dưới dạng dữ liệu hình ảnh.

Trước khi giới thiệu phần tử <picture>, các giải pháp giao diện người dùng khả thi nhất để phân phát các định dạng hình ảnh mới đòi hỏi trình duyệt phải yêu cầu và cố gắng phân tích cú pháp tệp hình ảnh trước khi xác định xem có cần loại bỏ tệp đó và tải bản dự phòng hay không. Ví dụ phổ biến là một tập lệnh dọc theo các dòng sau:

   <img src="image.webp"
    data-fallback="image.jpg"
    onerror="this.src=this.getAttribute('data-fallback'); this.onerror=null;"
    alt="...">

Với mẫu này, yêu cầu về image.webp sẽ vẫn được thực hiện trong mọi trình duyệt, nghĩa là quá trình chuyển bị lãng phí cho những trình duyệt không hỗ trợ WebP. Sau đó, những trình duyệt không thể phân tích cú pháp bộ mã hoá WebP sẽ gửi một sự kiện onerror và hoán đổi giá trị data-fallback thành src. Đó là một giải pháp lãng phí, nhưng một lần nữa, các phương pháp như phương pháp này là lựa chọn duy nhất có sẵn trên giao diện người dùng. Hãy nhớ rằng trình duyệt bắt đầu yêu cầu hình ảnh trước khi bất kỳ tập lệnh tuỳ chỉnh nào có cơ hội chạy (hoặc thậm chí là được phân tích cú pháp), vì vậy, chúng ta không thể giành ưu tiên quy trình này.

Phần tử <picture> được thiết kế rõ ràng để tránh những yêu cầu thừa đó. Mặc dù vẫn không có cách nào để trình duyệt nhận dạng được một định dạng mà không yêu cầu nếu không yêu cầu, nhưng thuộc tính type sẽ cảnh báo trước cho trình duyệt về việc mã hoá nguồn, để trình duyệt có thể quyết định có gửi yêu cầu hay không.

Trong thuộc tính type, bạn cung cấp Loại nội dung nghe nhìn (trước đây là loại MIME) của nguồn hình ảnh được chỉ định trong thuộc tính srcset của mỗi <source>. Điều này cung cấp cho trình duyệt tất cả thông tin cần thiết để xác định ngay lập tức xem liệu đề xuất hình ảnh do source đó cung cấp có thể được giải mã mà không cần yêu cầu bên ngoài nào hay không – nếu không nhận dạng được loại nội dung đa phương tiện, <source> và tất cả các đề xuất của nó sẽ bị bỏ qua và trình duyệt sẽ tiếp tục.

<picture>
 <source type="image/webp" srcset="pic.webp">
 <img src="pic.jpg" alt="...">
</picture>

Ở đây, mọi trình duyệt hỗ trợ mã hoá WebP đều nhận ra Loại nội dung nghe nhìn image/webp được chỉ định trong thuộc tính type của phần tử <source>, hãy chọn <source> đó. Vì chúng tôi chỉ cung cấp một đề xuất trong srcset nên hướng dẫn <img> bên trong yêu cầu, truyền và kết xuất pic.webp. Bất kỳ trình duyệt nào không hỗ trợ WebP sẽ bỏ qua source và không có bất kỳ hướng dẫn nào ngược lại, <img> sẽ hiển thị nội dung của src như đã làm từ năm 1992. Tất nhiên, bạn không cần chỉ định phần tử <source> thứ hai bằng type="image/jpeg" tại đây. Bạn có thể giả định khả năng hỗ trợ chung cho JPEG.

Bất kể ngữ cảnh duyệt web của người dùng như thế nào, tất cả những điều này đều đạt được chỉ bằng một lần chuyển tệp và không lãng phí băng thông trên các nguồn hình ảnh không thể kết xuất được. Chúng tôi cũng đã có tư duy tiến bộ: vì các định dạng tệp mới hơn và hiệu quả hơn sẽ đi kèm với Loại nội dung nghe nhìn của riêng chúng và chúng tôi sẽ có thể tận dụng những Loại nội dung này nhờ vào picture mà không có JavaScript, không có phần phụ thuộc phía máy chủ và tất cả tốc độ của <img>.

Tương lai của hình ảnh thích ứng

Tất cả các mẫu đánh dấu được thảo luận ở đây đều đạt mức độ tiêu chuẩn hoá lớn: việc thay đổi chức năng của một thứ gì đó đã được thiết lập và tập trung trên web vì <img> không phải là công việc đơn giản và ít nhất là bộ vấn đề mà những thay đổi đó muốn giải quyết. Nếu bạn cho rằng những mẫu đánh dấu này có nhiều điểm cần cải thiện, thì bạn hoàn toàn đúng. Ngay từ đầu, các tiêu chuẩn này là nhằm cung cấp cơ sở cho các công nghệ trong tương lai.

Tất cả các giải pháp này đều nhất thiết phải phụ thuộc vào mã đánh dấu, để được đưa vào tải trọng ban đầu từ máy chủ và đến kịp thời để trình duyệt yêu cầu nguồn hình ảnh – một hạn chế dẫn đến thuộc tính sizes khó sử dụng.

Tuy nhiên, kể từ khi các tính năng này được đưa vào nền tảng web, phương pháp gốc để trì hoãn yêu cầu hình ảnh đã được giới thiệu. Các phần tử <img> có thuộc tính loading="lazy" không được yêu cầu cho đến khi đã biết bố cục của trang, để trì hoãn các yêu cầu hình ảnh bên ngoài khung nhìn ban đầu của người dùng cho đến sau này trong quá trình hiển thị trang. Điều này có thể giúp tránh các yêu cầu không cần thiết. Vì trình duyệt hiểu rõ bố cục trang tại thời điểm đưa ra những yêu cầu này, nên chúng tôi đã đề xuất thuộc tính sizes="auto" để bổ sung cho thông số kỹ thuật HTML để tránh nhồi nhét các thuộc tính sizes được viết thủ công trong những trường hợp này.

Ngoài ra, chúng tôi cũng sẽ bổ sung các phần tử <picture> sắp tới để phù hợp với một số thay đổi đặc biệt thú vị về cách chúng tôi tạo kiểu cho bố cục trang. Mặc dù thông tin khung nhìn là cơ sở hợp lý để đưa ra quyết định về bố cục ở cấp cao, nhưng thông tin đó ngăn chúng tôi áp dụng phương pháp phát triển ở cấp độ thành phần đầy đủ, nghĩa là một thành phần có thể được thả vào bất kỳ phần nào của bố cục trang, với các kiểu phản hồi với không gian mà chính thành phần đó chiếm giữ. Mối lo ngại này đã dẫn đến việc tạo ra truy vấn vùng chứa: một phương thức định kiểu cho các phần tử dựa trên kích thước của vùng chứa gốc, thay vì chỉ riêng khung nhìn.

Mặc dù cú pháp truy vấn vùng chứa chỉ mới ổn định và hỗ trợ trình duyệt rất hạn chế tại thời điểm viết bài, nhưng việc bổ sung các công nghệ trình duyệt cho phép nó sẽ cung cấp phần tử <picture> có nghĩa là thực hiện tương tự: một thuộc tính container tiềm năng cho phép tiêu chí lựa chọn <source> dựa trên không gian mà <img> của phần tử <picture> chiếm, thay vì dựa trên kích thước của khung nhìn.

Nghe có vẻ hơi mơ hồ, thì có lý do chính đáng: các cuộc thảo luận về tiêu chuẩn web này đang diễn ra nhưng chưa được giải quyết — bạn chưa thể sử dụng chúng.

Mặc dù mã đánh dấu hình ảnh thích ứng hứa hẹn sẽ trở nên dễ sử dụng hơn theo thời gian, giống như mọi công nghệ web khác, nhưng vẫn có một số dịch vụ, công nghệ và khung hỗ trợ việc viết mã đánh dấu này theo cách thủ công. Trong học phần tiếp theo, chúng ta sẽ xem xét cách tích hợp mọi kiến thức đã tìm hiểu về các định dạng hình ảnh, tính năng nén và hình ảnh thích ứng vào một quy trình phát triển hiện đại.