Thuộc tính ngôn ngữ chỉ được liên kết với một ngôn ngữ. Tức là thuộc tính <html>
chỉ có thể có một ngôn ngữ, ngay cả khi có nhiều ngôn ngữ trên trang. Đặt lang
thành ngôn ngữ chính của trang.
<html lang="ar,en,fr,pt">...</html>Chúng tôi không hỗ trợ nhiều ngôn ngữ.
<html lang="ar">...</html>Chỉ đặt ngôn ngữ chính cho trang. Trong trường hợp này, ngôn ngữ là tiếng Ả Rập.
Liên kết
Tương tự như các nút, đường liên kết chủ yếu lấy tên dễ tiếp cận qua nội dung văn bản. Một mẹo hay khi tạo đường liên kết là đặt đoạn văn bản có ý nghĩa nhất vào chính đường liên kết đó, thay vì chèn các từ đệm như "Đây" hoặc "Đọc thêm".
Check out our guide to web performance <a href="/guide">here</a>.
Check out <a href="/guide">our guide to web performance</a>.
Kiểm tra xem ảnh động có kích hoạt bố cục hay không
Ảnh động di chuyển một phần tử bằng thao tác khác transform
có thể sẽ bị chậm.
Trong ví dụ sau, tôi đã đạt được cùng một kết quả trực quan ảnh động top
và left
bằng transform
.
.box { position: absolute; top: 10px; left: 10px; animation: move 3s ease infinite; } @keyframes move { 50% { top: calc(90vh - 160px); left: calc(90vw - 200px); } }
.box { position: absolute; top: 10px; left: 10px; animation: move 3s ease infinite; } @keyframes move { 50% { transform: translate(calc(90vw - 200px), calc(90vh - 160px)); } }
Bạn có thể kiểm thử điều này trong 2 ví dụ về Sự cố sau đây và khám phá hiệu suất bằng Công cụ cho nhà phát triển.
Với cùng một mã đánh dấu, chúng ta có thể thay thế: padding-top: 56.25%
bằng aspect-ratio: 16 / 9
, đặt aspect-ratio
thành tỷ lệ width
/ height
đã chỉ định.
.container { width: 100%; padding-top: 56.25%; }
.container { width: 100%; aspect-ratio: 16 / 9; }
Việc sử dụng aspect-ratio
thay vì padding-top
sẽ rõ ràng hơn nhiều và không đại diện cho thuộc tính khoảng đệm để thực hiện điều gì đó bên ngoài phạm vi thông thường.
Vâng, đúng vậy, tôi đang sử dụng reduce
để xâu chuỗi một chuỗi lời hứa. Tôi rất thông minh. Tuy nhiên, đây là một phương pháp lập trình rất thông minh.
Tuy nhiên, khi chuyển đổi nội dung trên thành một hàm không đồng bộ, bạn sẽ thực hiện thao tác quá tuần tự:
async function logInOrder(urls) { for (const url of urls) { const response = await fetch(url); console.log(await response.text()); } }Trông gọn gàng hơn nhiều, nhưng lần tìm nạp thứ hai của tôi chỉ bắt đầu cho đến khi lần tìm nạp đầu tiên được đọc đầy đủ và cứ tiếp tục như vậy. Phương thức này chậm hơn nhiều so với ví dụ hứa hẹn về việc thực hiện các tìm nạp song song. Rất may là có một vị trí giữa lý tưởng.
function markHandled(...promises) { Promise.allSettled(promises); } async function logInOrder(urls) { // fetch all the URLs in parallel const textPromises = urls.map(async (url) => { const response = await fetch(url); return response.text(); }); markHandled(...textPromises); // log them in sequence for (const textPromise of textPromises) { console.log(await textPromise); } }Trong ví dụ này, các URL được tìm nạp và đọc song song, nhưng bit
reduce
"thông minh" được thay thế bằng một vòng lặp tiêu chuẩn, nhàm chán và dễ đọc.
Viết thuộc tính tuỳ chỉnh Houdini
Sau đây là ví dụ về cách đặt thuộc tính tuỳ chỉnh (chẳng hạn như biến CSS), nhưng hiện tại thuộc tính này có cú pháp (loại), giá trị ban đầu (dự phòng) và boolean kế thừa (thuộc tính này có kế thừa giá trị của thành phần mẹ hay không?). Hiện tại, bạn có thể làm việc này thông qua CSS.registerProperty()
trong JavaScript, nhưng trong Chromium 85 trở lên, cú pháp @property
sẽ được hỗ trợ trong các tệp CSS của bạn:
CSS.registerProperty({ name: '--colorPrimary', syntax: '', initialValue: 'magenta', inherits: false });
@property --colorPrimary { syntax: ''; initial-value: magenta; inherits: false; }
Giờ đây, bạn có thể truy cập --colorPrimary
như mọi thuộc tính tuỳ chỉnh CSS khác thông qua var(--colorPrimary)
. Tuy nhiên, sự khác biệt ở đây là --colorPrimary
không chỉ được đọc dưới dạng chuỗi. Ứng dụng này có dữ liệu!
CSS backdrop-filter
áp dụng một hoặc nhiều hiệu ứng cho phần tử trong suốt hoặc trong suốt. Để hiểu rõ điều này, hãy xem xét những hình ảnh dưới đây.
![Một hình tam giác xếp chồng lên một đường tròn. Không thể nhìn thấy vòng tròn qua hình tam giác.](https://web.dev/static/examples/image/admin/LOqxvB3qqVkbZBmxMmKS.png?hl=vi)
.frosty-glass-pane { backdrop-filter: blur(2px); }
![Một hình tam giác xếp chồng lên một đường tròn. Hình tam giác trong suốt, cho phép có thể nhìn thấy vòng tròn.](https://web.dev/static/examples/image/admin/VbyjpS6Td39E4FudeiVg.png?hl=vi)
.frosty-glass-pane { opacity: .9; backdrop-filter: blur(2px); }
Hình ảnh ở bên trái cho thấy cách kết xuất các phần tử chồng chéo nếu backdrop-filter
không được sử dụng hoặc hỗ trợ. Hình ảnh ở bên phải áp dụng hiệu ứng làm mờ bằng backdrop-filter
. Xin lưu ý rằng thuộc tính này sử dụng opacity
ngoài backdrop-filter
. Nếu không có opacity
, thì sẽ không có gì để áp dụng tính năng làm mờ. Hầu như không có gì xảy ra nếu bạn đặt opacity
thành 1
(mờ hoàn toàn) thì sẽ không có ảnh hưởng nào đến nền.
Tuy nhiên, không giống như sự kiện unload
, beforeunload
được sử dụng hợp pháp. Ví dụ: khi bạn muốn cảnh báo người dùng rằng họ có các thay đổi chưa lưu, họ sẽ mất nếu rời khỏi trang. Trong trường hợp này, bạn chỉ nên thêm trình nghe beforeunload
khi người dùng chưa lưu các thay đổi, rồi xoá các thay đổi đó ngay sau khi lưu các thay đổi chưa lưu.
window.addEventListener('beforeunload', (event) => { if (pageHasUnsavedChanges()) { event.preventDefault(); return event.returnValue = 'Are you sure you want to exit?'; } });Đoạn mã trên đã thêm một trình nghe
beforeunload
một cách vô điều kiện.
function beforeUnloadListener(event) { event.preventDefault(); return event.returnValue = 'Are you sure you want to exit?'; }; // A function that invokes a callback when the page has unsaved changes. onPageHasUnsavedChanges(() => { window.addEventListener('beforeunload', beforeUnloadListener); }); // A function that invokes a callback when the page's unsaved changes are resolved. onAllChangesSaved(() => { window.removeEventListener('beforeunload', beforeUnloadListener); });Đoạn mã trên chỉ thêm trình nghe
beforeunload
khi cần thiết (và xoá trình nghe khi không cần thiết).
Hạn chế tối đa việc sử dụng Cache-Control: no-store
Cache-Control: no-store
là một tiêu đề HTTP mà máy chủ web có thể thiết lập trên những phản hồi hướng dẫn trình duyệt không lưu trữ phản hồi trong bất kỳ bộ nhớ đệm HTTP nào. Bạn nên sử dụng tính năng này cho các tài nguyên chứa thông tin nhạy cảm của người dùng, ví dụ như các trang yêu cầu phải đăng nhập.
Phần tử fieldset
, chứa từng nhóm đầu vào (.fieldset-item
), đang sử dụng gap: 1px
để tạo đường viền gọn gàng giữa các phần tử. Không có giải pháp đường viền phức tạp!
.grid { display: grid; gap: 1px; background: var(--bg-surface-1); & > .fieldset-item { background: var(--bg-surface-2); } }
.grid { display: grid; & > .fieldset-item { background: var(--bg-surface-2); &:not(:last-child) { border-bottom: 1px solid var(--bg-surface-1); } } }
Tự nhiên bọc lưới
Bố cục phức tạp nhất cuối cùng là bố cục macro, hệ thống bố cục logic giữa <main>
và <form>
.
<input type="checkbox" id="text-notifications" name="text-notifications" >
<label for="text-notifications"> <h3>Text Messages</h3> <small>Get notified about all text messages sent to your device</small> </label>
Phần tử fieldset
, chứa từng nhóm đầu vào (.fieldset-item
), đang sử dụng gap: 1px
để tạo đường viền gọn gàng giữa các phần tử. Không có giải pháp đường viền phức tạp!
.grid { display: grid; gap: 1px; background: var(--bg-surface-1); & > .fieldset-item { background: var(--bg-surface-2); } }
.grid { display: grid; & > .fieldset-item { background: var(--bg-surface-2); &:not(:last-child) { border-bottom: 1px solid var(--bg-surface-1); } } }
Bố cục <header>
thẻ
Bố cục tiếp theo cũng gần giống: Tôi sử dụng flex để tạo thứ tự dọc.
<snap-tabs> <header> <nav></nav> <span class="snap-indicator"></span> </header> <section></section> </snap-tabs>
header { display: flex; flex-direction: column; }
.snap-indicator
phải di chuyển theo chiều ngang cùng với nhóm các đường liên kết và bố cục tiêu đề này sẽ giúp thiết lập giai đoạn đó. Không có phần tử có vị trí tuyệt đối nào ở đây!
Gentle Flex là chiến lược chỉ tập trung vào trung tâm thực tế hơn. Hàm này rất mềm và nhẹ nhàng, vì không giống như place-content: center
, kích thước hộp của phần tử con không thay đổi trong quá trình căn giữa. Nhẹ nhàng nhất có thể, tất cả các mục sẽ được xếp chồng, căn giữa và giãn cách.
.gentle-flex {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 1ch;
}
- Chỉ xử lý căn chỉnh, hướng và phân phối
- Chỉnh sửa và bảo trì đều ở cùng một nơi
- Khoảng trống đảm bảo khoảng cách bằng nhau giữa n phần tử con
- Hầu hết các dòng mã
Phù hợp với cả bố cục macro và vi mô.
Cách sử dụng
gap
chấp nhận mọi độ dài hoặc phần trăm của CSS làm giá trị.
.gap-example {
display: grid;
gap: 10px;
gap: 2ch;
gap: 5%;
gap: 1em;
gap: 3vmax;
}
Khoảng trống có thể được chuyển 1 độ dài, sẽ được sử dụng cho cả hàng và cột.
.grid { display: grid; gap: 10px; }Đặt cả hàng và cột cùng nhau cùng một lúc
.grid { display: grid; row-gap: 10px; column-gap: 10px; }
Khoảng trống có thể được chuyển đi 2 chiều, sẽ được sử dụng cho hàng và cột.
.grid { display: grid; gap: 10px 5%; }Đặt cả hàng và cột riêng biệt cùng một lúc
.grid { display: grid; row-gap: 10px; column-gap: 5%; }