HTML

DOCTYPE làm gì?

DOCTYPE là viết tắt của Document Type (Kiểu tài liệu). Một DOCTYPE luôn được liên kết với một DTD - cho Document Type Definition (Định nghĩa kiểu tài liệu).

Một DTD định nghĩa cách các tài liệu của một loại nhất định nên được cấu trúc (tức là một button có thể chứa một span nhưng không phải một div), trong khi DOCTYPE khai báo DTD mà một tài liệu được cho là tuân thủ (tức là tài liệu này tuân thủ DTD HTML).

Đối với các trang web, khai báo DOCTYPE là bắt buộc. Nó được sử dụng để cho các tác nhân người dùng biết tài liệu của bạn tuân thủ phiên bản nào của đặc tả HTML. Khi một tác nhân người dùng đã nhận ra một DOCTYPE chính xác, nó sẽ kích hoạt chế độ không quirks khớp với DOCTYPE này để đọc tài liệu. Nếu một tác nhân người dùng không nhận ra một DOCTYPE chính xác, nó sẽ kích hoạt chế độ quirks.

Khai báo DOCTYPE cho tiêu chuẩn HTML5 là <!DOCTYPE html>.

Bạn phục vụ một trang với nội dung đa ngôn ngữ như thế nào?

Tôi sẽ giả định rằng câu hỏi này đang hỏi về trường hợp phổ biến nhất, đó là cách phục vụ một trang với nội dung có sẵn bằng nhiều ngôn ngữ, nhưng nội dung trong trang chỉ nên được hiển thị bằng một ngôn ngữ nhất quán.

Khi một yêu cầu HTTP được gửi đến máy chủ, tác nhân người dùng yêu cầu thường gửi thông tin về tùy chọn ngôn ngữ, chẳng hạn như trong tiêu đề Accept-Language. Máy chủ sau đó có thể sử dụng thông tin này để trả về một phiên bản tài liệu bằng ngôn ngữ thích hợp nếu có một lựa chọn thay thế như vậy. Tài liệu HTML được trả về cũng nên khai báo thuộc tính lang trong thẻ <html>, chẳng hạn như <html lang="en">...</html>.

Tất nhiên, điều này vô ích để cho công cụ tìm kiếm biết rằng cùng một nội dung có sẵn bằng các ngôn ngữ khác nhau, và do đó bạn cũng phải sử dụng thuộc tính hreflang trong <head>. Ví dụ: <link rel="alternate" hreflang="de" href="http://de.example.com/page.html" />

Ở phần phụ trợ, mã HTML sẽ chứa các phần giữ chỗ i18n và nội dung cho ngôn ngữ cụ thể được lưu trữ ở định dạng YML hoặc JSON. Máy chủ sau đó tự động tạo trang HTML với nội dung bằng ngôn ngữ cụ thể đó, thường là với sự trợ giúp của một khung công tác phụ trợ.

Bạn phải cẩn thận những điều gì khi thiết kế hoặc phát triển các trang web đa ngôn ngữ?

  • Sử dụng thuộc tính lang trong HTML của bạn.
  • Hướng người dùng đến ngôn ngữ bản địa của họ - Cho phép người dùng dễ dàng thay đổi quốc gia/ngôn ngữ của họ mà không gặp rắc rối.
  • Văn bản trong hình ảnh dựa trên raster (ví dụ: png, gif, jpg, v.v.) không phải là một phương pháp có thể mở rộng - Đặt văn bản trong hình ảnh vẫn là một cách phổ biến để hiển thị các phông chữ đẹp mắt, không phải hệ thống trên bất kỳ máy tính nào. Tuy nhiên, để dịch văn bản hình ảnh, mỗi chuỗi văn bản sẽ cần có một hình ảnh riêng được tạo cho mỗi ngôn ngữ. Bất kỳ số lượng thay thế nào lớn hơn một vài trường hợp như thế này có thể nhanh chóng vượt khỏi tầm kiểm soát.
  • Chiều dài từ/câu hạn chế - Một số nội dung có thể dài hơn khi được viết bằng ngôn ngữ khác. Hãy cẩn thận với các vấn đề về bố cục hoặc tràn trong thiết kế. Tốt nhất là tránh thiết kế mà số lượng văn bản sẽ làm hỏng hoặc tạo nên một thiết kế. Số lượng ký tự sẽ ảnh hưởng đến các tiêu đề, nhãn và nút. Chúng ít là vấn đề hơn với văn bản tự do như văn bản chính hoặc bình luận.
  • Cẩn thận về cách màu sắc được cảm nhận - Màu sắc được cảm nhận khác nhau giữa các ngôn ngữ và văn hóa. Thiết kế nên sử dụng màu sắc một cách thích hợp.
  • Định dạng ngày và tiền tệ - Ngày lịch đôi khi được trình bày theo những cách khác nhau. Ví dụ: "May 31, 2012" ở Hoa Kỳ so với "31 May 2012" ở các vùng của Châu Âu.
  • Không nối các chuỗi đã dịch - Không làm bất cứ điều gì như "Ngày hôm nay là " + date. Nó sẽ bị lỗi trong các ngôn ngữ có thứ tự từ khác nhau. Thay vào đó, hãy sử dụng một chuỗi mẫu với các tham số thay thế cho mỗi ngôn ngữ. Ví dụ, hãy xem hai câu sau đây bằng tiếng Anh và tiếng Trung tương ứng: I will travel on {% date %}{% date %} 我会出发. Lưu ý rằng vị trí của biến khác nhau do các quy tắc ngữ pháp của ngôn ngữ.
  • Hướng đọc ngôn ngữ - Trong tiếng Anh, chúng ta đọc từ trái sang phải, từ trên xuống dưới, trong tiếng Nhật truyền thống, văn bản được đọc từ trên xuống dưới, từ phải sang trái.
  • Hữu ích - bao gồm ngôn ngữ trong đường dẫn (ví dụ: en_US, zh_CN, v.v.).

`data-` thuộc tính có lợi ích gì?

Trước khi các framework JavaScript trở nên phổ biến, các nhà phát triển front-end đã sử dụng các thuộc tính data- để lưu trữ dữ liệu bổ sung trong chính DOM, mà không cần các cách hack khác như các thuộc tính không chuẩn, các thuộc tính bổ sung trên DOM. Nó được dùng để lưu trữ dữ liệu tùy chỉnh riêng tư cho trang hoặc ứng dụng, mà không có các thuộc tính hoặc phần tử phù hợp hơn.

Ngày nay, việc sử dụng các thuộc tính data- nói chung không được khuyến khích. Một lý do là người dùng có thể dễ dàng sửa đổi thuộc tính dữ liệu bằng cách sử dụng công cụ kiểm tra phần tử trong trình duyệt. Mô hình dữ liệu tốt hơn nên được lưu trữ trong chính JavaScript và được cập nhật với DOM thông qua liên kết dữ liệu có thể thông qua một thư viện hoặc một framework.

Tuy nhiên, một cách sử dụng hoàn toàn hợp lệ của các thuộc tính dữ liệu, là thêm một hook cho các framework kiểm thử end to end như Selenium và Capybara mà không cần tạo các lớp hoặc thuộc tính ID vô nghĩa. Phần tử cần một cách để được tìm thấy bởi một đặc tả Selenium cụ thể và một thứ gì đó như data-selector='the-thing' là một cách hợp lệ để làm như vậy mà không làm phức tạp ngữ nghĩa đánh dấu.

Coi HTML5 là một nền tảng web mở. Các khối xây dựng của HTML5 là gì?

  • Ngữ nghĩa - Cho phép bạn mô tả chính xác hơn nội dung của mình là gì.
  • Kết nối - Cho phép bạn giao tiếp với máy chủ theo những cách mới và sáng tạo.
  • Ngoại tuyến và lưu trữ - Cho phép các trang web lưu trữ dữ liệu cục bộ ở phía máy khách và hoạt động ngoại tuyến hiệu quả hơn.
  • Đa phương tiện - Đưa video và âm thanh trở thành công dân hạng nhất trên Web mở.
  • Đồ họa và hiệu ứng 2D/3D - Cho phép nhiều tùy chọn trình bày đa dạng hơn.
  • Hiệu suất và tích hợp - Cung cấp tối ưu hóa tốc độ cao hơn và sử dụng tốt hơn phần cứng máy tính.
  • Truy cập thiết bị - Cho phép sử dụng các thiết bị đầu vào và đầu ra khác nhau.
  • Tạo kiểu - Cho phép tác giả viết các chủ đề phức tạp hơn.

Mô tả sự khác biệt giữa `cookie`, `sessionStorage` và `localStorage`.

Tất cả các công nghệ được đề cập ở trên đều là cơ chế lưu trữ cặp khóa-giá trị ở phía máy khách. Chúng chỉ có thể lưu trữ các giá trị dưới dạng chuỗi.

| | cookie | localStorage | sessionStorage | | --- | --- | --- | --- | | Người khởi tạo | Máy khách hoặc máy chủ. Máy chủ có thể sử dụng tiêu đề Set-Cookie | Máy khách | Máy khách | | Thời hạn hết hạn | Đặt thủ công | Mãi mãi | Khi đóng tab | | Duy trì trên các phiên trình duyệt | Tùy thuộc vào việc thời hạn hết hạn có được đặt hay không | Có | Không | | Được gửi đến máy chủ với mọi yêu cầu HTTP | Cookie tự động được gửi qua tiêu đề Cookie | Không | Không | | Dung lượng (mỗi miền) | 4kb | 5MB | 5MB | | Khả năng truy cập | Bất kỳ cửa sổ nào | Bất kỳ cửa sổ nào | Cùng một tab |

Lưu ý: Nếu người dùng quyết định xóa dữ liệu duyệt web thông qua bất kỳ cơ chế nào do trình duyệt cung cấp, điều này sẽ xóa bất kỳ cookie, localStorage hoặc sessionStorage nào được lưu trữ. Điều quan trọng là phải ghi nhớ điều này khi thiết kế cho tính bền vững cục bộ, đặc biệt khi so sánh với các lựa chọn thay thế như lưu trữ phía máy chủ trong cơ sở dữ liệu hoặc tương tự (mà tất nhiên sẽ vẫn tồn tại bất chấp hành động của người dùng).

Mô tả sự khác biệt giữa `<script>`, `<script async>` và `<script defer>`.

  • <script> - Quá trình phân tích cú pháp HTML bị chặn, tập lệnh được tìm nạp và thực thi ngay lập tức, quá trình phân tích cú pháp HTML tiếp tục sau khi tập lệnh được thực thi.
  • <script async> - Tập lệnh sẽ được tìm nạp song song với quá trình phân tích cú pháp HTML và được thực thi ngay khi có sẵn (có thể trước khi quá trình phân tích cú pháp HTML hoàn tất). Sử dụng async khi tập lệnh độc lập với bất kỳ tập lệnh nào khác trên trang, ví dụ: phân tích.
  • <script defer> - Tập lệnh sẽ được tìm nạp song song với quá trình phân tích cú pháp HTML và được thực thi khi trang đã hoàn tất phân tích cú pháp. Nếu có nhiều tập lệnh, mỗi tập lệnh bị trì hoãn sẽ được thực thi theo thứ tự chúng được bắt gặp trong tài liệu. Nếu một tập lệnh phụ thuộc vào DOM được phân tích cú pháp hoàn chỉnh, thuộc tính defer sẽ hữu ích trong việc đảm bảo rằng HTML được phân tích cú pháp hoàn chỉnh trước khi thực thi. Một tập lệnh bị trì hoãn không được chứa document.write.

Lưu ý: Các thuộc tính asyncdefer bị bỏ qua đối với các tập lệnh không có thuộc tính src.

Tại sao việc đặt các thẻ `<link>` CSS giữa `<head></head>` và các thẻ `<script>` JS ngay trước `</body>` thường là một ý kiến hay? Bạn có biết trường hợp ngoại lệ nào không?

Đặt <link> trong <head>

Việc đặt các thẻ <link> trong <head> là một phần của quy cách phù hợp trong việc xây dựng một trang web được tối ưu hóa. Khi một trang tải lần đầu tiên, HTML và CSS được phân tích cú pháp đồng thời; HTML tạo DOM (Mô hình Đối tượng Tài liệu) và CSS tạo CSSOM (Mô hình Đối tượng CSS). Cả hai đều cần thiết để tạo ra các hình ảnh trong một trang web, cho phép thời gian "first meaningful paint" nhanh chóng. Việc hiển thị tăng dần này là một danh mục tối ưu hóa mà các trang web được đo lường trong điểm hiệu suất của chúng. Việc đặt các biểu định kiểu gần cuối tài liệu là điều cản trở việc hiển thị tăng dần trong nhiều trình duyệt. Một số trình duyệt chặn hiển thị để tránh phải vẽ lại các phần tử của trang nếu kiểu của chúng thay đổi. Người dùng sau đó bị mắc kẹt khi xem một trang trắng trống. Những lúc khác có thể có các đoạn nội dung không có kiểu (FOUC), hiển thị một trang web không áp dụng kiểu dáng.

Đặt <script> ngay trước </body>

Các thẻ <script> chặn quá trình phân tích cú pháp HTML trong khi chúng đang được tải xuống và thực thi, điều này có thể làm chậm trang của bạn. Việc đặt các tập lệnh ở cuối sẽ cho phép HTML được phân tích cú pháp và hiển thị cho người dùng trước.

Một trường hợp ngoại lệ để định vị các thẻ <script> ở cuối là khi tập lệnh của bạn chứa document.write(), nhưng ngày nay việc sử dụng document.write() không phải là một thực hành tốt. Ngoài ra, việc đặt các thẻ <script> ở cuối có nghĩa là trình duyệt không thể bắt đầu tải xuống các tập lệnh cho đến khi toàn bộ tài liệu được phân tích cú pháp. Điều này đảm bảo mã của bạn cần thao tác các phần tử DOM sẽ không gây lỗi và dừng toàn bộ tập lệnh. Nếu bạn cần đặt các thẻ <script> trong <head>, hãy sử dụng thuộc tính defer, điều này sẽ đạt được hiệu quả tương tự là chạy tập lệnh chỉ sau khi HTML được phân tích cú pháp nhưng trình duyệt có thể tải xuống tập lệnh sớm hơn.

Hãy nhớ rằng việc đặt các tập lệnh ngay trước thẻ </body> đóng sẽ tạo ra ảo giác rằng trang tải nhanh hơn trên bộ nhớ cache trống (vì các tập lệnh sẽ không chặn việc tải xuống phần còn lại của tài liệu). Tuy nhiên, nếu bạn có một số mã muốn chạy trong quá trình tải trang, nó sẽ chỉ bắt đầu thực thi sau khi toàn bộ trang đã tải. Nếu bạn đặt các tập lệnh đó trong thẻ <head>, chúng sẽ bắt đầu thực thi sớm hơn - vì vậy trên bộ nhớ cache đã được chuẩn bị sẵn, trang thực sự sẽ có vẻ tải nhanh hơn.

Các thẻ <head><body> hiện là tùy chọn

Theo đặc tả HTML5, một số thẻ HTML như <head><body> là tùy chọn. Hướng dẫn kiểu của Google thậm chí còn khuyến nghị loại bỏ chúng để tiết kiệm byte. Tuy nhiên, thực hành này vẫn chưa được áp dụng rộng rãi và lợi ích hiệu suất có thể là tối thiểu và đối với hầu hết các trang web, nó có thể không quan trọng.

Hiển thị tăng dần là gì?

Hiển thị tăng dần là tên được đặt cho các kỹ thuật được sử dụng để cải thiện hiệu suất của một trang web (đặc biệt là cải thiện thời gian tải được cảm nhận) để hiển thị nội dung nhanh nhất có thể.

Nó từng phổ biến hơn nhiều trong thời đại trước internet băng thông rộng nhưng nó vẫn được sử dụng trong phát triển hiện đại vì các kết nối dữ liệu di động ngày càng trở nên phổ biến (và không đáng tin cậy)!

Ví dụ về các kỹ thuật như vậy:

  • Tải chậm hình ảnh - Hình ảnh trên trang không được tải tất cả cùng một lúc. JavaScript sẽ được sử dụng để tải hình ảnh khi người dùng cuộn vào phần trang hiển thị hình ảnh.
  • Ưu tiên nội dung hiển thị (hoặc hiển thị trên màn hình đầu tiên) - Chỉ bao gồm CSS/nội dung/tập lệnh tối thiểu cần thiết cho phần trang sẽ được hiển thị trong trình duyệt của người dùng trước để hiển thị nhanh nhất có thể, sau đó bạn có thể sử dụng các tập lệnh bị trì hoãn hoặc lắng nghe sự kiện DOMContentLoaded/load để tải các tài nguyên và nội dung khác.
  • Các đoạn HTML không đồng bộ - Xả các phần của HTML vào trình duyệt khi trang được xây dựng ở phần phụ trợ. Chi tiết hơn về kỹ thuật có thể được tìm thấy.

Tại sao bạn lại sử dụng thuộc tính `srcset` trong thẻ `<img>`? Giải thích quá trình trình duyệt sử dụng khi đánh giá nội dung của thuộc tính này.

Bạn sẽ sử dụng thuộc tính srcset khi bạn muốn phục vụ các hình ảnh khác nhau cho người dùng tùy thuộc vào chiều rộng hiển thị thiết bị của họ - phục vụ hình ảnh chất lượng cao hơn cho các thiết bị có màn hình retina nâng cao trải nghiệm người dùng trong khi phục vụ hình ảnh có độ phân giải thấp hơn cho các thiết bị cấp thấp tăng hiệu suất và giảm lãng phí dữ liệu (vì phục vụ một hình ảnh lớn hơn sẽ không có bất kỳ sự khác biệt rõ rệt nào). Ví dụ: <img srcset="small.jpg 500w, medium.jpg 1000w, large.jpg 2000w" src="..." alt=""> cho trình duyệt biết hiển thị đồ họa .jpg nhỏ, trung bình hoặc lớn tùy thuộc vào độ phân giải của máy khách. Giá trị đầu tiên là tên hình ảnh và giá trị thứ hai là chiều rộng của hình ảnh tính bằng pixel. Đối với chiều rộng thiết bị là 320px, các phép tính sau được thực hiện:

  • 500 / 320 = 1.5625
  • 1000 / 320 = 3.125
  • 2000 / 320 = 6.25

Nếu độ phân giải của máy khách là 1x, 1.5625 là gần nhất và 500w tương ứng với small.jpg sẽ được trình duyệt chọn.

Nếu độ phân giải là retina (2x), trình duyệt sẽ sử dụng độ phân giải gần nhất trên mức tối thiểu. Có nghĩa là nó sẽ không chọn 500w (1.5625) vì nó lớn hơn 1 và hình ảnh có thể trông xấu. Trình duyệt sau đó sẽ chọn hình ảnh có tỷ lệ kết quả gần 2 nhất là 1000w (3.125).

srcset giải quyết vấn đề là bạn muốn phục vụ các tệp hình ảnh nhỏ hơn cho các thiết bị màn hình hẹp, vì chúng không cần hình ảnh lớn như màn hình máy tính để bàn - và cũng tùy chọn là bạn muốn phục vụ hình ảnh có độ phân giải khác nhau cho màn hình mật độ cao/mật độ thấp.

Bạn đã từng sử dụng các ngôn ngữ tạo mẫu HTML khác nhau chưa?

Có, Pug (trước đây là Jade), ERB, Slim, Handlebars, Jinja, Liquid và EJS chỉ là một vài trong số đó. Theo ý kiến của tôi, chúng ít nhiều giống nhau và cung cấp chức năng tương tự về việc thoát nội dung và các bộ lọc hữu ích để thao tác dữ liệu được hiển thị. Hầu hết các công cụ tạo mẫu cũng sẽ cho phép bạn chèn các bộ lọc của riêng mình trong trường hợp bạn cần xử lý tùy chỉnh trước khi hiển thị.

Sự khác biệt giữa canvas và SVG là gì?

Canvas dựa trên raster, làm việc với các pixel, trong khi SVG dựa trên vector, sử dụng các mô tả toán học của các hình dạng. Canvas sử dụng cách vẽ theo mệnh lệnh, trong đó mỗi bước được chỉ định bằng JavaScript, lý tưởng cho đồ họa động và tương tác như hoạt ảnh và trò chơi.

Ngược lại, SVG sử dụng cách vẽ khai báo, với các hình dạng và đường dẫn được định nghĩa trực tiếp trong HTML, làm cho nó dễ tiếp cận hơn và thân thiện với SEO. Canvas tối ưu cho các cảnh phức tạp do chi phí thấp hơn, nhưng việc mở rộng có thể dẫn đến mất chất lượng hình ảnh. SVG, không phụ thuộc vào độ phân giải, thích ứng với nhiều kích thước màn hình khác nhau mà không làm giảm chất lượng.

Cuối cùng, canvas phù hợp với đồ họa động, hiệu suất cao, trong khi SVG vượt trội trong đồ họa có thể mở rộng, không phụ thuộc vào độ phân giải, với các lợi thế vốn có về khả năng tiếp cận và SEO.

Các phần tử rỗng trong HTML là gì?

Các phần tử rỗng trong HTML là các phần tử không chứa bất kỳ nội dung nào giữa thẻ mở và thẻ đóng của chúng. Thay vào đó, chúng là các thẻ tự đóng, có nghĩa là chúng có một dấu gạch chéo (/) trước dấu ngoặc nhọn đóng (>). Một số ví dụ phổ biến về các phần tử rỗng bao gồm:

  • <img>: Dùng để nhúng hình ảnh vào tài liệu.
  • <input>: Dùng để chấp nhận dữ liệu nhập của người dùng.
  • <br>: Dùng để chèn ngắt dòng hoặc ngắt dòng bắt buộc.
  • <hr>: Dùng để tạo các đường ngang hoặc dấu phân cách.