Biểu mẫu HTML đã tồn tại từ rất lâu, nhưng thành thật mà nói, hầu hết các nhà phát triển vẫn đang viết những biểu mẫu cơ bản mà họ đã học từ nhiều năm trước. Trong khi đó, HTML đã âm thầm bổ sung các thuộc tính mạnh mẽ có thể giúp bạn tiết kiệm hàng tấn JavaScript. Tôi đang nói về việc xác thực, cải thiện trải nghiệm người dùng và các tính năng trợ năng đã có sẵn, sẵn sàng sử dụng.
Chúng được hỗ trợ tốt, thiết thực và sẽ giúp biểu mẫu của bạn tốt hơn ngay hôm nay.
Lưu ý:Danh sách hỗ trợ trình duyệt hiển thị phiên bản tối thiểu. Hầu hết các thuộc tính đều hoạt động trên tất cả các trình duyệt hiện đại.
Trước khi đi sâu hơn, đây là ví dụ mã đầy đủ dành cho bạn:
1.autocomplete
Điều này cho trình duyệt biết loại dữ liệu nào sẽ được đưa vào một trường để trình duyệt có thể tự động điền một cách thông minh.
< input type = "email" name = "email" autocomplete = "email" >
< input type = "tel" name = "phone" autocomplete = "tel" >
< input type = "text" name = "cc-number" autocomplete = "cc-number" >Người dùng thích tính năng tự động điền. Đừng bắt họ nhập email đến lần thứ một trăm. Hãy sử dụng các giá trị tự động điền phù hợp nhưemail,tel,street-address,cc-number,bday, và hàng chục giá trị khác nữa.
Hỗ trợ trình duyệt:Hỗ trợ phổ biến trên tất cả các trình duyệt hiện đại. Chrome 17+, Firefox 4+, Safari 5.1+, Edge 12+
2.autofocus
Tự động tập trung vào một mục nhập khi trang tải xong. Hoàn hảo cho hộp tìm kiếm hoặc biểu mẫu đăng nhập.
< kiểu đầu vào = "văn bản" tên = "tìm kiếm" tự động lấy nét>Hãy sử dụng tính năng này một cách tiết kiệm. Chỉ lấy nét tự động một trường và đảm bảo đó là trường mà người dùng thực sự muốn tương tác trước tiên.
Hỗ trợ trình duyệt:Chrome 5+, Firefox 4+, Safari 5+, Edge 12+, IE 10+
3.inputmode
Cho thiết bị di động biết nên hiển thị bàn phím nào. Điều này rất quan trọng đối với trải nghiệm người dùng trên thiết bị di động.
< kiểu đầu vào = "văn bản" chế độ đầu vào = "số" > < kiểu đầu vào = "văn bản" chế độ đầu vào = "thập phân" > < kiểu đầu vào = "văn bản" chế độ đầu vào = "email" > < kiểu đầu vào = "văn bản" chế độ đầu vào = "url" >
Ngay cả khi bạn sử dụngtype="text"vì lý do xác thực,inputmodenó vẫn cung cấp cho người dùng thiết bị di động bàn phím phù hợp. Sử dụngnumericcho mã PIN,decimalgiá cả,emailemail.
Hỗ trợ trình duyệt:Chrome 66+, Firefox 95+, Safari 12.1+, Edge 79+, iOS Safari 12.2+
4.pattern
Xác thực tùy chỉnh bằng regex. Tính năng này cực kỳ mạnh mẽ.
< input type = "text" pattern= "[0-9]{4}" placeholder= "Mã PIN (4 chữ số)" >
< input type = "text" pattern= "[A-Za-z]{3,}" placeholder= "Ít nhất 3 chữ cái" >Trình duyệt sẽ xác thực theo mẫu của bạn và hiển thị thông báo lỗi nếu không khớp. Sử dụngtitlethuộc tính để hiển thị thông báo lỗi hữu ích.
Hỗ trợ trình duyệt:Chrome 10+, Firefox 4+, Safari 10.1+, Edge 12+, IE 10+
5.title(có mẫu)
Khi sử dụng vớipattern,titlesẽ trở thành thông báo lỗi.
< input type = "text"
pattern= "[0-9]{4}"
title= "Vui lòng nhập chính xác 4 chữ số" >Đừng bỏ qua bước này. Thông báo lỗi mặc định rất tệ. Hãy cung cấp cho người dùng phản hồi hữu ích.
Hỗ trợ trình duyệt:Hỗ trợ chung trên mọi trình duyệt
6.minlengthvàmaxlength
Đặt giới hạn ký tự tối thiểu và tối đa. Không chỉ để xác thực, mà trình duyệt còn hiển thị bộ đếm ký tự trong một số trường hợp.
< kiểu nhập = "văn bản" độ dài tối thiểu = "3" độ dài tối đa = "20" >
< vùng văn bản độ dài tối thiểu = "10" độ dài tối đa = "500" > </ vùng văn bản >Người dùng sẽ nhận được phản hồi ngay lập tức nếu họ cố gắng gửi nội dung quá ngắn hoặc quá dài.
Hỗ trợ trình duyệt:
maxlength: Hỗ trợ toàn cầu (Chrome 4+, Firefox 4+, Safari 5+, IE 10+)minlength: Chrome 40+, Firefox 51+, Safari 10.1+, Edge 17+ (Không hỗ trợ IE)
7.minvàmax
Đối với dữ liệu đầu vào là số và ngày tháng, hãy đặt ranh giới.
< kiểu đầu vào = "số" min = "1" max = "100" > < kiểu đầu vào = "ngày" min = "2025-01-01" max = "2025-12-31" > < kiểu đầu vào = "thời gian" min = "09:00" max = "17:00" >
Trình duyệt sẽ không cho phép người dùng chọn các giá trị không hợp lệ. Không cần JavaScript.
Hỗ trợ trình duyệt:Chrome 10+, Firefox 16+, Safari 5+, Edge 12+, IE 10+
8.step
Kiểm soát mức tăng cho đầu vào số và bộ chọn ngày/giờ.
< input type = "number" step = "0.01" placeholder = "Price" >
< input type = "time" step = "900" > <!-- Khoảng thời gian 15 phút -->
< input type = "range" min = "0" max = "100" step = "5" >Sử dụngstep="0.01"cho tiền tệ,step="any"cho số thập phân mà không có hạn chế nào.
Hỗ trợ trình duyệt:Chrome 6+, Firefox 16+, Safari 5+, Edge 12+, IE 10+
9.multiple
Cho phép tải lên nhiều tệp hoặc nhiều địa chỉ email.
< input type = "file" nhiều>
< input type = "email" nhiều placeholder = "Phân tách email bằng dấu phẩy" >Đối với dữ liệu đầu vào là tệp, người dùng có thể chọn nhiều tệp cùng lúc. Đối với dữ liệu đầu vào là email, trình duyệt sẽ xác thực từng email trong danh sách được phân tách bằng dấu phẩy.
Hỗ trợ trình duyệt:Chrome 6+, Firefox 3.6+, Safari 4+, Edge 12+, IE 10+
10.accept
Hạn chế nhập tệp vào các loại tệp cụ thể.
< kiểu đầu vào = "tệp" chấp nhận = "hình ảnh/*" > < kiểu đầu vào = "tệp" chấp nhận = ".pdf,.doc,.docx" > < kiểu đầu vào = "tệp" chấp nhận = "hình ảnh/png,hình ảnh/jpeg" >
Sử dụngimage/*cho bất kỳ hình ảnh,video/*video hoặc loại MIME và phần mở rộng cụ thể nào. Trình chọn tệp sẽ lọc theo đó.
Hỗ trợ trình duyệt:Chrome 16+, Firefox 9+, Safari 6+, Edge 12+, IE 10+
11.formnovalidate
Bỏ qua xác thực cho nút gửi cụ thể. Rất hữu ích cho nút “Lưu bản nháp”.
<button type = "submit" >Gửi</button>
<button type = "submit" formnovalidate>Lưu bản nháp</button>Biểu mẫu sẽ được xác thực khi gửi bình thường nhưng bỏ qua xác thực khi lưu bản nháp.
Hỗ trợ trình duyệt:Chrome 10+, Firefox 4+, Safari 10.1+, Edge 12+, IE 10+
12.formaction
Thay đổi nơi gửi biểu mẫu khi sử dụng một nút cụ thể.
< form action = "/save" >
< button type = "submit" > Lưu </ button >
< button type = "submit" formaction = "/preview" > Xem trước </ button >
</ form >Các nút khác nhau có thể gửi đến các điểm cuối khác nhau mà không cần JavaScript.
Hỗ trợ trình duyệt:Chrome 10+, Firefox 4+, Safari 5.1+, Edge 12+, IE 10+
13.formmethod
Ghi đè phương thức của biểu mẫu cho một nút cụ thể.
< form method = "get" action = "/search" >
< button type = "submit" > Tìm kiếm </ button >
< button type = "submit" formmethod = "post" > Lưu tìm kiếm </ button >
</ form >Cho phép các nút khác nhau sử dụng các phương thức HTTP khác nhau (GET hoặc POST).
Hỗ trợ trình duyệt:Chrome 10+, Firefox 4+, Safari 5.1+, Edge 12+, IE 10+
14.formenctype
Ghi đè kiểu mã hóa của biểu mẫu cho nút gửi cụ thể.
< form >
< input type = "text" name = "title" >
< button type = "submit" > Lưu văn bản </ button >
< button type = "submit" formenctype = "multipart/form-data" > Tải tệp lên </ button >
</ form >Sử dụng tùy chọn này khi một nút cần xử lý việc tải tệp lên nhưng các nút khác thì không.
Hỗ trợ trình duyệt:Chrome 10+, Firefox 4+, Safari 5.1+, Edge 12+, IE 10+
15.formtarget
Chỉ định nơi hiển thị phản hồi cho nút gửi cụ thể.
< form action = "/submit" >
< button type = "submit" > Gửi </ button >
< button type = "submit" formtarget = "_blank" > Gửi trong Tab mới </ button >
</ form >Giá trị bao gồm_self,_blank,_parent,_top, hoặc một khung được đặt tên. Hữu ích cho các nút xem trước hoặc khi bạn muốn giữ trang hiện tại mở.
Hỗ trợ trình duyệt:Chrome 10+, Firefox 4+, Safari 5.1+, Edge 12+, IE 10+
16.readonly
Làm cho đầu vào không thể thay đổi nhưng vẫn gửi giá trị của nó. Khác vớidisabled.
< kiểu đầu vào = "văn bản" giá trị = "Đơn hàng #12345" chỉ đọc >Sử dụngreadonlykhi bạn muốn giá trị được gửi đi nhưng không muốn người dùng thay đổi nó. Sử dụngdisabledkhi bạn không muốn giá trị được gửi đi chút nào.
Hỗ trợ trình duyệt:Hỗ trợ chung trên mọi trình duyệt
17.placeholder
Hiển thị văn bản gợi ý bên trong đầu vào. Có thể bạn đã sử dụng tính năng này rồi, nhưng hãy sử dụng đúng cách.
< kiểu đầu vào = "email" giữ chỗ = "bạn@example.com" >Không sử dụng placeholder để thay thế nhãn. Placeholder sẽ biến mất khi người dùng bắt đầu nhập. Luôn sử dụng<label>các phần tử phù hợp.
Hỗ trợ trình duyệt:Chrome 10+, Firefox 4+, Safari 5+, Edge 12+, IE 10+
18.listvà<datalist>
Tạo danh sách thả xuống các gợi ý mà người dùng có thể chọn hoặc bỏ qua.
< input type = "text" list = "browsers" >
< datalist id = "browsers" >
< option value = "Chrome" >
< option value = "Firefox" >
< option value = "Safari" >
< option value = "Edge" >
</ datalist >Giống như tính năng tự động hoàn thành nhưng bạn kiểm soát các gợi ý. Người dùng có thể tự do nhập hoặc chọn từ danh sách của bạn.
Hỗ trợ trình duyệt:Chrome 20+, Firefox 4+, Safari 12.1+, Edge 12+ (Không hỗ trợ IE)
19.spellcheck
Kiểm soát xem trình duyệt có kiểm tra chính tả trường này hay không.
< textarea spellcheck = "true" > </ textarea >
< input type = "text" name = "code" spellcheck = "false" >Tắt tính năng này khi nhập mã, tên người dùng hoặc các trường kỹ thuật. Giữ nguyên tính năng này khi nhập văn bản và nội dung.
Hỗ trợ trình duyệt:Chrome 10+, Firefox 2+, Safari 3.1+, Edge 12+, IE 10+
20.enterkeyhint
Thay đổi nhãn phím Enter trên bàn phím di động.
< input type = "tìm kiếm" enterkeyhint = "tìm kiếm" >
< input type = "văn bản" enterkeyhint = "tiếp theo" >
<textarea enterkeyhint = "gửi" ></textarea>Các giá trị bao gồmenter,done,go,next,previous,search,send. Điều này chỉ dành cho trải nghiệm người dùng trên thiết bị di động nhưng tạo ra sự khác biệt lớn.
Hỗ trợ trình duyệt:Chrome 77+, Firefox 94+, Safari 13.1+, Edge 79+, iOS Safari 13.4+
21.dirname
Tự động gửi hướng văn bản đầu vào. Rất quan trọng đối với các biểu mẫu quốc tế.
<input type = "text" name = "comment" dirname = "comment.dir" >Khi biểu mẫu được gửi, nó sẽ bao gồm cảcomment(giá trị) vàcomment.dir(hoặcltr)rtl. Điều cần thiết để xử lý đúng các ngôn ngữ viết từ phải sang trái như tiếng Ả Rập hoặc tiếng Do Thái.
Hỗ trợ trình duyệt:Chrome 17+, Safari 6+, Edge 79+ (Không hỗ trợ Firefox hoặc IE)
22.form
Liên kết đầu vào với biểu mẫu ngay cả khi nó nằm ngoài<form>phần tử.
<form id = "myForm" action = "/submit" >
<input type = "text" name = "username" >
</form>
<input type="email" name="email" form="myForm">
<button type="submit" form="myForm">Gửi</button>Hữu ích khi biểu mẫu của bạn nằm ở một phần của trang nhưng bạn cần nhập dữ liệu hoặc nút ở nơi khác.formThuộc tính này sẽ liên kết chúng lại với nhau.
Hỗ trợ trình duyệt:Chrome 10+, Firefox 4+, Safari 5.1+, Edge 12+, IE 11+
23.capture
Đối với đầu vào tệp di động, hãy mở trực tiếp camera thay vì trình chọn tệp.
< input type = "file" accept = "image/*" capture = "environment" >
< input type = "file" accept = "video/*" capture = "user" >Dùngcapture="user"cho camera trước,capture="environment"camera sau. Hoàn hảo cho các ứng dụng mà người dùng cần chụp ảnh hoặc quay video trực tiếp.
Trình duyệt hỗ trợ:Chrome 53+ (Android), Safari 11+ (iOS), Samsung Internet 6.2+. Trình duyệt máy tính để bàn bỏ qua thuộc tính này.
24.novalidate
Vô hiệu hóa xác thực HTML5 cho toàn bộ biểu mẫu.
< form novalidate >
< input type = "email" required >
< button type = "submit" > Gửi </ button >
</ form >Sử dụng tùy chọn này khi bạn xử lý xác thực hoàn toàn bằng JavaScript hoặc muốn triển khai logic xác thực tùy chỉnh.
Hỗ trợ trình duyệt:Chrome 10+, Firefox 4+, Safari 10.1+, Edge 12+, IE 10+
25.autocapitalize
Kiểm soát việc viết hoa tự động trên bàn phím di động.
< input type = "text" autocapitalize= "words" >
< input type = "text" autocapitalize= "sentences" >
< input type = "email" autocapitalize= "none" >Giá trị:none,sentences,words,characters. Sử dụngnonecho email và tên người dùng,wordscho tên,sentencescho văn bản thông thường.
Trình duyệt hỗ trợ:Safari 5+ (iOS), Chrome 43+, Edge 79+. Firefox không hỗ trợ thuộc tính này.
26.size
Đặt chiều rộng hiển thị của đầu vào theo ký tự.
< kiểu đầu vào = "văn bản" kích thước = "30" > < kiểu đầu vào = "văn bản" kích thước = "5" chỗ giữ chỗ = "Mã" >
Tùy chọn này không giới hạn dữ liệu đầu vào, mà chỉ kiểm soát độ rộng hiển thị. Sử dụngmaxlengthnếu bạn muốn giới hạn độ dài dữ liệu đầu vào thực tế.
Hỗ trợ trình duyệt:Hỗ trợ chung trên mọi trình duyệt
27.colsvàrows
Kiểm soát kích thước hiển thị của vùng văn bản.
< textarea cols = "50" rows = "10" > </ textarea >colsthiết lập chiều rộng tính bằng ký tự,rowsthiết lập chiều cao tính bằng dòng. Người dùng vẫn có thể thay đổi kích thước nếu bạn không thiết lập CSS để ngăn chặn điều này.
Hỗ trợ trình duyệt:Hỗ trợ chung trên mọi trình duyệt
28.wrap
Kiểm soát cách ngắt dòng văn bản trong vùng văn bản khi gửi.
< textarea wrap = "mềm" > </ textarea >
< textarea wrap = "cứng" cols = "40" > </ textarea >softkhông thêm ngắt dòng vào văn bản đã gửi,hardmà thêm ngắt dòng theocolschiều rộng đã chỉ định. Hầu hết thời gian bạn muốnsoft.
Hỗ trợ trình duyệt:Hỗ trợ chung trên mọi trình duyệt
29.disabled
Vô hiệu hóa hoàn toàn dữ liệu đầu vào. Dữ liệu sẽ không thể chỉnh sửa hoặc gửi đi.
<input type = "text" disabled>
<button type = "submit" disabled>Gửi</button>Khác vớireadonly. Các mục nhập bị vô hiệu hóa sẽ không gửi giá trị của chúng và thường hiển thị màu xám. Sử dụng khi các trường tạm thời không khả dụng.
Hỗ trợ trình duyệt:Hỗ trợ chung trên mọi trình duyệt
30.required
Bắt buộc phải điền một trường trước khi gửi biểu mẫu.
< input type = "text" required >
< input type = "email" required >
< select required >
< option value = "" > Chọn một... </ option >
< option value = "1" > Tùy chọn 1 </ option >
</ select >Trình duyệt sẽ hiển thị lỗi nếu người dùng cố gắng gửi mà không điền đầy đủ các trường bắt buộc. Hoạt động với mọi kiểu nhập liệu.
Hỗ trợ trình duyệt:Chrome 10+, Firefox 4+, Safari 10.1+, Edge 12+, IE 10+
Tại sao những điều này quan trọng
Vấn đề là. Những thuộc tính này không hề mới mẻ hay cầu kỳ. Chúng được tích hợp sẵn trong HTML, được trình duyệt hỗ trợ, và chúng giải quyết những vấn đề thực tế. Hầu hết các nhà phát triển đều tìm đến JavaScript khi HTML đã có câu trả lời.
Sử dụng các thuộc tính này và bạn sẽ nhận được:
- Trải nghiệm người dùng tốt hơn với ít mã hơn
- Xác thực trình duyệt gốc hoạt động ở mọi nơi
- Các tính năng trợ năng được tích hợp sẵn
- Bàn phím và tương tác được tối ưu hóa cho thiết bị di động
- Ít JavaScript để duy trì
Tóm tắt hỗ trợ trình duyệt
Hỗ trợ tuyệt vời (Hoạt động ở mọi nơi):
autocomplete,autofocus,title,readonly,placeholder,size,cols,rows,wrap,disabled,spellcheck- Xác thực HTML5:
required,pattern,min,max,step,multiple,accept - Nút biểu mẫu ghi đè:
formaction,formmethod,formenctype,formtarget,formnovalidate,novalidate
Chỉ dành cho trình duyệt hiện đại:
inputmode: Chrome 66+, Firefox 95+, Safari 12.1+enterkeyhint: Chrome 77+, Firefox 94+, Safari 13.1+minlength: Chrome 40+, Firefox 51+, Safari 10.1+ (Không có IE)datalist: Chrome 20+, Firefox 4+, Safari 12.1+ (Không có IE)
Giới hạn/Dành riêng cho thiết bị di động:
capture: Chỉ dành cho trình duyệt di động (Chrome Android 53+, iOS Safari 11+)autocapitalize: Safari/iOS, Chrome 43+ (Không có Firefox)dirname: Chrome 17+, Safari 6+ (Không có Firefox hoặc IE)
Bắt đầu sử dụng chúng ngay hôm nay
Bạn không cần phải sử dụng cả 30 nút cùng lúc. Hãy chọn một vài nút phù hợp với vấn đề bạn đang gặp phải. Thêminputmodevào biểu mẫu di động. Sử dụngpatternthay vì viết xác thực tùy chỉnh. Thửformnovalidatedùng cho các nút nháp. Thêm vàocapturekhi tải lên bằng camera.
Đây không phải là những tính năng chưa được biết đến đang chờ trình duyệt hỗ trợ. Hãy bắt đầu sử dụng chúng.
<!-- Xác thực -->
< đầu vào yêu cầu minlength = "3" maxlength = "20" mẫu = "[A-Za-z]+" >
< mẫu novalidate >
<!-- Trải nghiệm người dùng di động --> <input inputmode="numeric" enterkeyhint="next" autocomplete="tel" autocapitalize="words"> <input type="file" accept="image/*" capture="environment"><!-- Tải tệp lên --> <input type="file" accept="image/*" nhiều><!-- Nút nâng cao --> <button formnovalidate>Lưu bản nháp</button> <button formaction="/preview" formtarget="_blank">Xem trước</button> <button formmethod="delete">Xóa</button> <button formenctype="multipart/form-data">Tải lên</button><!-- Gợi ý --> <input list="suggestions"> <datalist id="suggestions"> <option value="Tùy chọn 1"> <option value="Tùy chọn 2"> </datalist><!-- Textarea --> <textarea cols="50" rows="10" wrap="soft" spellcheck="true"></textarea><!-- Trạng thái đầu vào --> <đầu vào chỉ đọc> <đầu vào bị vô hiệu hóa><!-- Hướng văn bản --> <input dirname="comment.dir">
16 Tính năng HTML & JS
Các tính năng giúp xây dựng ứng dụng web hiện đại thực sự thú vị. HTML và JavaScript đã phát triển rất nhiều. Vài năm gần đây đã chứng kiến sự phát triển vượt bậc của lập trình web. Chúng ta có nhiều tính năng mới hoạt động liền mạch. Chúng thay đổi hoàn toàn cách chúng ta xây dựng ứng dụng. Bài viết này sẽ chia sẻ 16 tính năng HTML và JavaScript hoạt động hoàn hảo cùng nhau. Đây không phải là các tính năng nhàm chán ít người dùng. Đây là những công cụ thực tế, hữu ích. Chúng sẽ giúp công việc của bạn dễ dàng hơn mỗi ngày.
Dưới đây là các ví dụ mã hoạt động thực tế:
//codepen.io/web-strategist/embed/emJyNLj?
1. Phần tử Dialog với showModal()
Phần tử <dialog> gốc cuối cùng đã có mặt. Đây là một tính năng khiến bạn tự hỏi làm thế nào mình đã từng xây dựng các modal mà không có nó.
<dialog id="myDialog">
<h2>This is a modal</h2>
<button onclick="document.getElementById('myDialog').close()">Close</button>
</dialog>
<button onclick="document.getElementById('myDialog').showModal()">Open Modal</button>Điều làm cho tính năng này tốt:
- Bẫy lấy nét (Focus trapping): Khi bạn mở một modal bằng
showModal(), tiêu điểm sẽ tự động bị giữ bên trong. Bạn có thể điều hướng qua các phần tử trong hộp thoại bằng phím Tab. Tiêu điểm sẽ quay vòng lại. - Lớp phủ (Backdrop): Bạn nhận được một pseudo-element
::backdropmiễn phí. Bạn có thể tùy chỉnh kiểu dáng của nó. - Phím ESC: Nhấn phím ESC sẽ tự động đóng modal. Không cần JavaScript.
- Lớp trên cùng (Top layer): Hộp thoại xuất hiện trên tất cả các phần tử khác. Không cần phải xử lý xung đột
z-index.
Phần tốt nhất là nó hoàn toàn dễ tiếp cận ngay từ đầu. Trình duyệt xử lý tất cả các thuộc tính ARIA, quản lý tiêu điểm và tương tác bàn phím cho bạn.
2. Popover API
Trong khi dialog rất tốt cho các tương tác modal, Popover API hoàn hảo cho các lớp phủ không phải modal. Ví dụ như tooltips, menu và thông báo.
<button popovertarget="myPopover">Toggle Popover</button>
<div id="myPopover" popover>
<p>This is popover content.</p>
</div>Không cần JavaScript. Chỉ cần các thuộc tính HTML, bạn sẽ có được:
- Tắt nhẹ (Light dismiss) – nhấp ra ngoài để đóng.
- Hỗ trợ phím ESC.
- Hiển thị ở lớp trên cùng (Top layer rendering).
- Định vị tự động.
Bạn cũng có thể điều khiển nó bằng JavaScript nếu cần:
const popover = document.getElementById('myPopover');
popover.showPopover();
popover.hidePopover();
popover.togglePopover();Sự khác biệt giữa dialog và popover là gì? Dialog dành cho các tương tác quan trọng cần bẫy lấy nét. Popover dành cho nội dung bổ sung không cần chặn phần còn lại của trang.
3. IntersectionObserver
Đây là tính năng yêu thích trong số tất cả các API observer. IntersectionObserver cho bạn biết khi một phần tử đi vào hoặc rời khỏi khung nhìn. Nó hoàn hảo cho việc tải ảnh lười biếng (lazy loading images), cuộn vô hạn (infinite scrolling) và hiệu ứng cuộn (scroll animations).
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// Phần tử nằm trong khung nhìn
entry.target.classList.add('visible');
}
});
});
document.querySelectorAll('.lazy-load').forEach(el => {
observer.observe(el);
});Tại sao nó tuyệt vời:
- Không còn cần lắng nghe sự kiện cuộn (scroll event listeners).
- Hiệu suất tốt hơn nhiều.
- Hỗ trợ tích hợp cho các ngưỡng (thresholds) – kích hoạt khi 50% hiển thị, 100% hiển thị, v.v.
- Có thể quan sát nhiều phần tử với một observer.
Trường hợp sử dụng thực tế: Tải ảnh lười biếng khi chúng xuất hiện trong khung nhìn.
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
imageObserver.unobserve(img);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => {
imageObserver.observe(img);
});Khi ảnh tải xong, chúng ta ngừng quan sát nó. Sạch sẽ, hiệu quả và có hiệu suất cao.
4. ResizeObserver
ResizeObserver cho phép bạn theo dõi sự thay đổi kích thước trên bất kỳ phần tử DOM nào. Điều này rất quan trọng đối với các thành phần phản hồi cần điều chỉnh theo kích thước vùng chứa của chúng, không chỉ kích thước khung nhìn.
const observer = new ResizeObserver(entries => {
entries.forEach(entry => {
const { width, height } = entry.contentRect;
console.log(`Element size: ${width}px × ${height}px`);
if (width < 400) {
entry.target.classList.add('small');
} else {
entry.target.classList.remove('small');
}
});
});
observer.observe(document.querySelector('.resizable-panel'));Tại sao nó tốt hơn window.resize:
- Hoạt động trên từng phần tử riêng lẻ, không chỉ cửa sổ.
- Chính xác và hiệu quả hơn.
- Hoàn hảo cho các kiến trúc dựa trên thành phần.
Tuyệt vời cho các biểu đồ, lưới hoặc bất kỳ thành phần nào cần thích ứng với kích thước vùng chứa thực tế của nó.
5. MutationObserver
MutationObserver theo dõi các thay đổi đối với cây DOM. Khi các phần tử được thêm, xóa hoặc thuộc tính thay đổi, bạn sẽ nhận được thông báo.
const observer = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
if (mutation.type === 'childList') {
console.log('Children added or removed');
}
if (mutation.type === 'attributes') {
console.log('Attribute changed:', mutation.attributeName);
}
});
});
observer.observe(document.getElementById('container'), {
childList: true,
attributes: true,
subtree: true
});Các trường hợp sử dụng:
- Phát hiện khi có bình luận mới được thêm vào một feed.
- Theo dõi nội dung được tải động.
- Xây dựng công cụ phát triển hoặc tiện ích mở rộng trình duyệt.
Cả ba observer (Intersection, Resize, Mutation) đều tuân theo cùng một mẫu. Điều này giúp chúng dễ học một khi bạn hiểu một trong số chúng.
6. FormData API
FormData giúp việc tải tệp và gửi biểu mẫu dễ dàng hơn nhiều. Bạn có thể xây dựng dữ liệu biểu mẫu theo chương trình hoặc lấy nó từ một biểu mẫu hiện có.
// Từ một biểu mẫu hiện có
const form = document.querySelector('form');
const formData = new FormData(form);
// Hoặc xây dựng thủ công
const formData = new FormData();
formData.append('username', 'john');
formData.append('email', 'john@example.com');
// Thêm tệp
const fileInput = document.querySelector('#fileInput');
formData.append('avatar', fileInput.files[0]);
// Gửi đi
fetch('/upload', {
method: 'POST',
body: formData
});Không cần đặt Content-Type. Trình duyệt tự động xử lý nó khi bạn sử dụng FormData.
Đối với nhiều tệp:
const files = document.querySelector('#files').files;
const formData = new FormData();
Array.from(files).forEach(file => {
formData.append('files', file);
});
fetch('/upload-multiple', {
method: 'POST',
body: formData
});Trước FormData, việc tải tệp là một cơn ác mộng. Bây giờ nó chỉ là một vài dòng mã.
7. AbortController
AbortController cho phép bạn hủy các yêu cầu fetch (và các hoạt động bất đồng bộ khác) đang diễn ra. Điều này rất quan trọng cho các tính năng tìm kiếm, ngăn chặn các yêu cầu trùng lặp và xử lý thời gian chờ.
const controller = new AbortController();
fetch('/api/data', {
signal: controller.signal
})
.then(response => response.json())
.then(data => console.log(data))
.catch(err => {
if (err.name === 'AbortError') {
console.log('Fetch aborted');
}
});
// Hủy yêu cầu
controller.abort();Ví dụ thực tế: Tìm kiếm với debounce
let controller;
function search(query) {
// Hủy yêu cầu trước đó
if (controller) {
controller.abort();
}
// Tạo controller mới
controller = new AbortController();
fetch(`/search?q=${query}`, {
signal: controller.signal
})
.then(response => response.json())
.then(results => displayResults(results))
.catch(err => {
if (err.name !== 'AbortError') {
console.error(err);
}
});
}Mỗi khi người dùng nhập, yêu cầu trước đó sẽ bị hủy. Chỉ yêu cầu mới nhất mới quan trọng. Điều này giúp tiết kiệm băng thông và ngăn chặn kết quả lỗi thời hiển thị.
8. localStorage và sessionStorage
Web Storage API cung cấp một kho lưu trữ khóa-giá trị đơn giản. Nó lưu trữ dữ liệu trong trình duyệt.
localStorage: Duy trì cho đến khi bị xóa rõ ràng.sessionStorage: Bị xóa khi tab đóng.
// Lưu dữ liệu
localStorage.setItem('theme', 'dark');
localStorage.setItem('user', JSON.stringify({ name: 'John', age: 30 }));
// Lấy dữ liệu
const theme = localStorage.getItem('theme');
const user = JSON.parse(localStorage.getItem('user'));
// Xóa dữ liệu
localStorage.removeItem('theme');
localStorage.clear(); // Xóa tất cảsessionStorage hoạt động chính xác tương tự:
sessionStorage.setItem('sessionID', 'abc123');
const sessionID = sessionStorage.getItem('sessionID');Hoàn hảo cho:
- Tùy chọn người dùng (chủ đề, ngôn ngữ, v.v.).
- Giỏ hàng.
- Dữ liệu biểu mẫu (sử dụng
sessionStoragecho dữ liệu nhạy cảm). - Lưu trữ phản hồi API.
Giới hạn: Thường là 5–10MB cho mỗi nguồn gốc. Nếu bạn cần nhiều dung lượng hơn hoặc các truy vấn phức tạp, hãy sử dụng IndexedDB thay thế.
9. IndexedDB
IndexedDB là một cơ sở dữ liệu phía client mạnh mẽ. Nó dùng để lưu trữ lượng lớn dữ liệu có cấu trúc, bao gồm tệp và blobs.
// Mở cơ sở dữ liệu
const request = indexedDB.open('myDatabase', 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
const objectStore = db.createObjectStore('users', { keyPath: 'id' });
objectStore.createIndex('email', 'email', { unique: true });
};
request.onsuccess = (event) => {
const db = event.target.result;
// Thêm dữ liệu
const transaction = db.transaction(['users'], 'readwrite');
const objectStore = transaction.objectStore('users');
objectStore.add({ id: 1, name: 'John', email: 'john@example.com' });
// Đọc dữ liệu
const getRequest = objectStore.get(1);
getRequest.onsuccess = () => {
console.log(getRequest.result);
};
};Khi nào nên sử dụng IndexedDB:
- Ứng dụng ưu tiên ngoại tuyến (Offline-first apps).
- Tập dữ liệu lớn (hàng trăm MB).
- Truy vấn phức tạp với các chỉ mục.
- Lưu trữ tệp và blobs.
Khi nào nên sử dụng localStorage:
- Các cặp khóa-giá trị đơn giản.
- Lượng dữ liệu nhỏ (< 5MB).
- Không cần truy vấn phức tạp.
IndexedDB có đường cong học tập dốc hơn. Nhưng đối với bất cứ điều gì ngoài lưu trữ cơ bản, nó là lựa chọn đúng đắn.
10. Fetch API với Async/Await
Fetch API đã thay thế XMLHttpRequest. Với async/await, việc thực hiện các yêu cầu HTTP sạch sẽ hơn bao giờ hết.
async function fetchData() {
try {
const response = await fetch('/api/users');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Fetch failed:', error);
}
}Yêu cầu POST với JSON:
async function createUser(userData) {
const response = await fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(userData)
});
return await response.json();
}Kết hợp với AbortController:
async function fetchWithTimeout(url, timeout = 5000) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
signal: controller.signal
});
clearTimeout(timeoutId);
return await response.json();
} catch (error) {
if (error.name === 'AbortError') {
throw new Error('Request timeout');
}
throw error;
}
}Sạch sẽ, dễ đọc và mạnh mẽ.
11. Custom Elements (Web Components)
Custom Elements cho phép bạn tạo các phần tử HTML có thể tái sử dụng. Chúng có chức năng riêng được đóng gói.
class UserCard extends HTMLElement {
connectedCallback() {
const name = this.getAttribute('name');
const email = this.getAttribute('email');
this.innerHTML = `
<div class="user-card">
<h3>${name}</h3>
<p>${email}</p>
</div>
`;
}
}
customElements.define('user-card', UserCard);Sử dụng nó trong HTML:
<user-card name="John Doe" email="john@example.com"></user-card>Với Shadow DOM để đóng gói:
class FancyButton extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.shadowRoot.innerHTML = `
<style>
button {
background: blue;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
}
</style>
<button><slot></slot></button>
`;
}
}
customElements.define('fancy-button', FancyButton);Sử dụng nó:
<fancy-button>Click Me</fancy-button>Các kiểu dáng được đóng gói. Chúng sẽ không bị rò rỉ ra ngoài hoặc bị ảnh hưởng bởi CSS bên ngoài.
12. Template Element
Phần tử <template> chứa HTML. Nó sẽ không được hiển thị cho đến khi bạn sao chép và chèn nó bằng JavaScript.
<template id="user-template">
<div class="user">
<img class="avatar" src="" alt="">
<h3 class="name"></h3>
<p class="email"></p>
</div>
</template>
<div id="user-list"></div>Sao chép và sử dụng nó:
const template = document.getElementById('user-template');
const userList = document.getElementById('user-list');
function addUser(user) {
const clone = template.content.cloneNode(true);
clone.querySelector('.avatar').src = user.avatar;
clone.querySelector('.name').textContent = user.name;
clone.querySelector('.email').textContent = user.email;
userList.appendChild(clone);
}
// Thêm người dùng
addUser({ name: 'John', email: 'john@example.com', avatar: '/avatar1.jpg' });
addUser({ name: 'Jane', email: 'jane@example.com', avatar: '/avatar2.jpg' });Tại sao nó tuyệt vời:
- Cấu trúc HTML có thể tái sử dụng.
- Không được hiển thị cho đến khi cần.
- Hoàn hảo cho các danh sách động.
- Hoạt động tốt với Custom Elements.
13. Data Attributes
Các thuộc tính dữ liệu (Data attributes) cho phép bạn lưu trữ dữ liệu tùy chỉnh trực tiếp trong các phần tử HTML.
<button
data-user-id="123"
data-action="delete"
data-confirm="Are you sure?">
Delete User
</button>Truy cập trong JavaScript:
const button = document.querySelector('button');
// Sử dụng dataset
console.log(button.dataset.userId); // "123"
console.log(button.dataset.action); // "delete"
console.log(button.dataset.confirm); // "Are you sure?"
// Camel case cho các tên có dấu gạch ngang
// data-user-id trở thành dataset.userIdĐặt thuộc tính dữ liệu:
button.dataset.userId = '456';
button.dataset.newProp = 'value';Ví dụ thực tế: Ủy quyền sự kiện (Event delegation)
document.addEventListener('click', (e) => {
const button = e.target.closest('[data-action]');
if (!button) return;
const action = button.dataset.action;
const userId = button.dataset.userId;
if (action === 'delete') {
if (confirm(button.dataset.confirm)) {
deleteUser(userId);
}
}
});Không cần nhiều trình lắng nghe sự kiện. Một trình lắng nghe xử lý tất cả các nút có thuộc tính dữ liệu.
14. requestAnimationFrame
requestAnimationFrame là cách đúng đắn để thực hiện các hoạt ảnh và cập nhật hình ảnh trong JavaScript.
function animate() {
// Cập nhật hoạt ảnh
box.style.transform = `translateX(${position}px)`;
position += 2;
if (position < 500) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);Tại sao nó tốt hơn setTimeout/setInterval:
- Đồng bộ hóa với tốc độ làm mới của trình duyệt (thường là 60fps).
- Tự động tạm dừng khi tab không hiển thị.
- Hiệu suất cao hơn và tiết kiệm pin hơn.
Ví dụ cuộn mượt:
function smoothScrollTo(element) {
const targetPosition = element.offsetTop;
const startPosition = window.pageYOffset;
const distance = targetPosition - startPosition;
const duration = 1000;
let start = null;
function animation(currentTime) {
if (start === null) start = currentTime;
const timeElapsed = currentTime - start;
const progress = Math.min(timeElapsed / duration, 1);
window.scrollTo(0, startPosition + distance * progress);
if (timeElapsed < duration) {
requestAnimationFrame(animation);
}
}
requestAnimationFrame(animation);
}15. Clipboard API
Clipboard API giúp việc sao chép và dán văn bản siêu dễ dàng. Nó có các quyền người dùng phù hợp.
Sao chép vào bảng tạm:
async function copyToClipboard(text) {
try {
await navigator.clipboard.writeText(text);
console.log('Copied to clipboard');
} catch (err) {
console.error('Failed to copy:', err);
}
}Đọc từ bảng tạm:
async function pasteFromClipboard() {
try {
const text = await navigator.clipboard.readText();
console.log('Pasted:', text);
return text;
} catch (err) {
console.error('Failed to paste:', err);
}
}Ví dụ nút sao chép:
<button onclick="copyCode()">Copy Code</button>
<pre><code id="code">const x = 10;</code></pre>
async function copyCode() {
const code = document.getElementById('code').textContent;
await navigator.clipboard.writeText(code);
// Phản hồi trực quan
event.target.textContent = 'Copied!';
setTimeout(() => {
event.target.textContent = 'Copy Code';
}, 2000);
}Lưu ý: Đọc từ bảng tạm yêu cầu quyền của người dùng. Ghi thì không (trong hầu hết các trường hợp).
16. Geolocation API
Geolocation API cho phép bạn lấy vị trí của người dùng (với sự cho phép).
function getLocation() {
if ('geolocation' in navigator) {
navigator.geolocation.getCurrentPosition(
(position) => {
const lat = position.coords.latitude;
const lon = position.coords.longitude;
console.log(`Location: ${lat}, ${lon}`);
},
(error) => {
console.error('Error getting location:', error.message);
}
);
} else {
console.log('Geolocation not supported');
}
}Theo dõi vị trí (để theo dõi):
const watchId = navigator.geolocation.watchPosition(
(position) => {
updateMap(position.coords.latitude, position.coords.longitude);
},
(error) => {
console.error(error);
},
{
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
}
);
// Dừng theo dõi
navigator.geolocation.clearWatch(watchId);Các trường hợp sử dụng:
- Công cụ định vị cửa hàng.
- Ứng dụng thời tiết.
- Theo dõi giao hàng.
- Các dịch vụ dựa trên vị trí.
Trình duyệt sẽ yêu cầu quyền trước khi chia sẻ dữ liệu vị trí.
Lời kết
16 tính năng này giải quyết các vấn đề thực tế mà các nhà phát triển phải đối mặt hàng ngày. Nền tảng web đã trưởng thành rất nhiều trong vài năm qua. Hầu hết các tính năng này hoạt động trên tất cả các trình duyệt hiện đại. Nếu bạn vẫn đang sử dụng các mẫu cũ hoặc thư viện nặng cho các chức năng cơ bản, đã đến lúc thử các API gốc này.
Hãy bắt đầu với một hoặc hai tính năng giải quyết các vấn đề cấp bách của bạn. Sau đó, dần dần tìm hiểu phần còn lại. Hãy tin tôi, một khi bạn bắt đầu sử dụng các tính năng này, bạn sẽ tự hỏi làm thế nào mình đã từng xây dựng ứng dụng mà không có chúng.
15 tính năng gốc mạnh mẽ thay thế thư viện
HTML vẫn chứa đựng nhiều tính năng hữu ích. Hầu hết các nhà phát triển thường bỏ qua chúng. Điều này đúng ngay cả sau nhiều thập kỷ.
Mọi người dùng <div> và <span> hàng ngày. Tuy nhiên, HTML đã phát triển âm thầm. Nó giới thiệu các tính năng mới. Những tính năng này giải quyết vấn đề thực tế. Chúng không cần bất kỳ dòng JavaScript nào.
Hôm nay, chúng tôi sẽ phân tích 15 tính năng HTML bị đánh giá thấp. Chúng có thể giúp trang web của bạn nhanh hơn. Chúng cũng làm trang web thông minh hơn và mạnh mẽ hơn. Tất cả chỉ với HTML thuần túy. Không cần framework. Không cần thủ thuật. Chỉ là sức mạnh tự nhiên của HTML.
<details>và<summary>Tính năng này cho phép nội dung có thể thu gọn. Nó không cần JavaScript. Đây là giải pháp lý tưởng cho các câu hỏi thường gặp (FAQ). Nó cũng phù hợp cho tài liệu. Hoặc bất kỳ nội dung nào bạn muốn bật/tắt hiển thị. Chức năng mở rộng/thu gọn là tự nhiên. Không cần JavaScript. Điều này giúp tổ chức thông tin hiệu quả, cải thiện trải nghiệm người dùng khi duyệt các phần FAQ hoặc tài liệu dài mà không cần tải thêm thư viện.<details> <summary>Show Code Example</summary> <p>Here’s the hidden content revealed on click!</p> </details>contenteditableThuộc tính này biến bất kỳ phần tử nào thành một hộp văn bản có thể chỉnh sửa. Nó rất hữu ích cho các bản thử nghiệm. Nó cũng dùng cho các trình chỉnh sửa giống CMS. Hoặc cho việc chỉnh sửa nội dung trực tiếp trên trình duyệt mà không cần framework JavaScript. Người dùng có thể sửa đổi nội dung trực tiếp ngay trong trình duyệt. Điều này tăng cường khả năng tương tác và linh hoạt cho các ứng dụng web.<p contenteditable="true">Click and edit me!</p><datalist>Tính năng này cung cấp gợi ý tự động hoàn thành. Nó chỉ dùng HTML thuần túy. Nó làm cho các biểu mẫu của bạn thông minh hơn. Không cần plugin tự động hoàn thành bằng JavaScript. Điều này cải thiện tốc độ nhập liệu và độ chính xác cho người dùng, đặc biệt trong các biểu mẫu phức tạp.<input list="browsers" placeholder="Choose browser"> <datalist id="browsers"> <option value="Chrome"> <option value="Firefox"> <option value="Safari"> </datalist>- Thuộc tính
downloadThuộc tính này cho phép tải xuống tệp ngay lập tức. Nó không cần backend. Không có chuyển hướng trang. Không có script. Chỉ là sức mạnh thuần túy của HTML. Trình duyệt sẽ xử lý mọi thứ cho bạn. Điều này đơn giản hóa quy trình tải xuống, giảm tải cho máy chủ và tăng tốc độ phản hồi cho người dùng.<a href="resume.pdf" download="My_Resume.pdf">Download Resume</a> <meter>Phần tử này hiển thị các giá trị có thể đo lường. Ví dụ, nó hiển thị xếp hạng hoặc tiến độ. Nó mang tính ngữ nghĩa. Nó cũng dễ tiếp cận. Trình duyệt tự động tạo kiểu cho nó. Nó hoàn hảo cho các bảng điều khiển (dashboards). Hoặc cho các hệ thống đánh giá. Điều này giúp trình bày dữ liệu định lượng một cách trực quan và chuẩn hóa.<meter min="0" max="5" value="4">4 out of 5</meter><progress>Phần tử này hiển thị trực quan mức độ hoàn thành nhiệm vụ. Đây là một thanh tiến trình đơn giản. Nó lý tưởng cho việc tải lên. Nó cũng dùng cho các trạng thái tải. Hoặc cho bất kỳ quá trình không đồng bộ nào. Điều này cung cấp phản hồi trực quan cho người dùng, giảm sự không chắc chắn trong quá trình chờ đợi.<progress value="70" max="100"></progress>- Thuộc tính
autofocusThuộc tính này tự động đặt trọng tâm vào một trường nhập liệu. Nó hoạt động khi trang tải. Đây là một chi tiết nhỏ. Nhưng nó cải thiện trải nghiệm người dùng (UX) rất lớn. Đặc biệt, nó hữu ích cho các trang đăng nhập hoặc tìm kiếm. Điều này giúp người dùng bắt đầu tương tác ngay lập tức, tiết kiệm thời gian và giảm số lần nhấp chuột.<input type="text" placeholder="Start typing..." autofocus> <mark>Phần tử này làm nổi bật văn bản. Nó dùng để nhấn mạnh. Không cần CSS tùy chỉnh. Nó mang tính ngữ nghĩa. Nó cũng dễ tiếp cận. Tính năng làm nổi bật được tích hợp sẵn. Điều này giúp thu hút sự chú ý đến các từ khóa quan trọng hoặc thông tin cụ thể mà không cần can thiệp vào kiểu dáng CSS phức tạp.<p>This is a <mark>highlighted</mark> keyword.</p>- Thuộc tính
spellcheckThuộc tính này cho phép hoặc vô hiệu hóa kiểm tra chính tả. Nó áp dụng cho đầu vào của người dùng. Nó hữu ích cho các ứng dụng ghi chú. Hoặc cho các công cụ dựa trên văn bản. Nó kiểm soát khi trình duyệt tự động sửa nội dung. Điều này giúp người dùng nhập liệu chính xác hơn, đặc biệt trong các trường hợp cần độ chính xác cao như nhập liệu dữ liệu hoặc viết bài.<textarea spellcheck="true"></textarea> <output>Phần tử này hiển thị kết quả tính toán. Hoặc nó hiển thị dữ liệu động. HTML có thể tự thực hiện các phép tính nhỏ. Nó không cần gọi hàm JavaScript. Điều này cho phép xử lý các phép tính đơn giản trực tiếp trên giao diện người dùng, giảm sự phụ thuộc vào JavaScript cho các tác vụ nhỏ.<form oninput="result.value = a.valueAsNumber + b.valueAsNumber"> <input type="number" name="a"> + <input type="number" name="b"> = <output name="result"></output> </form>- Thuộc tính
inputmodeThuộc tính này tùy chỉnh bố cục bàn phím di động. Nó cho trình duyệt di động biết loại bàn phím cần hiển thị. Điều này cải thiện đáng kể tốc độ gõ phím. Nó giúp người dùng nhập liệu nhanh chóng và chính xác hơn trên thiết bị di động, đặc biệt đối với các trường nhập liệu số hoặc email.<input type="text" inputmode="numeric" placeholder="Enter numbers"> <abbr>Phần tử này định nghĩa các từ viết tắt. Nó giúp cải thiện khả năng tiếp cận. Trình đọc màn hình sẽ đọc đầy đủ dạng của từ viết tắt. Điều này cực kỳ quan trọng cho khả năng tiếp cận và SEO (Tối ưu hóa công cụ tìm kiếm). Nó đảm bảo mọi người dùng đều hiểu rõ nội dung và tăng cường ngữ nghĩa của trang web.<p>The <abbr title="World Health Organization">WHO</abbr> released new guidelines.</p><fieldset>và<legend>Các phần tử này nhóm các trường nhập liệu biểu mẫu. Chúng nhóm một cách trực quan và ngữ nghĩa. Điều này cải thiện trải nghiệm người dùng (UX) và khả năng tiếp cận. Trình duyệt thậm chí tự động thêm các đường viền tinh tế. Nó giúp tổ chức biểu mẫu rõ ràng, dễ hiểu hơn, đặc biệt với các biểu mẫu dài có nhiều phần.<fieldset> <legend>Personal Info</legend> <input type="text" placeholder="Name"> <input type="email" placeholder="Email"> </fieldset>loading="lazy"Thuộc tính này kích hoạt tải lười (lazy loading) tự nhiên. Nó áp dụng cho hình ảnh và iframe. Nó giảm thời gian tải trang ngay lập tức. Không cần thư viện JavaScript nặng để tải lười. Điều này cải thiện hiệu suất trang web, giảm băng thông sử dụng và tăng tốc độ hiển thị nội dung chính cho người dùng.<img src="photo.jpg" loading="lazy" alt="Nature"><dialog>Phần tử này tạo hộp thoại (modal) tự nhiên. Không cần thư viện bên ngoài. Nó hỗ trợ các phương thức.showModal()và.close()trong JavaScript. Nó sạch sẽ, dễ tiếp cận. Nó được hỗ trợ chính thức trong các trình duyệt hiện đại. Điều này cung cấp một giải pháp hộp thoại chuẩn hóa, giảm sự phức tạp và tăng tính tương thích.<dialog open> <p>This is a native HTML dialog box!</p> <button onclick="this.closest('dialog').close()">Close</button> </dialog>
Chúng ta đã quá phụ thuộc vào các framework và plugin. Vì vậy, chúng ta quên mất khả năng của HTML. Các tính năng này không chỉ giảm sự phụ thuộc. Chúng còn cải thiện khả năng tiếp cận. Chúng tăng cường hiệu suất. Và chúng làm cho mã của bạn sạch hơn.
Đôi khi, nâng cấp tốt nhất cho ngăn xếp front-end của bạn không phải là một thư viện mới. Đó là việc sử dụng HTML đúng cách. Hãy bắt đầu từ những điều nhỏ. Thay thế các widget tùy chỉnh bằng các widget tự nhiên. Hãy khám phá lại sức mạnh của ngôn ngữ đơn giản nhất trên web.
Tham khảo: medium.com
Thêm hoặc thay đổi màu sắc cho văn bản
Chúng ta có thể tạo một số kiểu tô màu cho một phần tử, trong trường hợp này là văn bản tiêu đề như minh họa bên dưới, bằng cách tô màu tím cho văn bản. Chúng ta thực hiện điều này bằng cách viết thuộc tính style bên trong thẻ <h1> và theo sau là dấu ‘bằng’, tiếp theo là thuộc tính color với dấu hai chấm, và sau đó là màu bạn chọn. Trong trường hợp này là màu tím. Khi bạn đề cập rằng color bằng với purple, hãy đảm bảo rằng chúng được viết trong dấu ngoặc kép mở và đóng như minh họa bên dưới. Xin lưu ý rằng bạn cần phải viết dấu chấm phẩy sau khi viết giá trị của color, nghĩa là sau khi viết purple trong khối mã, bạn cần phải nhập dấu chấm phẩy để hoàn tất mã kiểu.
Mã nguồn cũng có sẵn trong trình soạn thảo mã của tôi, tại đó bạn có thể xem kết quả của mã này, tức là màu của tiêu đề sẽ được hiển thị là màu tím, điều này không thể phản ánh trong bài đăng này, vì vậy bạn cần kiểm tra chế độ xem đầy đủ của đầu ra mãở đó.
< h1 style = "color: purple;" > XIN CHÀO THẾ GIỚI! </ h1 >Thay đổi kích thước phông chữ của văn bản
Ở đây, chúng ta sẽ thay đổi cỡ chữ của văn bản trong một đoạn văn bằng thuộc tính style như minh họa bên dưới. Bạn có thể sử dụng các cỡ chữ khác nhau để kiểm tra kết quả trong bảng điều khiển. Nhớ kiểm tra kết quảtại đây nhé.
< p style = "font-size: 36px;" > Thay đổi kích thước phông chữ của đoạn văn bản như được hiển thị ở đây. </ p > < p style = "font-size: 50px;" > Thay đổi kích thước phông chữ của đoạn văn bản như được hiển thị ở đây. </ p >Ở đây, chúng ta đã học cách tạo kiểu cho một trang HTML bằng thuộc tính style, nhưng hãy nhớ rằng thuộc tính này được sử dụng trong phương pháp trên được gọi là inline-style. Inline style không phải là phương pháp tối ưu để sử dụng lâu dài khi bạn bắt đầu sử dụng HTML, CSS và JavaScript để tạo các trang chuyên nghiệp, nhưng với tư cách là người mới bắt đầu, bạn có thể sử dụng kiểu định kiểu này khi tạo các tài liệu và trang HTML cơ bản.
Những thủ thuật HTML
Tôi liên tục gặp phải những vấn đề nhỏ về UI như đánh dấu lộn xộn, biểu mẫu khó hiểu, hộp thoại rườm rà.
Mỗi lần như vậy, tôi lại nghĩ mình cần thêm JavaScript để sửa lỗi.
Nhưng tôi đã không làm vậy.
Tôi bắt đầu nhận thấy HTML có những tính năng đơn giản mà tôi chưa từng sử dụng trước đây.
Và sau khi thử nghiệm, giao diện người dùng của tôi ngay lập tức trở nên sạch sẽ và dễ xây dựng hơn.
Những khám phá nhỏ này đã thay đổi cách làm việc của tôi, vì vậy tôi muốn chia sẻ chúng.
Tôi thường dựa vào đóinnerHTMLbất cứ khi nào tôi cần lặp lại một đoạn HTML.
Nhưng nó sẽ nhanh chóng trở nên lộn xộn và có thể khiến bạn dễ bị nhiễm vi khuẩn.
<template>đã sửa lỗi đó.
Nó cho phép bạn lưu trữ mã HTML ẩn cho đến khi bạn sao chép nó.
< mẫu id = "mẫu thẻ" >
< div lớp = "thẻ" >
< h2 > </ h2 >
< p > </ p >
</ div >
</ mẫu >
< div id = "thẻ" > </ div >const template = document.getElementById ( ‘card-template’ ); const container = document.getElementById ( ‘ cards’ ); function addCard ( title, body ) { const clone = template.content.cloneNode ( true ) ; clone.querySelector ( ‘ h2′ ) . textContent = title; clone.querySelector ( ‘ p ‘ ). textContent = body; container.appendChild ( clone); } addCard ( “Title 1” , “Nội dung của Thẻ 1” ) ; addCard ( “Title 2” , “Nội dung của Thẻ 2″ );
Kết quả: đánh dấu sạch, không có lỗi ẩn và các khối UI có thể tái sử dụng.
Khi một cửa sổ bật lên được mở, phần còn lại của trang sẽ không thể nhấp vào được.
inertthực hiện điều này trong một dòng đồng thời khiến trình đọc màn hình không thể hiểu được.
< div id = "main-content" inert >
<!-- nội dung trang của bạn -->
</ div >
< hộp thoại mở >
< p > Xin chào! </ p >
</ hộp thoại >
[trơ] {
độ mờ đục : 0,5 ;
}Ví dụ thực tế 1: Vô hiệu hóa thanh bên khi menu thả xuống đang mở
Tuyệt vời cho bảng điều khiển hoặc ứng dụng có menu bên
< aside id = "sidebar" >
< button > Mục menu </ button >
< button > Mục menu </ button >
</ aside >
< div class = "dropdown" id = "dropdown" >
< button id = "toggle" > Mở Cài đặt </ button >
< div class = "panel" hidden >
< p > Nội dung bảng cài đặt </ p >
</ div >
</ div >
const sidebar = document.getElementById ( 'sidebar' ) ; const toggle = document.getElementById ( ' toggle' ); const panel = document.querySelector ( ' .panel' ); toggle.addEventListener ( ' click' , ( ) => { const isOpen = !panel.hidden ; panel.hidden = isOpen ; sidebar.toggleAttribute ( ' inert' , !isOpen); } );
Ví dụ thực tế 2: Khóa biểu mẫu khi đang gửiHoàn hảo để ngăn chặn việc gửi biểu mẫu trùng lặp
< form id = "userForm" >
< input type = "text" required >
< button type = "submit" > Lưu </ button >
</ form >
< div id = "loading" hidden > Đang lưu… </ div >
const form = document.getElementById ( ' userForm' ); const loading = document.getElementById ( ' loading' ); form.addEventListener ( 'submit' , ( e ) => { e. preventDefault (); form.setAttribute ( ' inert' , '' ); loading.hidden = false ; // Trì hoãn gửi giả setTimeout ( () => { form.removeAttribute ( ' inert ' ); loading.hidden = true ; alert ( ' Đã lưu!' ); }, 1500 ) ; });
Thay thế Heavy JS Modals bằng <dialog><dialog>là một trong những khám phá HTML yêu thích của tôi.
Nó cung cấp cho bạn một hộp thoại gốc có khả năng truy cập phù hợp được tích hợp sẵn.
const dialog = document . getElementById ( 'myDialog' );
dialog.showModal ( ); // làm cho trang trở nên trơ + thêm phông nềnViệc đóng nó lại cũng dễ dàng như sau:
hộp thoại. đóng ();Bạn không cần thư viện bên ngoài nữa.
Và bạn có thể tạo kiểu cho phông nền:
hộp thoại ::backdrop {
nền : rgba ( 0 , 0 , 0 , 0.5 );
}Giao diện người dùng của bạn sẽ sạch hơn, nhanh hơn và ít lỗi hơn.
Phần tử này<picture>cho phép trình duyệt chọn hình ảnh phù hợp nhất.
Điều này giúp trang web của bạn tải nhanh hơn và hiển thị sắc nét trên mọi kích thước màn hình.
< hình ảnh >
< nguồn srcset = "hero-small.jpg" phương tiện = "(chiều rộng tối đa: 500px)" >
< nguồn srcset = "hero-large.jpg" phương tiện = "(chiều rộng tối đa: 1000px)" >
< img src = "hero-large.jpg" alt = "Hình ảnh nổi bật" >
</ hình ảnh >Hoặc chọn hình ảnh dựa trên mật độ điểm ảnh:
< nguồn
srcset= "hero-1x.jpg 1x, hero-2x.jpg 2x, hero-3x.jpg 3x" >Hình ảnh phản hồi là giải pháp dễ dàng để tăng hiệu suất.
Ví dụ thực tế 1: Đổi hình ảnh sang chế độ sáng/tối
Một trường hợp sử dụng thực tế tuyệt vời mà các nhà phát triển thích sao chép
< hình ảnh >
< nguồn srcset = "logo-dark.png" phương tiện = "(ưu tiên phối màu: tối)" >
< nguồn srcset = "logo-light.png" phương tiện = "(ưu tiên phối màu: sáng)" >
< img src = "logo-light.png" alt = "Logo trang web" >
</ hình ảnh >Công dụng:
Trang web của bạn sẽ tự động hiển thị logo phù hợp tùy theo chủ đề của người dùng.Không cần JavaScript.
Ví dụ thực tế 2: Phục vụ WebP nếu được hỗ trợ, nếu không thì quay lại JPG
Điều này giúp cải thiện hiệu suất rất nhiều và rất phổ biến ở các trang web hiện đại
<hình ảnh>
< nguồn srcset= "hero.webp" loại = "hình ảnh/webp" >
< nguồn srcset= "hero.jpg" loại = "hình ảnh/jpeg" >
<img src= "hero.jpg" alt= "Hình ảnh anh hùng"
> </hình ảnh >Tác dụng:
Trình duyệt hỗ trợ WebP tải hình ảnh nhỏ hơn, nhanh hơn. Các trình duyệt cũ hơn vẫn tải được ảnh JPG an toàn.
Khi một biểu mẫu thực hiện phép tính,<output>đó là cách ngữ nghĩa để hiển thị kết quả.
< form id = "calcForm" >
< input type = "number" id = "qty" min = "1" value = "1" >
< input type = "number" id = "price" min = "0" step = "0.01" value = "10" >
< output id = "total" for = "qty price" > </ output >
</ form >
form.addEventListener ( 'input' , () => { total.value = (qty.value * price.value ) .toFixed ( 2 ) ; } );
Trình đọc màn hình sẽ thông báo thay đổi mà không cần vai trò ARIA tùy chỉnh.
Ví dụ thực tế 1: Máy tính giá trực tiếp (Số lượng × Giá)
Tuyệt vời cho các cửa hàng, xe đẩy hoặc bất kỳ giao diện định giá nào
< form id = "cart" >
< label >
Số lượng:
< input type = "number" id = "qty" value = "1" min = "1" >
</ label >
< label >
Giá:
< input type = "number" id = "price" value = "15" min = "0" >
</ label >
< p > Tổng cộng: $ < output id = "total" > 15 </ output > </ p >
</ form >
const qty = document.getElementById ( 'qty' ) ; const price = document.getElementById ( ' price' ); const total = document.getElementById ( 'total' ) ; hàm updateTotal ( ) { total.value = (qty.value * price.value ) .toFixed ( ) ; } qty.addEventListener ( ' input' , updateTotal); price.addEventListener ( ' input ' , updateTotal) ;
Tại sao điều này hữu ích:
<output> cập nhật theo thời gian thực và được tự động thông báo bằng trình đọc màn hình.Ví dụ thực tế 2: Máy tính tiền boa (Tỷ lệ phần trăm tiền boa + tiền hóa đơn)
< form id = "tipForm" >
< label >
Hóa đơn:
< input type = "number" id = "bill" value = "40" min = "0" >
</ label >
< label >
Tiền boa:
< input type = "range" id = "tip" min = "0" max = "30" value = "15" >
</ label >
< p > Bạn sẽ trả: $ < output id = "final" > 46.00 </ output > </ p >
</ form >
< script >
const bill = document .getElementById ( ' bill' ) ; const tip = document .getElementById ( ' tip' ); const final = document .getElementById( ' final ' ) ; function calc ( ) { const total = Number ( bill.value ) * ( 1 + tip.value / 100 ) ; final.value = total.toFixed ( 2 ); } bill. addEventListener ( '
đầu vào' , tính toán); mẹo.addEventListener ( 'đầu vào' , tính toán); </ script ><details>là một trong những tính năng HTML mà tôi đã bỏ qua trong nhiều năm — và bây giờ tôi sử dụng nó ở mọi nơi.
Nó cung cấp cho bạn một phần tử mở rộng/thu gọn tích hợp mà không cần JavaScript.
Hoàn hảo cho phần Câu hỏi thường gặp, bảng cài đặt hoặc bất kỳ nội dung nhỏ nào bạn muốn ẩn.
< chi tiết >
< tóm tắt > Chính sách hoàn tiền của bạn là gì? </ tóm tắt >
Bạn có thể yêu cầu hoàn tiền trong vòng 30 ngày mà không cần giải thích lý do.
</ chi tiết >Bạn thậm chí có thể mở<details>thẻ theo mặc định:
< chi tiết mở >
< tóm tắt > Đọc thêm </ tóm tắt >
Phần này bắt đầu mở rộng.
</ chi tiết >Đầu vào gốc đã được cải thiện rất nhiều. Nhiều thứ chúng tôi giải quyết bằng JS đã được tích hợp sẵn.
Sau đây là những loại mà tôi hiện đang sử dụng nhiều nhất:
email— xác thực email cơ bản cho bạn
date— mở trình chọn ngày gốc
color— hiển thị giao diện người dùng chọn màu
range— cung cấp cho bạn một thanh trượt điều khiển
search— thêm nút rõ ràng và UX thân thiện với tìm kiếm
tel— kích hoạt bàn phím số trên điện thoại di động
Và bạn có thể kết hợp chúng với các ràng buộc tích hợp sẵn:
< kiểu đầu vào = "văn bản" độ dài tối thiểu = "3" độ dài tối đa = "20" bắt buộc>Nếu bạn muốn gợi ý mà không cần JavaScript, hãy sử dụng<datalist>:
< danh sách đầu vào = "xe hơi" >
< danh sách dữ liệu id = "xe hơi" >
< giá trị tùy chọn = "Toyota" >
< giá trị tùy chọn = "Honda" >
< giá trị tùy chọn = "Ford" >
</ danh sách dữ liệu >HTML hiện đại mạnh mẽ hơn nhiều so với những gì hầu hết các nhà phát triển nhận ra.Những thủ thuật này giúp tôi viết mã sạch hơn, ít phụ thuộc vào JavaScript hơn và làm cho giao diện người dùng của tôi trông bóng bẩy hơn.Nếu bạn đã bỏ qua những tính năng này thì bây giờ chính là thời điểm hoàn hảo để thử chúng.

Bài viết liên quan: