Truy vấn về nội dung nghe nhìn rất hữu ích, nhưng…
Truy vấn nội dung nghe nhìn là một công cụ tuyệt vời, một món quà trời ban cho các nhà phát triển trang web muốn điều chỉnh nhỏ biểu định kiểu để mang lại trải nghiệm tốt hơn cho người dùng trên các thiết bị có nhiều kích thước. Về cơ bản, truy vấn phương tiện cho phép bạn tuỳ chỉnh CSS của trang web tuỳ thuộc vào kích thước màn hình. Trước khi đi sâu vào bài viết này, hãy tìm hiểu thêm về thiết kế thích ứng và xem một số ví dụ hay về cách sử dụng truy vấn phương tiện tại đây: mediaqueri.es.
Như Brad Frost đã chỉ ra trong một bài viết trước đây, việc thay đổi giao diện chỉ là một trong nhiều điều cần cân nhắc khi xây dựng cho web di động. Nếu việc duy nhất bạn làm khi xây dựng trang web di động là tuỳ chỉnh bố cục bằng các truy vấn nội dung nghe nhìn, thì chúng ta sẽ có tình huống sau:
- Tất cả các thiết bị đều nhận được cùng một JavaScript, CSS và thành phần (hình ảnh, video), dẫn đến thời gian tải lâu hơn mức cần thiết.
- Tất cả các thiết bị đều nhận được cùng một DOM ban đầu, có thể buộc nhà phát triển phải viết CSS quá phức tạp.
- Ít linh hoạt trong việc chỉ định các hoạt động tương tác tuỳ chỉnh phù hợp với từng thiết bị.
Ứng dụng web cần nhiều hơn các truy vấn nội dung nghe nhìn
Đừng hiểu lầm tôi. Tôi không ghét thiết kế thích ứng thông qua các truy vấn nội dung nghe nhìn và chắc chắn nghĩ rằng thiết kế này có chỗ đứng trên thế giới. Hơn nữa, bạn có thể giải quyết một số vấn đề nêu trên bằng các phương pháp như hình ảnh thích ứng, tải tập lệnh động, v.v. Tuy nhiên, đến một thời điểm nào đó, bạn có thể thấy mình đang thực hiện quá nhiều tinh chỉnh gia tăng và có thể sẽ hiệu quả hơn nếu phân phát các phiên bản khác nhau.
Khi giao diện người dùng mà bạn tạo ngày càng phức tạp và bạn hướng đến các ứng dụng web một trang, bạn sẽ muốn làm nhiều việc hơn để tuỳ chỉnh giao diện người dùng cho từng loại thiết bị. Bài viết này sẽ hướng dẫn bạn cách thực hiện những hoạt động tuỳ chỉnh này mà không tốn nhiều công sức. Phương pháp chung liên quan đến việc phân loại thiết bị của khách truy cập vào đúng lớp thiết bị và phân phát phiên bản phù hợp cho thiết bị đó, đồng thời tối đa hoá khả năng sử dụng lại mã giữa các phiên bản.
Bạn đang nhắm đến những lớp thiết bị nào?
Có vô số thiết bị kết nối Internet và hầu hết đều có trình duyệt. Vấn đề nằm ở sự đa dạng của các thiết bị này: máy tính xách tay Mac, máy trạm Windows, iPhone, iPad, điện thoại Android có tính năng nhập bằng cảm ứng, bánh xe cuộn, bàn phím, tính năng nhập bằng giọng nói, thiết bị có độ nhạy áp lực, đồng hồ thông minh, lò nướng bánh và tủ lạnh, cùng nhiều thiết bị khác. Một số thiết bị trong số này có ở khắp mọi nơi, trong khi những thiết bị khác lại rất hiếm.
Để mang lại trải nghiệm tốt cho người dùng, bạn cần biết người dùng của mình là ai và họ đang sử dụng thiết bị nào. Nếu bạn tạo giao diện người dùng cho người dùng máy tính có chuột và bàn phím rồi đưa cho người dùng điện thoại thông minh, thì giao diện của bạn sẽ gây khó chịu vì được thiết kế cho một kích thước màn hình và phương thức nhập khác.
Có hai thái cực trong phạm vi các phương pháp:
Tạo một phiên bản hoạt động trên tất cả các thiết bị. Do đó, trải nghiệm người dùng sẽ bị ảnh hưởng vì các thiết bị khác nhau có những điểm cần cân nhắc khác nhau về thiết kế.
Tạo một phiên bản cho từng thiết bị mà bạn muốn hỗ trợ. Việc này sẽ mất rất nhiều thời gian vì bạn sẽ tạo quá nhiều phiên bản của ứng dụng. Ngoài ra, khi chiếc điện thoại thông minh mới tiếp theo xuất hiện (thường là mỗi tuần), bạn sẽ buộc phải tạo một phiên bản khác.
Có một sự đánh đổi cơ bản ở đây: bạn càng có nhiều danh mục thiết bị, bạn càng có thể mang lại trải nghiệm tốt hơn cho người dùng, nhưng bạn sẽ phải tốn nhiều công sức hơn để thiết kế, triển khai và duy trì.
Bạn nên tạo một phiên bản riêng cho từng loại thiết bị mà bạn quyết định vì lý do hiệu suất hoặc nếu các phiên bản bạn muốn phân phát cho các loại thiết bị khác nhau có sự khác biệt lớn. Nếu không, thiết kế web thích ứng là một phương pháp hoàn toàn hợp lý.
Một giải pháp tiềm năng
Đây là một giải pháp thoả hiệp: phân loại thiết bị thành các danh mục và thiết kế trải nghiệm tốt nhất có thể cho từng danh mục. Danh mục bạn chọn phụ thuộc vào sản phẩm và người dùng mục tiêu của bạn. Sau đây là một mẫu phân loại bao gồm các thiết bị phổ biến có thể truy cập web hiện nay.
- màn hình nhỏ + cảm ứng (chủ yếu là điện thoại)
- màn hình lớn + cảm ứng (chủ yếu là máy tính bảng)
- màn hình lớn + bàn phím/chuột (chủ yếu là máy tính để bàn/máy tính xách tay)
Đây chỉ là một trong nhiều cách phân tích có thể, nhưng là một cách phân tích rất hợp lý tại thời điểm viết bài. Danh sách trên không bao gồm các thiết bị di động không có màn hình cảm ứng (ví dụ: điện thoại cơ bản, một số thiết bị đọc sách điện tử chuyên dụng). Tuy nhiên, hầu hết những người này đều đã cài đặt phần mềm điều hướng bằng bàn phím hoặc trình đọc màn hình. Các phần mềm này sẽ hoạt động bình thường nếu bạn xây dựng trang web có tính đến khả năng hỗ trợ tiếp cận.
Ví dụ về các ứng dụng web dành riêng cho hệ số hình dạng
Có nhiều ví dụ về các tài sản trên web phân phát hoàn toàn các phiên bản khác nhau cho các hệ số hình dạng khác nhau. Google Tìm kiếm và Facebook cũng làm như vậy. Những yếu tố cần cân nhắc cho việc này bao gồm cả hiệu suất (tìm nạp tài sản, kết xuất trang) và trải nghiệm người dùng nói chung.
Trong thế giới ứng dụng gốc, nhiều nhà phát triển chọn điều chỉnh trải nghiệm của họ cho một loại thiết bị. Ví dụ: Flipboard cho iPad có giao diện người dùng rất khác so với Flipboard trên iPhone. Phiên bản dành cho máy tính bảng được tối ưu hoá để sử dụng bằng cả hai tay và lật theo chiều ngang, trong khi phiên bản dành cho điện thoại được thiết kế để tương tác bằng một tay và lật theo chiều dọc. Nhiều ứng dụng iOS khác cũng cung cấp các phiên bản dành cho điện thoại và máy tính bảng khác biệt đáng kể, chẳng hạn như Things (danh sách việc cần làm) và Showyou (video trên mạng xã hội), như minh hoạ bên dưới:
Phương pháp 1: Phát hiện phía máy chủ
Trên máy chủ, chúng ta hiểu biết hạn chế hơn nhiều về thiết bị mà chúng ta đang xử lý. Có lẽ manh mối hữu ích nhất hiện có là chuỗi tác nhân người dùng. Chuỗi này được cung cấp thông qua tiêu đề User-Agent trên mọi yêu cầu. Do đó, phương pháp phát hiện UA tương tự sẽ hoạt động ở đây. Trên thực tế, các dự án DeviceAtlas và WURFL đã làm điều này (và cung cấp rất nhiều thông tin bổ sung về thiết bị).
Rất tiếc là mỗi phương pháp này đều có những thách thức riêng. WURFL có kích thước rất lớn, chứa 20 MB XML, có thể gây ra chi phí đáng kể phía máy chủ cho mỗi yêu cầu. Có những dự án chia nhỏ XML vì lý do hiệu suất. DeviceAtlas không phải là nguồn mở và bạn cần có giấy phép trả phí để sử dụng.
Ngoài ra, còn có những giải pháp thay thế đơn giản và miễn phí, chẳng hạn như dự án Detect Mobile Browsers (Phát hiện trình duyệt di động). Nhược điểm là việc phát hiện thiết bị chắc chắn sẽ kém toàn diện hơn. Ngoài ra, tính năng này chỉ phân biệt giữa thiết bị di động và thiết bị không phải di động, chỉ hỗ trợ máy tính bảng ở mức độ hạn chế thông qua một nhóm các tinh chỉnh đặc biệt.
Phương pháp 2: Phát hiện phía máy khách
Chúng ta có thể tìm hiểu nhiều thông tin về trình duyệt và thiết bị của người dùng bằng cách sử dụng tính năng phát hiện. Những điều chính mà chúng ta cần xác định là liệu thiết bị có khả năng cảm ứng hay không và liệu đó là màn hình lớn hay nhỏ.
Chúng ta cần phân biệt rõ ràng giữa thiết bị cảm ứng nhỏ và thiết bị cảm ứng lớn. Còn những trường hợp đặc biệt như Galaxy Note 5 inch thì sao? Hình ảnh sau đây cho thấy một loạt thiết bị Android và iOS phổ biến được đặt chồng lên nhau (với độ phân giải màn hình tương ứng). Dấu hoa thị cho biết thiết bị có hoặc có thể có mật độ gấp đôi. Mặc dù mật độ điểm ảnh có thể tăng gấp đôi, nhưng CSS vẫn báo cáo cùng kích thước.
Một lưu ý nhanh về pixel trong CSS: Pixel CSS trên web di động không giống với pixel màn hình. Các thiết bị iOS Retina đã giới thiệu phương pháp tăng gấp đôi mật độ pixel (ví dụ: iPhone 3GS so với 4, iPad 2 so với 3). UA Mobile Safari Retina vẫn báo cáo cùng một device-width để tránh làm hỏng web. Là các thiết bị khác (ví dụ: Android) có màn hình độ phân giải cao hơn, chúng đang thực hiện thủ thuật tương tự về chiều rộng thiết bị.
Tuy nhiên, điều khiến quyết định này trở nên phức tạp là tầm quan trọng của việc cân nhắc cả chế độ dọc và ngang. Chúng ta không muốn tải lại trang hoặc tải thêm tập lệnh mỗi khi xoay thiết bị, mặc dù có thể muốn kết xuất trang theo cách khác.
Trong sơ đồ sau, các hình vuông biểu thị kích thước tối đa của mỗi thiết bị, do kết quả của việc phủ các đường viền dọc và ngang (và hoàn thành hình vuông):
Bằng cách đặt ngưỡng thành 650px, chúng ta phân loại iPhone, Galaxy Nexus là smalltouch và iPad, Galaxy Tab là "máy tính bảng". Trong trường hợp này, Galaxy Note là một thiết bị trung tính về giới tính và được phân loại là "điện thoại", đồng thời sẽ có bố cục điện thoại.
Vì vậy, một chiến lược hợp lý có thể như sau:
if (hasTouch) {
if (isSmall) {
device = PHONE;
} else {
device = TABLET;
}
} else {
device = DESKTOP;
}
Xem mẫu tối thiểu của phương pháp phát hiện tính năng đang hoạt động.
Phương pháp thay thế ở đây là sử dụng tính năng phát hiện UA để phát hiện loại thiết bị. Về cơ bản, bạn tạo một bộ phương pháp phỏng đoán và so khớp bộ phương pháp đó với navigator.userAgent của người dùng. Mã giả sẽ có dạng như sau:
var ua = navigator.userAgent;
for (var re in RULES) {
if (ua.match(re)) {
device = RULES[re];
return;
}
}
Xem ví dụ về phương pháp phát hiện UA đang hoạt động.
Lưu ý về việc tải phía máy khách
Nếu đang thực hiện việc phát hiện UA trên máy chủ, bạn có thể quyết định phân phát CSS, JavaScript và DOM nào khi nhận được một yêu cầu mới. Tuy nhiên, nếu bạn đang thực hiện quy trình phát hiện phía máy khách, thì tình huống sẽ phức tạp hơn. Bạn có một số lựa chọn:
- Chuyển hướng đến một URL dành riêng cho loại thiết bị có chứa phiên bản cho loại thiết bị này.
- Tải động các thành phần dành riêng cho loại thiết bị.
Phương pháp đầu tiên rất đơn giản, yêu cầu một lệnh chuyển hướng như window.location.href = '/tablet'. Tuy nhiên, vị trí hiện sẽ có thông tin về loại thiết bị này được thêm vào, vì vậy, bạn có thể muốn sử dụng History API để dọn dẹp URL của mình. Rất tiếc, phương pháp này liên quan đến một lệnh chuyển hướng có thể chậm, đặc biệt là trên thiết bị di động.
Cách tiếp cận thứ hai phức tạp hơn khá nhiều khi triển khai. Bạn cần một cơ chế để tải CSS và JS một cách linh hoạt, đồng thời (tuỳ thuộc vào trình duyệt), bạn có thể không thực hiện được những việc như tuỳ chỉnh <meta viewport>. Ngoài ra, vì không có lệnh chuyển hướng, nên bạn sẽ bị mắc kẹt với HTML gốc đã được phân phát. Tất nhiên, bạn có thể thao tác với nó bằng JavaScript, nhưng thao tác này có thể chậm và/hoặc không hiệu quả, tuỳ thuộc vào ứng dụng của bạn.
Quyết định máy khách hay máy chủ
Sau đây là bảng so sánh giữa các phương pháp:
Khách hàng chuyên nghiệp:
- Có khả năng thích ứng tốt hơn với các thay đổi trong tương lai vì dựa trên kích thước/khả năng của màn hình thay vì UA.
- Không cần liên tục cập nhật danh sách UA.
Máy chủ Pro:
- Toàn quyền kiểm soát phiên bản sẽ được phân phối cho thiết bị nào.
- Hiệu suất tốt hơn: không cần chuyển hướng máy khách hoặc tải động.
Tôi thích bắt đầu bằng device.js và tính năng phát hiện phía máy khách. Khi ứng dụng của bạn phát triển, nếu thấy việc chuyển hướng phía máy khách là một điểm hạn chế đáng kể về hiệu suất, bạn có thể dễ dàng xoá tập lệnh device.js và triển khai tính năng phát hiện UA trên máy chủ.
Giới thiệu về device.js
Device.js là điểm khởi đầu để thực hiện tính năng phát hiện thiết bị dựa trên truy vấn nội dung nghe nhìn và ngữ nghĩa mà không cần cấu hình đặc biệt phía máy chủ, giúp tiết kiệm thời gian và công sức cần thiết để phân tích chuỗi tác nhân người dùng.
Ý tưởng là bạn cung cấp mã đánh dấu thân thiện với công cụ tìm kiếm (link rel=alternate) ở đầu <head> cho biết phiên bản nào của trang web mà bạn muốn cung cấp.
<link rel="alternate" href="http://foo.com" id="desktop"
media="only screen and (touch-enabled: 0)">
Tiếp theo, bạn có thể tự thực hiện việc phát hiện UA phía máy chủ và xử lý lệnh chuyển hướng phiên bản hoặc sử dụng tập lệnh device.js để thực hiện lệnh chuyển hướng phía máy khách dựa trên tính năng.
Để biết thêm thông tin, hãy xem trang dự án device.js và cả ứng dụng giả sử dụng device.js để chuyển hướng phía máy khách.
Đề xuất: MVC có khung hiển thị dành riêng cho kiểu dáng thiết bị
Đến đây, có lẽ bạn đang nghĩ rằng tôi đang yêu cầu bạn tạo 3 ứng dụng hoàn toàn riêng biệt, mỗi ứng dụng cho một loại thiết bị. Không! Chia sẻ mã là yếu tố then chốt.
Hy vọng bạn đã và đang sử dụng một khung tương tự như MVC, chẳng hạn như Backbone, Ember, v.v. Nếu đã và đang sử dụng, bạn sẽ quen với nguyên tắc phân tách các mối lo ngại, cụ thể là giao diện người dùng (lớp hiển thị) của bạn sẽ tách biệt với logic (lớp mô hình). Nếu bạn chưa biết đến MVC, hãy bắt đầu với một số tài nguyên về MVC và MVC trong JavaScript.
Câu chuyện trên nhiều thiết bị phù hợp với khung MVC hiện có của bạn. Bạn có thể dễ dàng di chuyển các khung hiển thị vào các tệp riêng biệt, tạo khung hiển thị tuỳ chỉnh cho từng loại thiết bị. Sau đó, bạn có thể phân phát cùng một mã cho tất cả các thiết bị, ngoại trừ lớp hiển thị.
Dự án của bạn có thể có cấu trúc như sau (tất nhiên, bạn có thể tự do chọn cấu trúc phù hợp nhất tuỳ thuộc vào ứng dụng của mình):
models/ (các mô hình dùng chung) item.js item-collection.js
controllers/ (shared controllers) item-controller.js
versions/ (device-specific stuff) tablet/ desktop/ phone/ (phone-specific code) style.css index.html views/ item.js item-list.js
Cấu trúc này cho phép bạn kiểm soát hoàn toàn những thành phần mà mỗi phiên bản tải, vì bạn có HTML, CSS và JavaScript tuỳ chỉnh cho từng thiết bị. Đây là một cách rất hiệu quả và có thể dẫn đến cách phát triển tinh gọn và hiệu quả nhất cho web đa thiết bị mà không cần dựa vào các thủ thuật như hình ảnh thích ứng.
Sau khi chạy công cụ tạo bản dựng mà bạn yêu thích, bạn sẽ nối và giảm thiểu tất cả JavaScript và CSS của mình thành các tệp riêng lẻ để tải nhanh hơn, với HTML sản xuất của bạn trông giống như sau (đối với điện thoại, sử dụng device.js):
<!doctype html>
<head>
<title>Mobile Web Rocks! (Phone Edition)</title>
<!-- Every version of your webapp should include a list of all
versions. -->
<link rel="alternate" href="http://foo.com" id="desktop"
media="only screen and (touch-enabled: 0)">
<link rel="alternate" href="http://m.foo.com" id="phone"
media="only screen and (max-device-width: 650px)">
<link rel="alternate" href="http://tablet.foo.com" id="tablet"
media="only screen and (min-device-width: 650px)">
<!-- Viewport is very important, since it affects results of media
query matching. -->
<meta name="viewport" content="width=device-width">
<!-- Include device.js in each version for redirection. -->
<script src="device.js"></script>
<link rel="style" href="phone.min.css">
</head>
<body>
<script src="phone.min.js"></script>
</body>
Xin lưu ý rằng truy vấn nội dung nghe nhìn (touch-enabled: 0) không phải là truy vấn chuẩn (chỉ được triển khai trong Firefox sau tiền tố nhà cung cấp moz), nhưng được device.js xử lý chính xác (nhờ Modernizr.touch).
Ghi đè phiên bản
Đôi khi, tính năng phát hiện thiết bị có thể hoạt động không chính xác. Trong một số trường hợp, người dùng có thể muốn xem bố cục dành cho máy tính bảng trên điện thoại (có thể họ đang dùng Galaxy Note). Vì vậy, bạn cần cho người dùng lựa chọn phiên bản trang web mà họ muốn sử dụng nếu họ muốn ghi đè theo cách thủ công.
Cách tiếp cận thông thường là cung cấp một đường liên kết đến phiên bản dành cho máy tính từ phiên bản dành cho thiết bị di động. Bạn có thể dễ dàng triển khai tính năng này, nhưng device.js hỗ trợ chức năng này bằng tham số GET device.
Kết luận
Tóm lại, khi xây dựng giao diện người dùng một trang trên nhiều thiết bị, không phù hợp với thế giới thiết kế thích ứng, hãy làm như sau:
- Chọn một nhóm các lớp thiết bị để hỗ trợ và tiêu chí để phân loại thiết bị thành các lớp.
- Tạo ứng dụng MVC với sự tách biệt rõ ràng về các mối quan tâm, tách các khung hiển thị khỏi phần còn lại của cơ sở mã.
- Sử dụng device.js để phát hiện lớp thiết bị phía máy khách.
- Khi bạn đã sẵn sàng, hãy đóng gói tập lệnh và biểu định kiểu thành một trong mỗi loại cho mỗi lớp thiết bị.
- Nếu hiệu suất chuyển hướng phía máy khách gặp vấn đề, hãy bỏ device.js và chuyển sang tính năng phát hiện UA phía máy chủ.