แอตทริบิวต์ lang จะเชื่อมโยงกับภาษาได้เพียงภาษาเดียวเท่านั้น ซึ่งหมายความว่าแอตทริบิวต์ <html>
ต้องมีภาษาเดียวเท่านั้น แม้ว่าหน้าเว็บจะมีหลายภาษาก็ตาม ตั้งค่า lang
เป็นภาษาหลักของหน้า
<html lang="ar,en,fr,pt">...</html>
<html lang="ar">...</html>
ลิงก์
ลิงก์จะได้รับชื่อสำหรับการช่วยเหลือพิเศษจากเนื้อหาข้อความเป็นหลัก ซึ่งคล้ายกับปุ่ม เคล็ดลับดีๆ ในการสร้างลิงก์คือใส่ข้อความที่มีความหมายมากที่สุดลงในลิงก์แทนที่จะใส่คำเชื่อม เช่น "ที่นี่" หรือ "อ่านเพิ่มเติม"
Check out our guide to web performance <a href="/guide">here</a>.
Check out <a href="/guide">our guide to web performance</a>.
ตรวจสอบว่าภาพเคลื่อนไหวทริกเกอร์เลย์เอาต์หรือไม่
ภาพเคลื่อนไหวที่ย้ายองค์ประกอบโดยใช้อย่างอื่นที่ไม่ใช่ transform
มีแนวโน้มที่จะทำงานช้า
ในตัวอย่างต่อไปนี้ เราได้รับผลลัพธ์ภาพเดียวกันจากภาพเคลื่อนไหว top
และ left
และใช้ 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)); } }
คุณสามารถทดสอบได้ในตัวอย่าง Glitch 2 รายการต่อไปนี้ และสำรวจประสิทธิภาพโดยใช้เครื่องมือสำหรับนักพัฒนาเว็บ
เมื่อใช้มาร์กอัปเดียวกันนี้ เราสามารถแทนที่ padding-top: 56.25%
ด้วย aspect-ratio: 16 / 9
โดยตั้งค่า aspect-ratio
เป็นอัตราส่วน width
/ height
ที่ระบุ
.container { width: 100%; padding-top: 56.25%; }
.container { width: 100%; aspect-ratio: 16 / 9; }
การใช้ aspect-ratio
แทน padding-top
นั้นชัดเจนกว่ามาก และไม่ต้องแก้ไขพร็อพเพอร์ตี้การเว้นวรรคเพื่อทําสิ่งที่อยู่นอกขอบเขตปกติ
ใช่ ฉันใช้ reduce
เพื่อต่อเชื่อมลำดับของ Promise ฉันฉลาดมาก แต่นี่เป็นการเขียนโค้ดที่ฉลาดมากซึ่งคุณควรหลีกเลี่ยง
อย่างไรก็ตาม เมื่อแปลงโค้ดข้างต้นเป็นฟังก์ชันที่ทำงานแบบไม่พร้อมกัน คุณอาจเรียงลำดับการทำงานมากเกินไป
async function logInOrder(urls) { for (const url of urls) { const response = await fetch(url); console.log(await response.text()); } }
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); } }
reduce
แทนการวนซ้ำ for มาตรฐานที่อ่านได้และน่าเบื่อ
การเขียนพร็อพเพอร์ตี้ที่กำหนดเองของ Houdini
ต่อไปนี้คือตัวอย่างการตั้งค่าพร็อพเพอร์ตี้ที่กำหนดเอง (ลองนึกถึงตัวแปร CSS) แต่ตอนนี้มีไวยากรณ์ (ประเภท) ค่าเริ่มต้น (ค่าสำรอง) และบูลีนการสืบทอด (รับค่ามาจากพร็อพเพอร์ตี้หลักหรือไม่) วิธีปัจจุบันในการทำเช่นนี้คือผ่าน CSS.registerProperty()
ใน JavaScript แต่ Chromium 85 ขึ้นไปจะรองรับไวยากรณ์ @property
ในไฟล์ CSS ดังนี้
CSS.registerProperty({ name: '--colorPrimary', syntax: '' , initialValue: 'magenta', inherits: false });
@property --colorPrimary { syntax: '' ; initial-value: magenta; inherits: false; }
ตอนนี้คุณเข้าถึง --colorPrimary
ได้เช่นเดียวกับพร็อพเพอร์ตี้ที่กำหนดเองอื่นๆ ของ CSS ผ่าน
var(--colorPrimary)
แต่ความแตกต่างของที่นี่คือ --colorPrimary
ไม่ได้อ่านเป็นสตริงเท่านั้น มีข้อมูล
CSS backdrop-filter
ใช้เอฟเฟกต์อย่างน้อย 1 รายการกับองค์ประกอบที่โปร่งแสงหรือโปร่งใส โปรดดูภาพด้านล่างเพื่อให้เข้าใจ

.frosty-glass-pane { backdrop-filter: blur(2px); }

.frosty-glass-pane { opacity: .9; backdrop-filter: blur(2px); }
รูปภาพด้านซ้ายแสดงลักษณะที่องค์ประกอบที่ซ้อนกันจะแสดงผลหากไม่ได้ใช้หรือระบบไม่รองรับ backdrop-filter
รูปภาพทางด้านขวาใช้เอฟเฟกต์เบลอโดยใช้ backdrop-filter
โปรดสังเกตว่าใช้ opacity
เพิ่มเติมจาก backdrop-filter
หากไม่มี opacity
ก็จะไม่มีสิ่งใดให้เบลอ คงไม่ต้องอธิบายให้มากความว่าหากตั้งค่า opacity
เป็น 1
(ทึบแสงโดยสมบูรณ์) จะไม่มีผลกับพื้นหลัง
อย่างไรก็ตาม beforeunload
มีการใช้งานที่ถูกต้องตามกฎหมาย ซึ่งต่างจากเหตุการณ์ unload
เช่น เมื่อต้องการเตือนผู้ใช้ว่ามีการเปลี่ยนแปลงที่ยังไม่ได้บันทึกซึ่งจะหายไปหากออกจากหน้า ในกรณีนี้ เราขอแนะนําให้เพิ่มbeforeunload
Listeners เฉพาะเมื่อผู้ใช้มีการเปลี่ยนแปลงที่ไม่ได้บันทึกไว้ แล้วนําออกทันทีหลังจากบันทึกการเปลี่ยนแปลงที่ไม่ได้บันทึกไว้
window.addEventListener('beforeunload', (event) => { if (pageHasUnsavedChanges()) { event.preventDefault(); return event.returnValue = 'Are you sure you want to exit?'; } });
beforeunload
โดยไม่มีข้อกําหนด
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); });
beforeunload
เฉพาะเมื่อจําเป็นเท่านั้น (และนําออกเมื่อไม่จําเป็น)
ลดการใช้ Cache-Control: no-store
Cache-Control: no-store
คือส่วนหัว HTTP ที่เว็บเซิร์ฟเวอร์สามารถตั้งค่าในการตอบกลับเพื่อสั่งให้เบราว์เซอร์ไม่จัดเก็บการตอบกลับไว้ในแคช HTTP ควรใช้กับทรัพยากรที่มีข้อมูลที่ละเอียดอ่อนของผู้ใช้ เช่น หน้าเว็บที่ต้องเข้าสู่ระบบ
เอลิเมนต์ fieldset
ซึ่งมีกลุ่มอินพุตแต่ละกลุ่ม (.fieldset-item
) ใช้ gap: 1px
เพื่อสร้างเส้นขอบบางๆ ระหว่างองค์ประกอบ ไม่มีวิธีแก้ปัญหาเส้นขอบที่ยุ่งยาก
.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); } } }
การตัดตารางกริดให้พอดี
เลย์เอาต์ที่ซับซ้อนที่สุดคือเลย์เอาต์มาโคร ซึ่งเป็นเลย์เอาต์เชิงตรรกะระหว่าง <main>
กับ <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>
เอลิเมนต์ fieldset
ซึ่งมีกลุ่มอินพุตแต่ละกลุ่ม (.fieldset-item
) ใช้ gap: 1px
เพื่อสร้างเส้นขอบบางๆ ระหว่างองค์ประกอบ ไม่จำเป็นต้องใช้วิธีแก้ปัญหาเส้นขอบที่ซับซ้อน
.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); } } }
เลย์เอาต์แท็บ <header>
เลย์เอาต์ถัดไปเกือบจะเหมือนกัน ฉันใช้ Flex เพื่อสร้างการจัดเรียงแนวตั้ง
<snap-tabs> <header> <nav></nav> <span class="snap-indicator"></span> </header> <section></section> </snap-tabs>
header { display: flex; flex-direction: column; }
.snap-indicator
ควรเลื่อนไปทางแนวนอนพร้อมกับกลุ่มลิงก์ และเลย์เอาต์ส่วนหัวนี้ช่วยสร้างเวทีนั้น ไม่มีองค์ประกอบที่มีตำแหน่งแบบสัมบูรณ์
Gentle Flex เป็นกลยุทธ์การเน้นเฉพาะที่แท้จริง การดำเนินการนี้นุ่มนวลและเบาเนื่องจากไม่เหมือน place-content: center
ตรงที่จะไม่มีการเปลี่ยนขนาดกล่องของช่องสำหรับเด็กในระหว่างการจัดกึ่งกลาง ระบบจะจัดวางรายการทั้งหมดซ้อนกัน จัดกึ่งกลาง และเว้นระยะห่างอย่างเบาที่สุด
.gentle-flex {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 1ch;
}
- จัดการเฉพาะการจัดแนว ทิศทาง และการเผยแพร่
- แก้ไขและดูแลรักษาได้ในที่เดียว
- Gap รับประกันการเว้นระยะห่างเท่าๆ กันระหว่างเด็ก n คน
- โค้ดหลายบรรทัด
เหมาะสำหรับเลย์เอาต์ทั้งแบบมหภาคและแบบไมโคร
การใช้งาน
gap
ยอมรับความยาวหรือเปอร์เซ็นต์ CSS เป็นค่า
.gap-example {
display: grid;
gap: 10px;
gap: 2ch;
gap: 5%;
gap: 1em;
gap: 3vmax;
}
คุณสามารถส่ง Gap ความยาว 1 ซึ่งจะใช้สำหรับทั้งแถวและคอลัมน์
.grid { display: grid; gap: 10px; }
.grid { display: grid; row-gap: 10px; column-gap: 10px; }
คุณสามารถส่ง Gap ความยาว 2 รายการ ซึ่งจะใช้สำหรับแถวและคอลัมน์
.grid { display: grid; gap: 10px 5%; }
.grid { display: grid; row-gap: 10px; column-gap: 5%; }