Giới thiệu
Phát triển cho web dành cho thiết bị di động là một chủ đề nổi bật hiện nay. Năm nay, lần đầu tiên, điện thoại thông minh bán chạy hơn máy tính. Ngày càng có nhiều người dùng sử dụng thiết bị di động để duyệt web, điều này có nghĩa là các nhà phát triển cần phải tối ưu hoá trang web của họ cho trình duyệt di động.
Mặt trận "thiết bị di động" vẫn là vùng đất chưa được khám phá đối với nhiều nhà phát triển. Nhiều người hiện có trang web cũ bỏ qua người dùng thiết bị di động. Thay vào đó, trang web này chủ yếu được thiết kế để duyệt web trên máy tính và hoạt động kém trên trình duyệt dành cho thiết bị di động. Trang web này (html5rock.com) cũng không phải là ngoại lệ. Khi ra mắt, chúng tôi dành ít nỗ lực cho phiên bản dành cho thiết bị di động của trang web.
Tạo html5rocks.com thân thiện với thiết bị di động
Để thực hành, tôi nghĩ sẽ rất thú vị nếu lấy html5rocks (một trang web HTML5 hiện có) và bổ sung phiên bản thân thiện với thiết bị di động. Tôi chủ yếu quan tâm đến lượng công việc tối thiểu cần thiết để nhắm đến điện thoại thông minh. Mục tiêu của bài tập này không phải là tạo một trang web dành cho thiết bị di động hoàn toàn mới và duy trì hai cơ sở mã. Việc này sẽ mất rất nhiều thời gian và lãng phí rất nhiều thời gian. Chúng tôi đã xác định được cấu trúc của trang web (mã đánh dấu). Chúng tôi đã có cái nhìn và cảm nhận (CSS). Chức năng cốt lõi (JS) đã có sẵn. Vấn đề là nhiều trang web cũng gặp phải tình trạng này.
Bài viết này xem xét cách chúng tôi tạo ra một phiên bản html5rock cho thiết bị di động, được tối ưu hoá cho thiết bị Android và iOS. Bạn chỉ cần tải html5rocks.com trên một thiết bị hỗ trợ một trong những hệ điều hành đó để thấy sự khác biệt. Không có lệnh chuyển hướng đến m.html5rocks.com hoặc các trang web lừa đảo khác thuộc loại đó. Bạn sẽ nhận được html5rocks như hiện tại… với lợi ích bổ sung là giao diện đẹp mắt và hoạt động tốt trên thiết bị di động.
Truy vấn nội dung đa phương tiện CSS
HTML4 và CSS2 đã hỗ trợ biểu định kiểu phụ thuộc vào nội dung nghe nhìn trong một thời gian. Ví dụ:
<link rel="stylesheet" media="print" href="printer.css">
sẽ nhắm đến các thiết bị in và cung cấp kiểu cụ thể cho nội dung trang khi in. CSS3 đưa ý tưởng về các loại nội dung đa phương tiện lên một tầm cao mới và nâng cao chức năng của các loại nội dung đó bằng truy vấn nội dung đa phương tiện. Truy vấn nội dung đa phương tiện mở rộng tính hữu ích của các loại nội dung đa phương tiện bằng cách cho phép gắn nhãn chính xác hơn cho các trang kiểu. Điều này cho phép tuỳ chỉnh cách trình bày nội dung cho một phạm vi thiết bị đầu ra cụ thể mà không cần thay đổi nội dung. Nghe rất phù hợp với một bố cục hiện có cần sửa đổi!
Bạn có thể sử dụng các truy vấn nội dung nghe nhìn trong thuộc tính media
của bảng định kiểu bên ngoài để nhắm mục tiêu chiều rộng màn hình, chiều rộng thiết bị, hướng, v.v. Để biết danh sách đầy đủ, hãy xem thông số kỹ thuật truy vấn nội dung nghe nhìn W3C.
Nhắm mục tiêu theo kích thước màn hình
Trong ví dụ sau, phone.css
sẽ áp dụng cho các thiết bị mà trình duyệt coi là "thiết bị cầm tay" hoặc các thiết bị có màn hình rộng <= 320px.
<link rel='stylesheet'
media='handheld, only screen and (max-device-width: 320px)' href='phone.css'>
Việc thêm tiền tố vào một truy vấn nội dung đa phương tiện với từ khoá "only
" sẽ khiến
các trình duyệt không tuân thủ CSS3 bỏ qua quy tắc này.
Nội dung sau đây sẽ nhắm đến kích thước màn hình từ 641px đến 800px:
<link rel='stylesheet'
media='only screen and (min-width: 641px) and (max-width: 800px)' href='ipad.css'>
Truy vấn nội dung nghe nhìn cũng có thể xuất hiện trong thẻ <style>
cùng dòng. Các mục tiêu sau đây nhắm đến các loại nội dung nghe nhìn all
khi ở hướng dọc:
<style>
@media only all and (orientation: portrait) { ... }
</style>
media="handheld"
Chúng ta cần dừng lại một chút để thảo luận về media="handheld"
.
Thực tế là Android và iOS bỏ qua media="handheld"
. Ý kiến xác nhận là người dùng sẽ bỏ lỡ nội dung cao cấp do các kiểu phông chữ nhắm đến media="screen"
cung cấp và nhà phát triển ít có khả năng duy trì phiên bản media="handheld"
chất lượng thấp hơn. Vì vậy, theo phương châm "web đầy đủ", hầu hết trình duyệt điện thoại thông minh hiện đại chỉ bỏ qua các trang kiểu cầm tay.
Tốt nhất là bạn nên sử dụng tính năng này để nhắm đến thiết bị di động, nhưng các trình duyệt khác nhau đã triển khai tính năng này theo nhiều cách:
- Một số người chỉ đọc biểu định kiểu cầm tay.
- Một số chỉ đọc trang kiểu cầm tay nếu có, nhưng mặc định là trang kiểu màn hình nếu không.
- Một số trình đọc cả trang kiểu cầm tay và trang kiểu màn hình.
- Một số người chỉ đọc biểu định kiểu màn hình.
Opera Mini không bỏ qua media="handheld"
. Mẹo để Windows Mobile nhận ra media="handheld"
là viết hoa giá trị thuộc tính media cho tệp kiểu màn hình:
<!-- media="handheld" trick for Windows Mobile -->
<link rel="stylesheet" href="screen.css" media="Screen">
<link rel="stylesheet" href="mobile.css" media="handheld">
Cách html5rocks sử dụng truy vấn nội dung đa phương tiện
Truy vấn phương tiện được sử dụng rất nhiều trên html5rock của thiết bị di động. Các lớp này cho phép chúng tôi chỉnh sửa bố cục mà không cần thực hiện thay đổi đáng kể nào đối với mã đánh dấu mẫu Django… một giải pháp thực sự hữu ích! Ngoài ra, dịch vụ hỗ trợ của họ trên nhiều trình duyệt khá tốt.
Trong <head>
của mỗi trang, bạn sẽ thấy các tệp kiểu sau:
<link rel='stylesheet'
media='all' href='/static/css/base.min.css' />
<link rel='stylesheet'
media='only screen and (max-width: 800px)' href='/static/css/mobile.min.css' />
base.css
luôn xác định giao diện chính của html5rocks.com, nhưng giờ đây, chúng ta sẽ áp dụng các kiểu mới (mobile.css
) cho chiều rộng màn hình dưới 800px. Truy vấn nội dung nghe nhìn của thiết bị này bao gồm điện thoại thông minh (~320px) và iPad (~768px).
Hiệu ứng: chúng ta đang ghi đè dần các kiểu trong base.css
(chỉ khi cần thiết) để mọi thứ trông đẹp hơn trên thiết bị di động.
Một số thay đổi về kiểu mà mobile.css
thực thi:
- Giảm khoảng trắng/khoảng đệm thừa trên trang web. Màn hình nhỏ đồng nghĩa với không gian bị hạn chế!
- Xoá các trạng thái
:hover
. Các nút này sẽ không bao giờ xuất hiện trên thiết bị cảm ứng. - Điều chỉnh bố cục thành một cột. Chúng ta sẽ nói thêm về điều này ở phần sau.
- Xoá
box-shadow
xung quanh div vùng chứa chính của trang web. Bóng hộp lớn làm giảm hiệu suất trang. - Sử dụng mô hình hộp flex CSS
box-ordinal-group
để thay đổi thứ tự của từng phần trên trang chủ. Bạn sẽ thấy mục "TÌM HIỂU VỀ CÁC NHÓM TÍNH NĂNG CHỦ YẾU HTML5" xuất hiện trước phần "HƯỚNG DẪN" trên trang chủ nhưng sau đó trên phiên bản dành cho thiết bị di động. Thứ tự này phù hợp hơn với thiết bị di động và không yêu cầu thay đổi mã đánh dấu. Hộp flex CSS FTW! - Xoá
opacity
thay đổi. Việc thay đổi giá trị alpha sẽ ảnh hưởng đến hiệu suất trên thiết bị di động.
Thẻ meta dành cho thiết bị di động
WebKit dành cho thiết bị di động hỗ trợ một số tính năng giúp người dùng có trải nghiệm duyệt web tốt hơn trên một số thiết bị nhất định.
Cài đặt khung nhìn
Chế độ cài đặt meta đầu tiên (và chế độ cài đặt mà bạn sẽ sử dụng thường xuyên nhất) là thuộc tính khung nhìn. Việc đặt khung nhìn sẽ cho trình duyệt biết cách nội dung vừa với màn hình của thiết bị và thông báo cho trình duyệt rằng trang web được tối ưu hoá cho thiết bị di động. Ví dụ:
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
cho trình duyệt biết cách đặt khung nhìn theo chiều rộng của thiết bị với tỷ lệ ban đầu là 1. Ví dụ này cũng cho phép thu phóng, đây là một tính năng mà có thể bạn mong muốn đối với một trang web chứ không phải ứng dụng web. Chúng ta có thể ngăn việc thu phóng bằng user-scalable=no
hoặc giới hạn tỷ lệ ở một mức độ nhất định:
<meta name=viewport
content="width=device-width, initial-scale=1.0, minimum-scale=0.5 maximum-scale=1.0">
Android mở rộng thẻ meta khung nhìn bằng cách cho phép nhà phát triển chỉ định độ phân giải màn hình mà trang web được phát triển:
<meta name="viewport" content="target-densitydpi=device-dpi">
Các giá trị có thể có cho target-densitydpi
là device-dpi
, high-dpi
, medium-dpi
, low-dpi
.
Nếu bạn muốn sửa đổi trang web cho nhiều mật độ màn hình, hãy sử dụng truy vấn nội dung đa phương tiện CSS -webkit-device-pixel-ratio
và/hoặc thuộc tính window.devicePixelRatio
trong JavaScript, sau đó đặt thuộc tính meta target-densitydpi
thành device-dpi
. Điều này ngăn Android thực hiện việc mở rộng quy mô trên trang web của bạn và cho phép bạn thực hiện các điều chỉnh cần thiết cho mỗi mật độ, thông qua CSS và JavaScript.
Hãy xem tài liệu về WebView của Android để biết thêm thông tin về cách nhắm đến độ phân giải thiết bị.
Duyệt web ở chế độ toàn màn hình
Có hai giá trị siêu dữ liệu khác là iOS-sfic. apple-mobile-web-app-capable
và apple-mobile-web-app-status-bar-style
sẽ hiển thị nội dung trang ở chế độ toàn màn hình giống như ứng dụng và làm cho thanh trạng thái trở nên mờ:
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
Để biết thêm thông tin về tất cả các tuỳ chọn meta có sẵn, hãy xem tài liệu tham khảo trong Safari.
Biểu tượng trên màn hình chính
Các thiết bị iOS và Android cũng chấp nhận rel="apple-touch-icon"
(iOS) và rel="apple-touch-icon-precomposed"
(Android) cho đường liên kết. Các mã này sẽ tạo ra một biểu tượng giống ứng dụng hào nhoáng trên màn hình chính của người dùng khi họ đánh dấu trang web của bạn:
<link rel="apple-touch-icon"
href="/static/images/identity/HTML5_Badge_64.png" />
<link rel="apple-touch-icon-precomposed"
href="/static/images/identity/HTML5_Badge_64.png" />
Cách html5rock sử dụng thẻ meta dành cho thiết bị di động
Sau khi kết hợp tất cả, dưới đây là một đoạn mã từ phần <head>
của html5rocks:
<head>
...
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
<link rel="apple-touch-icon"
href="/static/images/identity/HTML5_Badge_64.png" />
<link rel="apple-touch-icon-precomposed"
href="/static/images/identity/HTML5_Badge_64.png" />
...
</head>
Bố cục dọc
Trên màn hình nhỏ, việc cuộn theo chiều dọc sẽ thuận tiện hơn nhiều so với chiều ngang. Giữ cho nội dung ở dạng một cột, bố cục dọc được ưu tiên cho thiết bị di động. Đối với html5rocks, chúng tôi đã sử dụng truy vấn nội dung nghe nhìn CSS3 để tạo một bố cục như vậy. Xin nhắc lại, mà không cần thay đổi mã đánh dấu.
Tối ưu hoá cho thiết bị di động
Hầu hết các hoạt động tối ưu hoá mà chúng ta đã thực hiện là những việc nên làm ngay từ đầu. Những việc như giảm số lượng yêu cầu mạng, nén JS/CSS, nén gzip (có sẵn miễn phí trên App Engine) và giảm thiểu thao tác DOM. Những kỹ thuật này là các phương pháp hay nhất phổ biến nhưng đôi khi bị bỏ qua khi người dùng truy cập một trang web.
Tự động ẩn thanh địa chỉ
Trình duyệt di động thiếu không gian màn hình so với trình duyệt dành cho máy tính. Tệ hơn nữa, trên các nền tảng khác nhau, đôi khi bạn sẽ thấy một thanh địa chỉ lớn ở đầu màn hình… ngay cả sau khi trang tải xong.
Một cách dễ dàng để xử lý vấn đề này là cuộn trang bằng JavaScript.
Ngay cả khi bạn chỉ di chuyển một pixel, thanh địa chỉ phiền phức cũng sẽ biến mất.
Để buộc ẩn thanh địa chỉ trên html5rocks, tôi đã đính kèm trình xử lý sự kiện onload
vào đối tượng window
và cuộn trang theo chiều dọc một pixel:
// Hides mobile browser's address bar when page is done loading.
window.addEventListener('load', function(e) {
setTimeout(function() { window.scrollTo(0, 1); }, 1);
}, false);
Chúng tôi cũng đã gói trình nghe này trong biến mẫu is_mobile
vì không cần đến trình nghe này trên máy tính.
Giảm số yêu cầu mạng, tiết kiệm băng thông
Một thực tế đã biết là việc giảm số lượng yêu cầu HTTP có thể cải thiện đáng kể hiệu suất. Thiết bị di động giới hạn thêm số lượng kết nối đồng thời mà trình duyệt có thể thực hiện, vì vậy, các trang web dành cho thiết bị di động sẽ được hưởng lợi nhiều hơn nữa từ việc giảm các yêu cầu không cần thiết này. Hơn nữa, việc giảm bớt từng byte là rất quan trọng vì băng thông thường bị giới hạn trên điện thoại. Bạn có thể khiến người dùng mất tiền!
Sau đây là một số phương pháp chúng tôi đã áp dụng để giảm thiểu các yêu cầu mạng và giảm băng thông trên html5rocks:
Xóa iframe - iframe chậm! Một lượng lớn độ trễ của chúng tôi đến từ các tiện ích chia sẻ của bên thứ ba (Buzz, Google Friend Connect, Twitter, Facebook) trên các trang hướng dẫn. Các API này được đưa vào thông qua thẻ
<script>
và tạo các iframe làm giảm tốc độ của trang. Các tiện ích đã bị xoá đối với thiết bị di động.display:none
– Trong một số trường hợp, chúng tôi đã ẩn mã đánh dấu nếu mã đó không phù hợp với hồ sơ dành cho thiết bị di động. Một ví dụ điển hình là 4 hộp bo tròn ở đầu trang chủ:
Các đường liên kết này bị thiếu trên trang web dành cho thiết bị di động. Điều quan trọng cần nhớ là trình duyệt vẫn đưa ra yêu cầu cho mỗi biểu tượng, mặc dù vùng chứa của các biểu tượng đó bị ẩn bằng display:none
. Do đó, việc chỉ ẩn các nút này là chưa đủ. Điều này không chỉ lãng phí băng thông mà người dùng thậm chí còn không thấy được kết quả của băng thông bị lãng phí đó! Giải pháp là tạo một boolean "is_mobile" trong mẫu Django để bỏ qua các phần HTML theo điều kiện.
Khi người dùng xem trang web trên thiết bị thông minh, các nút này sẽ bị bỏ qua.
Bộ nhớ đệm ứng dụng – Không chỉ hỗ trợ chúng ta khi không có kết nối mạng, mà còn giúp khởi động nhanh hơn.
Nén CSS/JS – chúng ta đang sử dụng trình nén YUI thay vì trình biên dịch Closure chủ yếu vì trình nén này xử lý cả CSS và JS. Một vấn đề mà chúng tôi gặp phải là các truy vấn phương tiện cùng dòng (truy vấn phương tiện xuất hiện bên trong biểu định kiểu) được đưa vào trình nén YUI 2.4.2 (xem vấn đề này). Sử dụng YUI Compressor 2.4.4+ đã khắc phục được sự cố.
Sử dụng sprite hình ảnh CSS nếu có thể.
Sử dụng pngcrush để nén hình ảnh.
Sử dụng dataURI cho hình ảnh nhỏ. Việc mã hoá Base64 sẽ làm tăng kích thước hình ảnh thêm khoảng 30% nhưng sẽ tiết kiệm yêu cầu mạng.
Tự động tải Google Tìm kiếm tuỳ chỉnh bằng một thẻ tập lệnh thay vì tải động bằng
google.load()
. Lệnh sau sẽ tạo thêm một yêu cầu.
<script src="//www.google.com/jsapi?autoload={"modules":[{"name":"search","version":"1"}]}"> </script>
- Trình in mã đẹp và Modernizr của chúng tôi được đưa vào mọi trang, ngay cả khi chúng không bao giờ được sử dụng. Modernizr rất tuyệt vời, nhưng nó chạy một loạt các bài kiểm thử trên mỗi lần tải. Một số kiểm thử đó thực hiện các sửa đổi tốn kém đối với DOM và làm chậm quá trình tải trang. Hiện tại, chúng tôi chỉ đưa các thư viện này vào các trang thực sự cần thiết. -2 yêu cầu :)
Các tuỳ chỉnh hiệu suất khác:
- Di chuyển tất cả JS xuống cuối trang (nếu có thể).
- Xoá thẻ
<style>
cùng dòng. - Truy vấn DOM được lưu vào bộ nhớ đệm và thao tác DOM được giảm thiểu – Mỗi khi bạn chạm vào DOM, trình duyệt sẽ thực hiện lưu lại. Việc kết hợp lại còn tốn kém hơn trên thiết bị di động.
- Chuyển mã phía máy khách không cần thiết sang máy chủ. Cụ thể, hộp đánh dấu để xem chế độ cài đặt kiểu điều hướng của trang hiện tại:
js var lis = document.querySelectorAll('header nav li'); var i = lis.length; while (i--) { var a = lis[i].querySelector('a'); var section = a.getAttribute("data-section"); if (new RegExp(section).test(document.location.href)) { a.className = 'current'; } }
- Các phần tử có chiều rộng cố định đã được thay thế bằng
width:100%
hoặcwidth:auto
linh hoạt.
Bộ nhớ đệm của ứng dụng
Phiên bản di động của html5rocks sử dụng Bộ nhớ đệm ứng dụng để tăng tốc độ tải ban đầu và cho phép người dùng đọc nội dung khi không có mạng.
Khi triển khai AppCache trên trang web, điều quan trọng là bạn không lưu tệp kê khai vào bộ nhớ đệm (rõ ràng trong chính tệp kê khai hoặc ngầm ẩn với các tiêu đề kiểm soát bộ nhớ đệm nặng). Nếu trình duyệt lưu tệp kê khai vào bộ nhớ đệm, thì việc gỡ lỗi sẽ trở thành một cơn ác mộng. iOS và Android đặc biệt hiệu quả trong việc lưu tệp này vào bộ nhớ đệm nhưng không cung cấp cách thuận tiện để xoá bộ nhớ đệm như các trình duyệt dành cho máy tính.
Để ngăn việc lưu vào bộ nhớ đệm đối với trang web của mình, trước tiên, chúng tôi thiết lập App Engine không bao giờ lưu các tệp kê khai vào bộ nhớ đệm:
- url: /(.*\.(appcache|manifest))
static_files: \1
mime_type: text/cache-manifest
upload: (.*\.(appcache|manifest))
expiration: "0s"
Thứ hai, chúng tôi đã sử dụng API JS để thông báo cho người dùng khi tệp kê khai mới tải xuống xong. Họ sẽ được nhắc làm mới trang:
window.applicationCache.addEventListener('updateready', function(e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
window.applicationCache.swapCache();
if (confirm('A new version of this site is available. Load it?')) {
window.location.reload();
}
}
}, false);
Để tiết kiệm lưu lượng truy cập mạng, hãy giữ tệp kê khai của bạn đơn giản. Tức là bạn không nên gọi ra mọi trang trên trang web của mình. Bạn chỉ cần liệt kê các tệp hình ảnh, CSS và JavaScript quan trọng. Điều cuối cùng bạn muốn làm là buộc trình duyệt di động tải một lượng lớn thành phần xuống trong mỗi lần cập nhật bộ nhớ đệm ứng dụng. Thay vào đó, hãy nhớ rằng trình duyệt sẽ ngầm lưu trang html vào bộ nhớ đệm khi người dùng truy cập (và trang này có chứa thuộc tính <html manifest="...">
).