Phương pháp không phản hồi để xây dựng các ứng dụng web trên nhiều thiết bị

Boris Smus
Boris Smus

Truy vấn phương tiện rất tuyệt, nhưng...

Truy vấn nội dung đa phương tiện là lựa chọn tuyệt vời dành cho các nhà phát triển trang web muốn thực hiện những chỉnh sửa nhỏ đối với biểu định kiểu của họ để mang lại trải nghiệm tốt hơn cho người dùng trên các thiết bị ở 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 bạn tìm hiểu kỹ 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ụ điển hình về cách sử dụng truy vấn nội dung nghe nhìn tại đây: mediaqueri.es.

Như Brad Frost đã chỉ ra trong một bài viết trước đó, 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 trang web dành cho thiết bị di động. Nếu bạn chỉ cần tuỳ chỉnh bố cục bằng các truy vấn nội dung nghe nhìn khi tạo trang web dành cho thiết bị di động, thì chúng ta sẽ gặp phải tình huống sau:

  • Tất cả các thiết bị đều nhận được cùng một JavaScript, CSS và nội dung (hình ảnh, video), dẫn đến thời gian tải lâu hơn 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 các nhà phát triển phải viết CSS quá phức tạp.
  • Ít linh hoạt để chỉ định các 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 truy vấn phương tiện

Bạn không hiểu sai ý tôi. Tôi không ghét thiết kế đáp ứng thông qua các truy vấn phương tiện và chắc chắn rằng thiết kế này có một vị thế trên thế giới. Hơn nữa, bạn có thể giải quyết một số vấn đề đã đề cập ở trên bằng các phương pháp như hình ảnh thích ứng, tải tập lệnh linh động, v.v. Tuy nhiên, tại một thời điểm nhất định, bạn có thể thấy mình đã thực hiện quá nhiều thao tác điều chỉnh tăng dần, và bạn nên phân phát nhiều phiên bản khác nhau.

Khi giao diện người dùng bạn tạo ngày càng phức tạp và ngày càng thích ứng dụng web trang đơn, bạn nê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 các tuỳ chỉnh này mà không tốn nhiều công sức. Phương pháp chung bao gồm việc phân loại thiết bị của khách truy cập vào đúng loại 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á việc sử dụng lại mã giữa các phiên bản.

Bạn đang nhắm đến những loại thiết bị nào?

Có rất nhiều thiết bị có kết nối Internet trên thị trường và gần như tất cả đều có trình duyệt. Chức năng này nằm ở tính đa dạng: Máy tính xách tay Mac, máy trạm Windows, iPhone, iPad, điện thoại Android có phương thức nhập bằng cách chạm, con lăn, bàn phím, nhập bằng giọng nói, thiết bị nhạy áp lực, đồng hồ thông minh, máy nướng bánh mì và tủ lạnh, v.v. Một số thiết bị trong số này có ở khắp nơi, trong khi một số khác thì rất hiếm.

Nhiều loại thiết bị.
Nhiều thiết bị (nguồn).

Để tạo ra 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 xây dựng giao diện người dùng cho người dùng máy tính bằng chuột và bàn phím rồi cung cấp giao diện đó cho người dùng điện thoại thông minh, thì giao diện của bạn sẽ gây thất vọng vì giao diện đó được thiết kế cho một kích thước màn hình khác và cho một phương thức nhập khác.

Có hai phương pháp tiếp cận cực đoan:

  1. Tạo một phiên bản hoạt động trên tất cả thiết bị. Kết quả là trải nghiệm người dùng sẽ bị ảnh hưởng vì các thiết bị khác nhau có các cân nhắc khác nhau về thiết kế.

  2. Tạo một phiên bản cho từng thiết bị bạn muốn hỗ trợ. Việc này sẽ mất vĩnh viễn vì bạn sẽ tạo quá nhiều phiên bản ứng dụng. Ngoài ra, khi điện thoại thông minh mới tiếp theo ra mắt (diễn ra gần như hằng 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ể cung cấp trải nghiệm người dùng tốt hơn, nhưng bạn càng mất nhiều công sức để thiết kế, triển khai và duy trì hơn.

Việc tạo một phiên bản riêng cho từng lớp thiết bị mà bạn quyết định có thể là ý tưởng hay vì lý do hiệu suất, hoặc nếu phiên bản bạn muốn phân phát cho các lớp thiết bị khác nhau có sự khác biệt đáng kể. Nếu không, thiết kế web thích ứng là phương pháp hoàn toàn hợp lý.

Một giải pháp tiềm năng

Sau đây là một giải phá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. Những danh mục mà bạn chọn sẽ phụ thuộc vào sản phẩm và người dùng mục tiêu của bạn. Dưới đây là cách phân loại mẫu áp dụng trên các thiết bị hỗ trợ web phổ biến hiện nay.

  1. màn hình nhỏ + cảm ứng (chủ yếu là điện thoại)
  2. màn hình lớn + cảm ứng (chủ yếu là máy tính bảng)
  3. 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 chỉ số chia nhỏ có thể xảy ra, nhưng sẽ có ý nghĩa rất lớn tại thời điểm viết. Danh sách trên còn thiếu là các thiết bị di động không có màn hình cảm ứng (ví dụ: điện thoại phổ thông, một số trình đọc sách điện tử chuyên dụng). Tuy nhiên, hầu hết các trang này đều được 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. Những phần mềm này sẽ hoạt động hiệu quả nếu bạn xây dựng trang web chú trọng đế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ề việc các thuộc tính web phân phát các phiên bản hoàn toàn khác nhau cho các hệ số hình dạng khác nhau. Google Tìm kiếm thực hiện việc này, cũng như Facebook. Những điểm cần cân nhắc bao gồm cả hiệu suất (tìm nạp thành phần, hiển thị 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 phù hợp với lớp 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á cho việc sử dụng 2 tay và lật ngang, trong khi phiên bản điện thoại dành cho tương tác bằng một tay và lật dọc. Nhiều ứng dụng iOS khác cũng cung cấp 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ư được nêu dưới đây:

Khả năng tuỳ chỉnh đáng kể giao diện người dùng cho điện thoại và máy tính bảng.
Khả năng tuỳ chỉnh đáng kể giao diện người dùng cho điện thoại và máy tính bảng.

Phương pháp 1: Phát hiện phía máy chủ

Trên máy chủ, chúng tôi không hiểu rõ hơn nhiều về thiết bị mà chúng tôi đ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, được cung cấp thông qua tiêu đề Tác nhân người dùng trong mọi yêu cầu. Do đó, phương pháp theo dõi tương tự của UA sẽ hoạt động ở đây. Trên thực tế, các dự án DeviceAtlas và WURFL đã thực hiện việc này (và cung cấp rất nhiều thông tin bổ sung về thiết bị).

Thật không may, mỗi phương pháp lại có những thách thức riêng. WURFL rất lớn, chứa 20 MB XML, có thể làm phát sinh chi phí đáng kể phía máy chủ cho mỗi yêu cầu. Có những dự án phân tách tệp XML vì lý do hiệu suất. DeviceAtlas không phải là nguồn mở và yêu cầu phải có giấy phép trả phí để sử dụng.

Ngoài ra, còn có các lựa chọn thay thế miễn phí và đơn giản hơn, như dự án Phát hiện trình duyệt trên thiết bị di động. Tất nhiên, 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, nó 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 có giới hạn thông qua một số 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 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 tính năng. Những nội dung chính mà chúng ta cần xác định là xem thiết bị có khả năng cảm ứng hay không và đó là màn hình lớn hay nhỏ.

Chúng ta cần vẽ đường kẻ ở vị trí nào đó để phân biệt thiết bị cảm ứng nhỏ và lớn. Còn các ốp lưng như Galaxy Note 5" thì sao? Hình ảnh đồ hoạ sau đây cho thấy một số thiết bị Android và iOS phổ biến xếp chồng (với độ phân giải màn hình tương ứng). Dấu hoa thị cho biết thiết bị xuất hiện hoặc có thể có mật độ gấp đôi. Mặc dù mật độ pixel có thể tăng gấp đôi, nhưng CSS vẫn báo cáo cùng một kích thước.

Một chút về pixel trong CSS: pixel CSS trên web dành cho thiết bị di động không giống với pixel màn hình. Các thiết bị retina iOS đã giới thiệu phương pháp nhân đôi mật độ pixel (ví dụ: iPhone 3GS so với 4, iPad 2 so với 3). Các UA retina Mobile Safari vẫn báo cáo cùng một chiều rộng của thiết bị để tránh làm hỏng web. Như các thiết bị khác (ví dụ: Android) nhận được màn hình có độ phân giải cao hơn, chúng đang thực hiện cùng một thủ thuật theo chiều rộng của thiết bị.

Độ phân giải của thiết bị (tính bằng pixel).
Độ phân giải của thiết bị (tính bằng pixel).

Tuy nhiên, việc làm phức tạp quyết định này là rất quan trọng khi xem xét cả chế độ dọc và chế độ 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 định hướng lại thiết bị, mặc dù chúng ta có thể muốn hiển thị 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 từng thiết bị, do việc phủ lên các đường viền dọc và ngang (đồng thời hoàn thành hình vuông):

Độ phân giải dọc + ngang (tính bằng pixel)
Độ phân giải dọc + ngang (tính bằng pixel)

Bằng cách đặt ngưỡng thành 650px, chúng tôi phân loại iPhone, Galaxy Nexus là thiết bị cảm ứng nhỏ, còn iPad, Galaxy Tab là "máy tính bảng". Trong trường hợp này, Galaxy Note được phân loại là "điện thoại" và sẽ nhận được bố cục điện thoại.

Do đó, chiến lược hợp lý có thể có dạng như sau:

if (hasTouch) {
  if (isSmall) {
    device = PHONE;
  } else {
    device = TABLET;
  }
} else {
  device = DESKTOP;
}

Xem một ví dụ mẫu tối thiểu về phương pháp phát hiện tính năng trong thực tế.

Phương pháp thay thế ở đây là sử dụng tính năng nhận biết của UA để phát hiện loại thiết bị. Về cơ bản, bạn sẽ tạo một tập hợp phương pháp phỏng đoán và so khớp chúng 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ụ thực tế về phương pháp phát hiện UA.

Lưu ý về việc tải phía máy khách

Nếu đang phát hiện UA trên máy chủ của mình, bạn có thể quyết định CSS, JavaScript và DOM nào sẽ phân phát khi nhận được yêu cầu mới. Tuy nhiên, nếu bạn đang thực hiện phát hiện phía máy khách, tình huống này sẽ phức tạp hơn. Bạn có một số lựa chọn:

  1. Chuyển hướng đến URL cụ thể theo loại thiết bị có chứa phiên bản dành cho loại thiết bị này.
  2. Tự động tải 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, chẳng hạn như window.location.href = '/tablet'. Tuy nhiên, thông tin về loại thiết bị này hiện sẽ được thêm vào thông tin vị trí, vì vậy, bạn nên sử dụng API Lịch sử để xoá URL của mình. Rất tiếc, phương pháp này liên quan đến lệnh chuyển hướng, có thể chậm, đặc biệt là trên thiết bị di động.

Phương pháp thứ hai phức tạp hơn một chút khi triển khai. Bạn cần có một cơ chế để tự động tải CSS và JS, và (tuỳ thuộc vào trình duyệt), bạn có thể không làm đượ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ị kẹt với HTML ban đầu được phân phát. Tất nhiên, bạn có thể thao tác bằng JavaScript, nhưng phương thức này có thể chậm và/hoặc không phù hợp, tuỳ thuộc vào ứng dụng của bạn.

Ứng dụng hoặc máy chủ quyết định

Sau đây là điểm đánh đổi giữa các phương pháp:

Ứng dụng Pro:

  • Bằng chứng rõ ràng hơn trong tương lai dựa trên kích thước/chức năng màn hình chứ không phải UA.
  • Không cần phải liên tục cập nhật danh sách UA.

Máy chủ Pro:

  • Có toàn quyền kiểm soát phiên bản nào sẽ phân phát đến thiết bị nào.
  • Hiệu suất tốt hơn: không cần chuyển hướng ứng dụng khách hoặc tải động.

Ưu tiên cá nhân của tôi là 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 nhận thấy lệnh chuyển hướng phía máy khách có 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 device.js

Device.js là điểm xuất phát để phát hiện thiết bị dựa trên truy vấn nội dung nghe nhìn theo 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 cú pháp 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 bạn muốn cung cấp phiên bản nào của trang web.

<link rel="alternate" href="http://foo.com" id="desktop"
    media="only screen and (touch-enabled: 0)">

Tiếp theo, bạn có thể tự 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 để 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 cũng như ứ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 từng hệ số hình dạng

Giờ đây, có thể bạn đang nghĩ rằng tôi sẽ hướng dẫn bạn xây dựng 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 đâu! Chia sẻ mã là chìa khoá.

Hy vọng bạn đã và đang sử dụng khung giống như MVC, chẳng hạn như Back X xương, Ember, v.v. Nếu đã từng sử dụng, bạn đã quen thuộc với nguyên tắc tách biệt các vấn đề, cụ thể là giao diện người dùng (lớp khung hiển thị) phải được tách riêng khỏi logic (lớp mô hình). Nếu bạn mới sử dụng tính năng này, hãy bắt đầu với một số tài nguyên về MVCMVC trong JavaScript.

Câu chuyện trên nhiều thiết bị hoàn toàn phù hợp với khung MVC hiện tại của bạn. Bạn có thể dễ dàng di chuyển khung hiển thị của mình thành các tệp riêng biệt, tạo ra một 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 khung hiển thị.

MVC trên nhiều thiết bị.
MVC trên nhiều thiết bị.

Dự án của bạn có thể có cấu trúc sau (tất nhiên, bạn có thể tuỳ ý chọn cấu trúc phù hợp nhất tuỳ thuộc vào ứng dụng của mình):

mô hình/ (mô hình dùng chung) item.js item-collection.js

bộ điều khiển/ (bộ điều khiển dùng chung) item-controller.js

phiên bản/ (nội dung dành riêng cho thiết bị) máy tính bảng/ máy tính/ điện thoại/ (mã dành riêng cho điện thoại) style.css index.html view/ item.js item-list.js

Loại 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ị. Giải pháp này rất hiệu quả và có thể mang đến cách phát triển gọn gàng, hiệu quả nhất cho web trên nhiều thiết bị mà không cần dựa vào các thủ thuật như hình ảnh thích ứng.

Khi chạy công cụ xây dựng yêu thích, bạn sẽ nối và giảm kích thước tất cả JavaScript và CSS thành các tệp duy nhất để 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 đa phương tiện (touch-enabled: 0) là không chuẩn (chỉ được triển khai trong Firefox sau moz tiền tố nhà cung cấp), nhưng lại được xử lý chính xác (nhờ Modernizr.touch) bằng device.js.

Ghi đè phiên bản

Tính năng phát hiện thiết bị đôi khi có thể gặp sự cố và trong một số trường hợp, người dùng có thể muốn xem bố cục máy tính bảng trên điện thoại của họ (có thể họ đang sử dụng Galaxy Note). Vì vậy, điều quan trọng là bạn phải cho người dùng lựa chọn phiên bản trang web của bạn sẽ sử dụng nếu họ muốn ghi đè theo cách thủ công.

Phương pháp thông thường là cung cấp đườ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. Việc này đủ dễ để triển khai, 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 trang đơn trên nhiều thiết bị, giao diện này không phù hợp với thiết kế thích ứng, hãy làm như sau:

  1. Chọn một tập hợp các lớp thiết bị cần hỗ trợ và tiêu chí để phân loại thiết bị thành các lớp.
  2. Xây dựng ứng dụng MVC bằng khả năng tách biệt mạnh mẽ các vấn đề, chia khung hiển thị khỏi phần còn lại của cơ sở mã.
  3. Sử dụng device.js để phát hiện lớp thiết bị phía máy khách.
  4. 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 tập lệnh và biểu định kiểu cho mỗi lớp thiết bị.
  5. Nếu có vấn đề về hiệu suất chuyển hướng phía máy khách, hãy huỷ device.js và chuyển sang dùng tính năng phát hiện UA phía máy chủ.