Một trong những đặc điểm của bối cảnh thiết bị phức tạp hiện nay là có mật độ pixel màn hình rất đa dạng. Một số thiết bị có màn hình có độ phân giải rất cao, trong khi một số thiết bị khác lại bị tụt lại phía sau. Nhà phát triển ứng dụng cần hỗ trợ một loạt mật độ pixel, điều này có thể khá khó khăn. Trên web dành cho thiết bị di động, các thách thức được kết hợp bởi một số yếu tố:
- Nhiều loại thiết bị với nhiều kiểu dáng.
- Băng thông mạng và thời lượng pin bị hạn chế.
Về hình ảnh, mục tiêu của nhà phát triển ứng dụng web là phân phát hình ảnh có chất lượng tốt nhất một cách hiệu quả nhất có thể. Bài viết này sẽ đề cập đến một số kỹ thuật hữu ích để thực hiện việc này ngay hôm nay và trong tương lai gần.
Tránh sử dụng hình ảnh nếu có thể
Trước khi mở hộp Pandora này, hãy nhớ rằng web có nhiều công nghệ mạnh mẽ, phần lớn độc lập với độ phân giải và DPI. Cụ thể, văn bản, SVG và phần lớn CSS sẽ "chỉ hoạt động" nhờ tính năng tự động điều chỉnh tỷ lệ pixel của web (thông qua devicePixelRatio).
Tuy nhiên, không phải lúc nào bạn cũng có thể tránh sử dụng hình ảnh đường quét. Ví dụ: bạn có thể được cung cấp các thành phần khá khó để sao chép trong SVG/CSS thuần tuý hoặc bạn đang xử lý một bức ảnh. Mặc dù bạn có thể tự động chuyển đổi hình ảnh thành SVG, nhưng việc vectơ hoá ảnh chụp lại không có ý nghĩa vì các phiên bản được tăng tỷ lệ thường không đẹp.
Thông tin khái quát
Lịch sử rất ngắn về mật độ điểm ảnh
Trong những ngày đầu, màn hình máy tính có mật độ điểm ảnh là 72 hoặc 96dpi (điểm trên mỗi inch).
Màn hình dần cải thiện mật độ điểm ảnh, chủ yếu là do trường hợp sử dụng thiết bị di động, trong đó người dùng thường cầm điện thoại gần mặt hơn, giúp các điểm ảnh dễ nhìn thấy hơn. Đến năm 2008, điện thoại 150dpi trở thành tiêu chuẩn mới. Xu hướng tăng mật độ điểm ảnh trên màn hình vẫn tiếp tục và điện thoại mới ngày nay có màn hình 300dpi (Apple đặt tên là "Retina").
Tất nhiên, mục tiêu tối thượng là một màn hình mà các pixel hoàn toàn không nhìn thấy được. Đối với kiểu dáng điện thoại, màn hình Retina/HiDPI thế hệ hiện tại có thể gần đạt được lý tưởng đó. Tuy nhiên, các loại phần cứng và thiết bị đeo mới như Project Glass có thể sẽ tiếp tục tăng mật độ điểm ảnh.
Trong thực tế, hình ảnh có mật độ điểm ảnh thấp sẽ trông giống như trên màn hình cũ, nhưng so với hình ảnh sắc nét có mật độ điểm ảnh cao mà người dùng thường thấy, hình ảnh có mật độ điểm ảnh thấp sẽ trông chói lóa và bị vỡ. Sau đây là bản mô phỏng sơ bộ về hình ảnh 1x sẽ trông như thế nào trên màn hình 2x. Ngược lại, hình ảnh 2x trông khá ổn.


Pixel trên web
Khi web được thiết kế, 99% màn hình có độ phân giải 96dpi (hoặc giả vờ là) và có rất ít quy định về sự khác biệt về mặt này. Do sự khác biệt lớn về kích thước và mật độ màn hình, chúng tôi cần một cách thức chuẩn để làm cho hình ảnh trông đẹp trên nhiều mật độ và kích thước màn hình.
Gần đây, quy cách HTML đã giải quyết vấn đề này bằng cách xác định một pixel tham chiếu mà nhà sản xuất sử dụng để xác định kích thước của pixel CSS.
Bằng cách sử dụng pixel tham chiếu, nhà sản xuất có thể xác định kích thước của pixel thực tế của thiết bị so với pixel chuẩn hoặc pixel lý tưởng. Tỷ lệ này được gọi là tỷ lệ pixel của thiết bị.
Tính tỷ lệ pixel của thiết bị
Giả sử một điện thoại thông minh có màn hình với kích thước pixel thực là 180 pixel trên mỗi inch (ppi). Việc tính tỷ lệ pixel của thiết bị sẽ trải qua 3 bước:
So sánh khoảng cách thực tế mà thiết bị được giữ với khoảng cách cho pixel tham chiếu.
Theo thông số kỹ thuật, chúng ta biết rằng ở kích thước 28 inch, kích thước lý tưởng là 96 pixel/inch. Tuy nhiên, vì là điện thoại thông minh nên mọi người cầm thiết bị này gần mặt hơn so với khi cầm máy tính xách tay. Hãy ước tính khoảng cách đó là 18 inch.
Nhân tỷ lệ khoảng cách với mật độ tiêu chuẩn (96ppi) để có được mật độ pixel lý tưởng cho khoảng cách đã cho.
idealPixelDensity = (28/18) * 96 = 150 pixel/inch (xấp xỉ)
Lấy tỷ lệ mật độ pixel thực tế với mật độ pixel lý tưởng để có được tỷ lệ pixel của thiết bị.
devicePixelRatio
= 180/150 = 1,2

Vì vậy, giờ đây, khi trình duyệt cần biết cách đổi kích thước hình ảnh cho vừa với màn hình theo độ phân giải lý tưởng hoặc tiêu chuẩn, trình duyệt sẽ tham chiếu đến tỷ lệ pixel của thiết bị là 1,2 – tức là đối với mỗi pixel lý tưởng, thiết bị này có 1,2 pixel thực. Công thức để chuyển đổi giữa pixel lý tưởng (do thông số kỹ thuật web xác định) và pixel thực (các dấu chấm trên màn hình thiết bị) như sau:
physicalPixels = window.devicePixelRatio * idealPixels
Trước đây, các nhà cung cấp thiết bị có xu hướng làm tròn devicePixelRatios
(DPR). iPhone và iPad của Apple báo cáo DPR là 1 và các thiết bị tương đương với màn hình Retina báo cáo 2. Quy cách CSS đề xuất rằng
đơn vị pixel đề cập đến số nguyên của các pixel thiết bị gần nhất với pixel tham chiếu.
Một lý do khiến tỷ lệ hình tròn có thể tốt hơn là vì tỷ lệ này có thể dẫn đến ít hiệu ứng phụ pixel hơn.
Tuy nhiên, thực tế về chế độ ngang của thiết bị lại đa dạng hơn nhiều và điện thoại Android thường có DPR là 1, 5. Máy tính bảng Nexus 7 có DPR là ~1,33, được tính theo cách tương tự như trên. Trong tương lai, chúng tôi dự kiến sẽ có nhiều thiết bị hơn có DPR biến đổi. Do đó, bạn không bao giờ được giả định rằng ứng dụng khách sẽ có DPR dạng số nguyên.
Tổng quan về các kỹ thuật hình ảnh HiDPI
Có nhiều kỹ thuật để giải quyết vấn đề hiển thị hình ảnh chất lượng tốt nhất nhanh nhất có thể, về cơ bản thuộc hai loại:
- Tối ưu hoá hình ảnh đơn lẻ và
- Tối ưu hoá lựa chọn giữa nhiều hình ảnh.
Phương pháp sử dụng một hình ảnh: sử dụng một hình ảnh nhưng làm điều gì đó thông minh với hình ảnh đó. Những phương pháp này có nhược điểm là bạn không thể tránh khỏi việc hy sinh hiệu suất, vì bạn sẽ tải hình ảnh HiDPI xuống ngay cả trên các thiết bị cũ có DPI thấp hơn. Sau đây là một số phương pháp cho trường hợp hình ảnh đơn:
- Hình ảnh HiDPI bị nén nhiều
- Định dạng hình ảnh cực kỳ tuyệt vời
- Định dạng hình ảnh tăng tiến
Nhiều phương pháp hình ảnh: sử dụng nhiều hình ảnh, nhưng hãy làm một cách thông minh để chọn hình ảnh cần tải. Các phương pháp này có chi phí cố hữu để nhà phát triển tạo nhiều phiên bản của cùng một thành phần, sau đó tìm ra chiến lược quyết định. Sau đây là các tùy chọn:
- JavaScript
- Phân phối phía máy chủ
- Truy vấn nội dung đa phương tiện CSS
- Các tính năng tích hợp sẵn của trình duyệt (
image-set()
,<img srcset>
)
Hình ảnh HiDPI bị nén nhiều
Hình ảnh đã chiếm tới 60% băng thông dùng để tải một trang web trung bình xuống. Bằng cách phân phát hình ảnh HiDPI cho tất cả ứng dụng, chúng tôi sẽ tăng số lượng này. Nó sẽ lớn hơn bao nhiêu?
Tôi đã chạy một số thử nghiệm tạo các mảnh hình ảnh 1x và 2x với chất lượng JPEG ở mức 90, 50 và 20. Dưới đây là tập lệnh shell mà tôi đã sử dụng (sử dụng ImageMagick) để tạo các hình ảnh này:



Từ mẫu nhỏ, không khoa học này, có vẻ như việc nén hình ảnh lớn mang lại sự đánh đổi tốt về chất lượng so với kích thước. Theo tôi, hình ảnh nén 2x thực sự trông đẹp hơn hình ảnh 1x không nén.
Tất nhiên, việc phân phát hình ảnh chất lượng thấp, nén nhiều lần cho thiết bị 2x sẽ kém hơn so với việc phân phát hình ảnh chất lượng cao hơn và phương pháp trên sẽ bị phạt về chất lượng hình ảnh. Nếu so sánh chất lượng: 90 ảnh với chất lượng: 20 ảnh, bạn sẽ thấy độ sắc nét giảm và độ hạt tăng lên. Bạn có thể không chấp nhận những cấu phần phần mềm này trong trường hợp hình ảnh chất lượng cao là yếu tố chính (ví dụ: ứng dụng trình xem ảnh) hoặc đối với các nhà phát triển ứng dụng không muốn đánh đổi.
Bản so sánh ở trên được thực hiện hoàn toàn bằng các tệp JPEG nén. Xin lưu ý rằng có nhiều yếu tố đánh đổi giữa các định dạng hình ảnh được triển khai rộng rãi (JPEG, PNG, GIF), điều này dẫn đến…
Định dạng hình ảnh hoàn toàn tuyệt vời
WebP là một định dạng hình ảnh hấp dẫn, nén rất tốt mà vẫn giữ được độ trung thực cao của hình ảnh. Tất nhiên, tính năng này chưa được triển khai ở mọi nơi!
Một cách là kiểm tra khả năng hỗ trợ WebP thông qua JavaScript. Bạn tải hình ảnh 1px thông qua data-uri, đợi sự kiện đã tải hoặc lỗi được kích hoạt, sau đó xác minh rằng kích thước là chính xác. Modernizr đi kèm với một tập lệnh phát hiện tính năng như vậy, có sẵn thông qua Modernizr.webp
.
Tuy nhiên, cách tốt hơn để thực hiện việc này là trực tiếp trong CSS bằng cách sử dụng hàm image(). Vì vậy, nếu có hình ảnh WebP và dự phòng JPEG, bạn có thể viết như sau:
#pic {
background: image("foo.webp", "foo.jpg");
}
Có một vài vấn đề với phương pháp này. Thứ nhất, image()
không được triển khai rộng rãi. Thứ hai, mặc dù việc nén WebP vượt trội so với JPEG, nhưng vẫn là một điểm cải tiến tương đối – nhỏ hơn khoảng 30% dựa trên thư viện WebP này. Do đó, chỉ WebP là không đủ để giải quyết vấn đề DPI cao.
Định dạng hình ảnh tăng tiến
Các định dạng hình ảnh tăng tiến như JPEG 2000, JPEG tăng tiến, PNG tăng tiến và GIF có lợi ích (đôi khi gây tranh cãi) là cho phép xem hình ảnh trước khi tải xong. Các lớp này có thể gây ra một số hao tổn về kích thước, mặc dù có bằng chứng mâu thuẫn về điều này. Jeff Atwood cho biết rằng chế độ tăng dần "tăng khoảng 20% kích thước của hình ảnh PNG và khoảng 10% kích thước của hình ảnh JPEG và GIF". Tuy nhiên, Stoyan Stefanov cho biết rằng đối với các tệp lớn, chế độ tăng tiến sẽ hiệu quả hơn (trong hầu hết các trường hợp).
Thoạt nhìn, hình ảnh tăng tiến có vẻ rất hứa hẹn trong bối cảnh phân phát hình ảnh chất lượng cao nhất nhanh nhất có thể. Ý tưởng là trình duyệt có thể ngừng tải xuống và giải mã hình ảnh sau khi biết rằng dữ liệu bổ sung sẽ không làm tăng chất lượng hình ảnh (tức là tất cả các điểm cải thiện độ trung thực đều là điểm ảnh phụ).
Mặc dù dễ dàng chấm dứt kết nối, nhưng việc khởi động lại thường tốn kém. Đối với một trang web có nhiều hình ảnh, phương pháp hiệu quả nhất là duy trì một kết nối HTTP, sử dụng lại kết nối đó càng lâu càng tốt. Nếu kết nối bị chấm dứt sớm vì một hình ảnh đã được tải xuống đủ, thì trình duyệt cần tạo một kết nối mới. Điều này có thể thực sự chậm trong môi trường có độ trễ thấp.
Một giải pháp cho vấn đề này là sử dụng yêu cầu Phạm vi HTTP. Yêu cầu này cho phép trình duyệt chỉ định một phạm vi byte để tìm nạp. Trình duyệt thông minh có thể tạo một yêu cầu HEAD để lấy tiêu đề, xử lý tiêu đề đó, quyết định lượng hình ảnh thực sự cần thiết, sau đó tìm nạp. Rất tiếc, Phạm vi HTTP được hỗ trợ kém trong máy chủ web, khiến phương pháp này không thực tế.
Cuối cùng, một hạn chế rõ ràng của phương pháp này là bạn không thể chọn hình ảnh nào sẽ tải, mà chỉ có thể thay đổi độ trung thực của cùng một hình ảnh. Do đó, trường hợp sử dụng "hướng dẫn nghệ thuật" không được đề cập đến.
Sử dụng JavaScript để quyết định hình ảnh cần tải
Phương pháp đầu tiên và rõ ràng nhất để quyết định hình ảnh cần tải là sử dụng JavaScript trong ứng dụng. Phương pháp này cho phép bạn tìm hiểu mọi thứ về tác nhân người dùng và làm điều đúng đắn. Bạn có thể xác định tỷ lệ pixel của thiết bị thông qua window.devicePixelRatio
, lấy chiều rộng và chiều cao màn hình, thậm chí có thể thực hiện một số hoạt động đánh hơi kết nối mạng thông qua navigator.connection hoặc đưa ra yêu cầu giả mạo, như thư viện foresight.js. Sau khi thu thập tất cả thông tin này, bạn có thể quyết định hình ảnh nào sẽ tải.
Có khoảng một triệu thư viện JavaScript làm những việc tương tự như trên, nhưng đáng tiếc là không có thư viện nào đặc biệt nổi bật.
Một hạn chế lớn của phương pháp này là việc sử dụng JavaScript có nghĩa là bạn sẽ trì hoãn việc tải hình ảnh cho đến khi trình phân tích cú pháp tìm trước hoàn tất. Về cơ bản, điều này có nghĩa là hình ảnh thậm chí sẽ không bắt đầu tải xuống cho đến khi sự kiện pageload
kích hoạt. Tìm hiểu thêm về vấn đề này trong
bài viết của Jason Grigsby.
Quyết định hình ảnh cần tải trên máy chủ
Bạn có thể trì hoãn quyết định cho phía máy chủ bằng cách viết trình xử lý yêu cầu tuỳ chỉnh cho từng hình ảnh mà bạn phân phát. Trình xử lý như vậy sẽ kiểm tra khả năng hỗ trợ Retina dựa trên User-Agent (phần thông tin duy nhất được chuyển tiếp đến máy chủ). Sau đó, dựa trên việc logic phía máy chủ có muốn phân phát tài sản HiDPI hay không, bạn sẽ tải tài sản thích hợp (được đặt tên theo một số quy ước đã biết).
Rất tiếc, Trình đại diện người dùng không nhất thiết phải cung cấp đủ thông tin để quyết định xem thiết bị có nên nhận hình ảnh chất lượng cao hay thấp hay không. Ngoài ra, không cần phải nói rằng mọi thứ liên quan đến Agent-User đều là hành vi xâm nhập và bạn nên tránh nếu có thể.
Sử dụng truy vấn nội dung đa phương tiện CSS
Là một truy vấn khai báo, truy vấn nội dung nghe nhìn CSS cho phép bạn nêu rõ ý định của mình và cho phép trình duyệt thay mặt bạn thực hiện hành động phù hợp. Ngoài cách sử dụng phổ biến nhất của truy vấn nội dung đa phương tiện – so khớp kích thước thiết bị – bạn cũng có thể so khớp devicePixelRatio
. Truy vấn nội dung đa phương tiện được liên kết là
device-pixel-ratio và có các biến thể tối thiểu và tối đa được liên kết, như bạn
có thể mong đợi. Nếu muốn tải hình ảnh có DPI cao và tỷ lệ pixel của thiết bị vượt quá ngưỡng, bạn có thể làm như sau:
#my-image { background: (low.png); }
@media only screen and (min-device-pixel-ratio: 1.5) {
#my-image { background: (high.png); }
}
Việc này sẽ phức tạp hơn một chút khi tất cả tiền tố của nhà cung cấp được kết hợp, đặc biệt là do sự khác biệt lớn về vị trí của tiền tố "min" và "max":
@media only screen and (min--moz-device-pixel-ratio: 1.5),
(-o-min-device-pixel-ratio: 3/2),
(-webkit-min-device-pixel-ratio: 1.5),
(min-device-pixel-ratio: 1.5) {
#my-image {
background:url(high.png);
}
}
Với phương pháp này, bạn sẽ lấy lại được các lợi ích của tính năng phân tích cú pháp xem trước mà giải pháp JS đã mất. Bạn cũng có thể linh hoạt chọn điểm ngắt thích ứng (ví dụ: bạn có thể có hình ảnh DPI thấp, trung bình và cao), điều này không có trong phương pháp phía máy chủ.
Rất tiếc, cách này vẫn còn hơi khó sử dụng và dẫn đến CSS trông lạ mắt (hoặc yêu cầu xử lý trước). Ngoài ra, phương pháp này chỉ dành cho các thuộc tính CSS, vì vậy, không có cách nào để đặt <img src>
và tất cả hình ảnh của bạn đều phải là các phần tử có nền. Cuối cùng, bằng cách chỉ dựa vào tỷ lệ pixel của thiết bị, bạn có thể gặp phải trường hợp điện thoại thông minh có DPI cao tải một thành phần hình ảnh lớn gấp 2 lần trong khi đang ở chế độ kết nối EDGE. Đây không phải là trải nghiệm người dùng tốt nhất.
Sử dụng các tính năng mới của trình duyệt
Gần đây, có rất nhiều cuộc thảo luận về việc hỗ trợ nền tảng web cho vấn đề hình ảnh có DPI cao. Gần đây, Apple đã tham gia vào không gian này, đưa hàm CSS image-set() vào WebKit. Do đó, cả Safari và Chrome đều hỗ trợ tính năng này. Vì là một hàm CSS, nên image-set()
không giải quyết được vấn đề cho thẻ <img>
. Nhập @srcset để giải quyết vấn đề này nhưng (tại thời điểm viết bài này) chưa có cách triển khai tham chiếu nào! Phần tiếp theo sẽ đi sâu hơn vào image-set
và srcset
.
Các tính năng của trình duyệt để hỗ trợ DPI cao
Cuối cùng, quyết định về phương pháp bạn sử dụng sẽ phụ thuộc vào các yêu cầu cụ thể của bạn. Tuy nhiên, hãy lưu ý rằng tất cả các phương pháp nêu trên đều có hạn chế. Tuy nhiên, trong tương lai, khi image-set
và srcset được hỗ trợ rộng rãi, chúng sẽ là giải pháp thích hợp cho vấn đề này. Hiện tại, hãy cùng thảo luận về một số phương pháp hay nhất có thể giúp chúng ta tiến gần nhất có thể đến tương lai lý tưởng đó.
Trước tiên, hai cách này khác nhau như thế nào? image-set()
là một hàm CSS, thích hợp để sử dụng làm giá trị của thuộc tính CSS nền. srcset là một thuộc tính dành riêng cho các phần tử <img>
, có cú pháp tương tự.
Cả hai thẻ này đều cho phép bạn chỉ định nội dung khai báo hình ảnh, nhưng thuộc tính srcset cũng cho phép bạn định cấu hình hình ảnh cần tải dựa trên kích thước khung nhìn.
Các phương pháp hay nhất về nhóm hình ảnh
Hàm CSS image-set()
có sẵn tiền tố là -webkit-image-set()
. Cú pháp khá đơn giản, lấy một hoặc nhiều khai báo hình ảnh được phân tách bằng dấu phẩy, bao gồm một chuỗi URL hoặc hàm url()
, theo sau là độ phân giải liên quan. Ví dụ:
background-image: -webkit-image-set(
url(icon1x.jpg) 1x,
url(icon2x.jpg) 2x
);
Điều này cho trình duyệt biết rằng có hai hình ảnh để chọn. Một trong số đó được tối ưu hoá cho màn hình 1x và màn hình còn lại được tối ưu hoá cho màn hình 2x. Sau đó, trình duyệt sẽ chọn tải tệp nào, dựa trên nhiều yếu tố, thậm chí có thể bao gồm cả tốc độ mạng, nếu trình duyệt đủ thông minh (theo tôi biết thì hiện chưa được triển khai).
Ngoài việc tải hình ảnh chính xác, trình duyệt cũng sẽ điều chỉnh theo tỷ lệ tương ứng. Nói cách khác, trình duyệt giả định rằng 2 hình ảnh lớn gấp đôi hình ảnh 1x, do đó sẽ giảm tỷ lệ hình ảnh 2x xuống theo hệ số 2 để hình ảnh có cùng kích thước trên trang.
Thay vì chỉ định 1x, 1,5x hoặc Nx, bạn cũng có thể chỉ định một mật độ pixel thiết bị nhất định theo dpi.
Cách này hoạt động tốt, ngoại trừ trong các trình duyệt không hỗ trợ thuộc tính image-set
. Các trình duyệt này sẽ không hiển thị hình ảnh nào cả! Đây rõ ràng là một vấn đề, vì vậy bạn phải sử dụng phương thức dự phòng (hoặc một loạt phương thức dự phòng) để giải quyết vấn đề đó:
background-image: url(icon1x.jpg);
background-image: -webkit-image-set(
url(icon1x.jpg) 1x,
url(icon2x.jpg) 2x
);
/* This will be useful if image-set gets into the platform, unprefixed.
Also include other prefixed versions of this */
background-image: image-set(
url(icon1x.jpg) 1x,
url(icon2x.jpg) 2x
);
Mã trên sẽ tải thành phần thích hợp trong các trình duyệt hỗ trợ nhóm hình ảnh và quay lại thành phần 1x nếu không. Lưu ý rõ ràng là mặc dù khả năng hỗ trợ trình duyệt image-set()
ở mức thấp, nhưng hầu hết các tác nhân người dùng sẽ nhận được thành phần 1x.
Bản minh hoạ này sử dụng image-set()
để tải hình ảnh chính xác, quay lại thành phần 1x nếu hàm CSS này không được hỗ trợ.
Tại thời điểm này, bạn có thể thắc mắc tại sao không chỉ polyfill (tức là tạo một trình bổ trợ JavaScript cho) image-set()
và gọi là xong? Hóa ra, khá khó để triển khai các polyfill hiệu quả cho các hàm CSS. (Để biết lý do chi tiết, hãy xem cuộc thảo luận về kiểu www này).
Srcset hình ảnh
Dưới đây là ví dụ về srcset:
<img alt="my awesome image"
src="banner.jpeg"
srcset="banner-HD.jpeg 2x, banner-phone.jpeg 640w, banner-phone-HD.jpeg 640w 2x">
Như bạn có thể thấy, ngoài các nội dung khai báo x mà image-set
cung cấp, phần tử srcset cũng lấy các giá trị w và h tương ứng với kích thước của khung nhìn, cố gắng phân phát phiên bản phù hợp nhất. Nội dung trên sẽ phân phát banner-phone.jpeg cho các thiết bị có chiều rộng khung nhìn dưới 640px, banner-phone-HD.jpeg cho các thiết bị có màn hình nhỏ có DPI cao, banner-HD.jpeg cho các thiết bị có DPI cao có màn hình lớn hơn 640px và banner.jpeg cho mọi thiết bị khác.
Sử dụng image-set cho các phần tử hình ảnh
Vì thuộc tính srcset trên các phần tử img không được triển khai trong hầu hết trình duyệt, nên bạn có thể thay thế các phần tử img bằng <div>
có nền và sử dụng phương pháp nhóm hình ảnh. Cách này sẽ hoạt động, nhưng có một số lưu ý. Điểm hạn chế ở đây là thẻ <img>
có giá trị ngữ nghĩa lâu dài. Trong thực tế, điều này chủ yếu quan trọng đối với trình thu thập thông tin trên web và các lý do liên quan đến khả năng tiếp cận.
Nếu sử dụng -webkit-image-set
, bạn có thể muốn sử dụng thuộc tính CSS nền. Nhược điểm của phương pháp này là bạn cần chỉ định kích thước hình ảnh. Kích thước này không xác định được nếu bạn đang sử dụng hình ảnh không phải 1x.
Thay vì làm như vậy, bạn có thể sử dụng thuộc tính CSS nội dung như sau:
<div id="my-content-image"
style="content: -webkit-image-set(
url(icon1x.jpg) 1x,
url(icon2x.jpg) 2x);">
</div>
Thao tác này sẽ tự động điều chỉnh tỷ lệ hình ảnh dựa trên devicePixelRatio. Hãy xem ví dụ này về kỹ thuật trên trong thực tế, với một phương án dự phòng bổ sung là url()
cho các trình duyệt không hỗ trợ image-set
.
Tự động điền srcset
Một tính năng hữu ích của srcset
là tính năng này đi kèm với một phương án dự phòng tự nhiên.
Trong trường hợp không triển khai thuộc tính srcset, tất cả trình duyệt đều biết xử lý thuộc tính src. Ngoài ra, vì đây chỉ là một thuộc tính HTML, nên bạn có thể tạo polyfill bằng JavaScript.
Tiện ích bổ sung này đi kèm với kiểm thử đơn vị để đảm bảo rằng tiện ích bổ sung này gần với thông số kỹ thuật nhất có thể. Ngoài ra, có các biện pháp kiểm tra để ngăn polyfill thực thi bất kỳ mã nào nếu srcset được triển khai theo cách gốc.
Dưới đây là bản minh hoạ về polyfill đang hoạt động.
Kết luận
Không có giải pháp thần kỳ nào để giải quyết vấn đề hình ảnh có DPI cao.
Giải pháp dễ nhất là tránh sử dụng hình ảnh hoàn toàn, thay vào đó, hãy chọn SVG và CSS. Tuy nhiên, điều này không phải lúc nào cũng thực tế, đặc biệt là nếu bạn có hình ảnh chất lượng cao trên trang web.
Các phương pháp trong JS, CSS và sử dụng phía máy chủ đều có điểm mạnh và điểm yếu. Tuy nhiên, phương pháp hứa hẹn nhất là tận dụng các tính năng mới của trình duyệt. Mặc dù tính năng hỗ trợ trình duyệt cho image-set
và srcset
vẫn chưa hoàn chỉnh, nhưng hiện có các phương án dự phòng hợp lý để sử dụng.
Tóm lại, tôi đề xuất như sau:
- Đối với hình nền, hãy sử dụng image-set với các phương án dự phòng thích hợp cho những trình duyệt không hỗ trợ tính năng này.
- Đối với hình ảnh nội dung, hãy sử dụng srcset polyfill hoặc sử dụng tính năng dự phòng sử dụng image-set (xem ở trên).
- Trong trường hợp bạn sẵn sàng hy sinh chất lượng hình ảnh, hãy cân nhắc sử dụng hình ảnh nén 2x.