Cú pháp quy định

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

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

<img> nội bộ đó cũng cung cấp cho bạn mẫu dự phòng đáng tin cậy cho những 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 ra phần tử <picture>, thì phần tử này sẽ bị bỏ qua. Sau đó, các phần tử <source> cũng bị loại bỏ, vì trình duyệt sẽ hoàn toàn không nhận ra các em hoặc không có bối cảnh có ý nghĩa cho các em nếu không có cha 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 sẽ hiển thị như mong đợi.

"Chỉ đạo nghệ thuật" hình ảnh 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ướng đến nghệ thuật" hình ảnh thích ứng. srcsetsizes được thiết kế để hoạt động một cách vô hình, hoán đổi liền mạch các nguồn theo yêu cầu của trình duyệt của người dùng. Tuy nhiên, đôi khi 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 tốt 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 đủ với tâm điểm nhỏ ở giữa có thể hoạt động tốt trên khung nhìn lớn:

Hình ảnh chiều rộng của một bông hoa dừa cạn, xung quanh là lá và thân cây đang được một con ong mật ghé thăm.

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

Hình ảnh chiều rộng của một bông hoa màu dừa cạn, được thu nhỏ. Ong mật hầu như không nhìn thấy được.

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

Một cành hoa lá dừa cạn được phóng to.

Kiểu "cắt" đấy có thể đạt được 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 đó, cho dù cuối cùng họ có thể không bao giờ nhìn thấy quảng cáo đó.

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 một truy vấn phương tiện và type, chấp nhận một loại phương tiện (trước đây gọi là "loại MIME"). <source> đầu tiên trong nguồn để phù hợp với ngữ cảnh duyệt web hiện tại của người dùng và nội dung của thuộc tính srcset trên source đó sẽ được dùng để xác định các đề xuất phù hợp cho bối cảnh đó. Trong ví dụ này, source đầu tiên có thuộc tính media phù hợp với kích thước khung nhìn của người dùng sẽ là kích thước đượ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 media hoặc type của chúng hình ảnh sẽ đóng vai trò là "mặc định" nguồn. Nếu bạn đang sử dụng min-width truy vấn phương tiện, bạn sẽ có truy vấn lớn nhất trước tiên, như đã thấy trong mã trước. Khi sử dụng các truy vấn phương tiện max-width, bạn nên đặt nguồn nhỏ nhất lên 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í mà bạn đã chỉ định, thuộc tính srcset trên source sẽ được chuyển đến <img> như được xác định trên chính <img>, nghĩa là bạn có thể dùng sizes để tối ưu hoá hình ảnh dựa trên nghệ thuật nguồn thông tin.

<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 duy nhất, nhưng việc bỏ qua các thuộc tính đó có thể khiến người dùng có trải nghiệm kém hơn đáng kể. Để giải thích cho điều này, một kết quả tương đối gần đây—nhưng được hỗ trợ tốt—thêm vào HTML thông số kỹ thuật cho phép sử dụng thuộc tính heightwidth trên các phần tử <source>. Các định dạng này cũng giúp giảm sự thay đổi về 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>

Cần lưu ý rằng phương hướng nghệ thuật có thể được dùng để đưa ra nhiều quyết định hơn dựa trên kích thước khung nhìn. đa số 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 tốt hơn phù hợp với bảng phối màu được chỉ định bởi sở thích của người dùng:

<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 theo một yêu cầu của phần tử <picture> để chỉ phân phát các định dạng hình ảnh vào các trình duyệt hỗ trợ chúng.

Như bạn đã tìm hiểu trong phần Định dạng và nén hình ảnh, phương thức 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 là dữ liệu hình ảnh.

Trước khi phần tử <picture> ra mắt, cần có những 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 trình duyệt để 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ó nên xóa tệp đó đi và tải dự phòng hay không. Đáp ví dụ phổ biến là tập lệnh ở những dòng sau:

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

Với cách này, yêu cầu đối với image.webp vẫn sẽ được thực hiện trong mọi trình duyệt, nghĩa là quá trình chuyển bị lãng phí đối với các trình duyệt mà không hỗ trợ WebP. Các trình duyệt không thể phân tích cú pháp mã hoá WebP sẽ gửi một sự kiện onerror và hoán đổi giá trị data-fallback vào src. Đó là một giải pháp lãng phí, nhưng một lần nữa, những phương pháp tiếp cận như thế này lại 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 tạo yêu cầu hình ảnh trước khi bất kỳ tập lệnh tùy chỉnh nào có cơ hội chạy hay thậm chí được phân tích cú pháp, vì vậy, chúng tôi không thể giành quyền này quá trình.

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

Trong thuộc tính type, bạn cung cấp Loại nội dung đa phương tiệ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>. Việc này sẽ cung cấp cho trình duyệt tất cả thông tin cần xác định ngay lập tức xem có thể giải mã đề xuất hình ảnh do source đó cung cấp hay không mà không cần thực hiện bất kỳ yêu cầu—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 thuộc tính đó 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>

Tại đây, mọi trình duyệt hỗ trợ phương thức mã hoá WebP đều sẽ nhận ra Loại nội dung đa phương tiện image/webp được chỉ định trong thuộc tính type của phần tử <source>, chọn <source> đó và (vì chúng ta chỉ cung cấp một đề xuất duy nhất trong srcset) nên hướng dẫn bên trong <img> để yêu cầu, chuyển và hiển thị pic.webp. Mọi trình duyệt 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ư đã thực hiện kể từ năm 1992. Tất nhiên, bạn không cần chỉ định phần tử <source> thứ hai có type="image/jpeg" tại đây – bạn có thể giả định hỗ trợ chung cho JPEG.

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

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

Xét về khía cạnh tiêu chuẩn hoá, tất cả các mẫu đánh dấu được thảo luận ở đây đều tăng lên nhiều: việc thay đổi chức năng của một điều gì đó được thiết lập và tập trung vào web như <img> không phải là một việc đơn giản, và loạt vấn đề mà những thay đổi đó nhắm đến mà có thể nói là khá bao quát. Nếu bạn thấy mình có rất nhiều cách để cải thiện những nội dung này mẫu đánh dấu của chúng tôi, bạn hoàn toàn đúng. Ngay từ đầu, những tiêu chuẩn này được dự định là để cung cấp đường cơ sở cho tương lai để xây dựng dựa trên đó.

Tất cả các giải pháp này 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à kịp thời để trình duyệt yêu cầu nguồn hình ảnh – một giới hạn dẫn đến thuộc tính sizes khó sử dụng.

Tuy nhiên, vì những tính năng này đã được giới thiệu trên nền tảng web, nên một phương thức gốc để trì hoãn yêu cầu hình ảnh đã được giới thiệu. Để trì hoãn việc cung cấp bố cục, các phần tử <img> có thuộc tính loading="lazy" thì không được yêu cầu cho đến khi xác định được bố cục của trang 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ể tránh được các yêu cầu không cần thiết. Bởi vì trình duyệt hoàn toàn hiểu bố cục trang tại thời điểm các yêu cầu này được thực hiện, Thuộc tính sizes="auto" được đề xuất để bổ sung cho quy cách HTML để tránh sử dụng 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, phần tử <picture> ở đường chân trời cũng được bổ sung để phù hợp với một số thay đổi đặc biệt thú vị đến cách chúng tôi tạo kiểu bố cục trang. Mặc dù thông tin về khung nhìn là cơ sở hợp lý cho các quyết định về bố cục cấp cao, ngăn chúng ta sử dụng cách tiếp cận hoàn toàn ở cấp thành phần để phát triển – nghĩa là một thành phần có thể được đưa 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 không gian mà chính thành phần đó chiếm giữ. Mối lo ngại này đã dẫn đến đối với việc tạo truy vấn vùng chứa: phương thức tạo kiểu các phần tử dựa trên kích thước của vùng chứa gốc, thay vì chỉ dựa trên 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ế, vào thời điểm viết bài—việc bổ sung các công nghệ trình duyệt hỗ trợ công nghệ này sẽ cung cấp cho phần tử <picture> một có nghĩa là thực hiện cùng một việc: 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.

Điều đó nghe có vẻ hơi mơ hồ, thì cũng có lý do chính đáng: những cuộc thảo luận về tiêu chuẩn web này đang diễn ra nhưng vẫn chưa được ổn định — 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, nhưng vẫn có một số các dịch vụ, công nghệ và khung chương trình để giúp giảm bớt gánh nặng khi viết mã đánh dấu này. Trong học phần tiếp theo, chúng ta sẽ xem cách tích hợp mọi kiến thức đã học 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.