ภาพรวมพื้นฐานของวิธีสร้างคอมโพเนนต์สวิตช์ธีมที่ปรับเปลี่ยนได้และเข้าถึงได้ง่าย
ในโพสต์นี้ เราต้องการแชร์แนวคิดเกี่ยวกับวิธีสร้างคอมโพเนนต์สวิตช์ธีมมืดและธีมสว่าง ลองใช้การสาธิต
หากต้องการดูวิดีโอ โปรดดูโพสต์เวอร์ชัน YouTube ที่นี่
ภาพรวม
เว็บไซต์อาจมีการกําหนดค่าสำหรับควบคุมรูปแบบสีแทนที่จะใช้ค่ากําหนดของระบบทั้งหมด ซึ่งหมายความว่าผู้ใช้อาจท่องเว็บในโหมดอื่นนอกเหนือจากค่ากำหนดของระบบ เช่น ระบบของผู้ใช้ใช้ธีมสว่าง แต่ผู้ใช้ต้องการให้เว็บไซต์แสดงในธีมมืด
การสร้างฟีเจอร์นี้ต้องคำนึงถึงวิศวกรรมเว็บหลายประการ ตัวอย่างเช่น ควรแจ้งให้เบราว์เซอร์ทราบถึงค่ากําหนดโดยเร็วที่สุดเพื่อป้องกันไม่ให้สีของหน้าเว็บกะพริบ และการควบคุมต้องซิงค์กับระบบก่อน จากนั้นจึงอนุญาตข้อยกเว้นที่เก็บไว้ฝั่งไคลเอ็นต์
Markup
คุณควรใช้ <button>
ในการสลับ เนื่องจากคุณจะได้ประโยชน์จากเหตุการณ์และการโต้ตอบที่เบราว์เซอร์มีให้ เช่น เหตุการณ์การคลิกและความสามารถในการโฟกัส
ปุ่ม
ปุ่มต้องมีคลาสสําหรับใช้จาก CSS และรหัสสําหรับใช้จาก JavaScript
นอกจากนี้ เนื่องจากเนื้อหาของปุ่มเป็นไอคอนแทนข้อความ ให้เพิ่มแอตทริบิวต์ชื่อเพื่อระบุข้อมูลเกี่ยวกับวัตถุประสงค์ของปุ่ม สุดท้าย ให้เพิ่ม [aria-label]
เพื่อเก็บสถานะของปุ่มไอคอนไว้เพื่อให้โปรแกรมอ่านหน้าจอแชร์สถานะของธีมกับผู้ที่มีความบกพร่องทางสายตาได้
<button
class="theme-toggle"
id="theme-toggle"
title="Toggles light & dark"
aria-label="auto"
>
…
</button>
aria-label
และ aria-live
สุภาพ
หากต้องการระบุว่าควรประกาศการเปลี่ยนแปลง aria-label
ให้กับโปรแกรมอ่านหน้าจอ ให้เพิ่ม aria-live="polite"
ลงในปุ่ม
<button
class="theme-toggle"
id="theme-toggle"
title="Toggles light & dark"
aria-label="auto"
aria-live="polite"
>
…
</button>
การเพิ่มมาร์กอัปนี้จะส่งสัญญาณให้โปรแกรมอ่านหน้าจอฟังอย่างสุภาพ แทนที่จะเป็น aria-live="assertive"
ให้แจ้งผู้ใช้ว่ามีอะไรเปลี่ยนแปลงบ้าง ในกรณีของปุ่มนี้ อุปกรณ์จะอ่านออกเสียงว่า "สว่าง" หรือ "มืด" โดยขึ้นอยู่กับสถานะของ aria-label
ไอคอนกราฟิกเวกเตอร์ที่ปรับขนาดได้ (SVG)
SVG ช่วยให้คุณสร้างรูปร่างคุณภาพสูงที่รองรับการปรับขนาดโดยใช้มาร์กอัปน้อยที่สุด การโต้ตอบกับปุ่ม สามารถทริกเกอร์สถานะภาพใหม่สำหรับเวกเตอร์ ทำให้ SVG เหมาะสำหรับไอคอน
มาร์กอัป SVG ต่อไปนี้อยู่ภายใน <button>
<svg class="sun-and-moon" aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">
…
</svg>
เราได้เพิ่ม aria-hidden
ลงในองค์ประกอบ SVG เพื่อให้โปรแกรมอ่านหน้าจอทราบว่าไม่ต้องสนใจองค์ประกอบนี้เนื่องจากทำเครื่องหมายว่าเป็นการนำเสนอ ซึ่งเหมาะอย่างยิ่งสําหรับการตกแต่งภาพ เช่น ไอคอนภายในปุ่ม นอกจากแอตทริบิวต์ viewBox
ที่ต้องระบุในองค์ประกอบแล้ว ให้เพิ่มความสูงและความกว้างด้วยเหตุผลที่คล้ายกับที่รูปภาพควรมีขนาด
ดวงอาทิตย์
กราฟิกดวงอาทิตย์ประกอบด้วยวงกลมและเส้น ซึ่ง SVG มีรูปร่างที่สะดวก <circle>
จะอยู่ตรงกลางโดยการตั้งค่าพร็อพเพอร์ตี้ cx
และ cy
เป็น 12 ซึ่งเท่ากับครึ่งหนึ่งของขนาดวิวพอร์ต (24) จากนั้นกำหนดรัศมี (r
) เป็น 6
ซึ่งจะเป็นการกำหนดขนาด
<svg class="sun-and-moon" aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">
<circle class="sun" cx="12" cy="12" r="6" mask="url(#moon-mask)" fill="currentColor" />
</svg>
นอกจากนี้ พร็อพเพอร์ตี้มาสก์จะชี้ไปที่รหัสขององค์ประกอบ SVG ซึ่งคุณจะสร้างในลำดับต่อไป และสุดท้ายจะมีสีเติมที่ตรงกับสีข้อความของหน้าเว็บด้วย currentColor
แสงอาทิตย์
ถัดไป ให้เพิ่มเส้นแสงอาทิตย์ใต้วงกลมภายในกลุ่มองค์ประกอบ <g>
<svg class="sun-and-moon" aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">
<circle class="sun" cx="12" cy="12" r="6" mask="url(#moon-mask)" fill="currentColor" />
<g class="sun-beams" stroke="currentColor">
<line x1="12" y1="1" x2="12" y2="3" />
<line x1="12" y1="21" x2="12" y2="23" />
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
<line x1="1" y1="12" x2="3" y2="12" />
<line x1="21" y1="12" x2="23" y2="12" />
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
</g>
</svg>
ในครั้งนี้ ระบบจะตั้งค่าเส้นของแต่ละเส้นแทนที่จะตั้งค่าfill เป็นcurrentColor
เส้นและรูปวงกลมสร้างดวงอาทิตย์ที่มีแสงส่องลงมาได้สวยงาม
ดวงจันทร์
เพื่อสร้างภาพลวงตาของการเปลี่ยนจากสว่าง (ดวงอาทิตย์) เป็นมืด (ดวงจันทร์) อย่างราบรื่น ดวงจันทร์จึงเป็นการขยายไอคอนดวงอาทิตย์โดยใช้มาสก์ SVG
<svg class="sun-and-moon" aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">
<circle class="sun" cx="12" cy="12" r="6" mask="url(#moon-mask)" fill="currentColor" />
<g class="sun-beams" stroke="currentColor">
…
</g>
<mask class="moon" id="moon-mask">
<rect x="0" y="0" width="100%" height="100%" fill="white" />
<circle cx="24" cy="10" r="6" fill="black" />
</mask>
</svg>
มาสก์ที่ใช้ SVG มีประสิทธิภาพสูง เนื่องจากใช้สีขาวและสีดำเพื่อนำส่วนต่างๆ ของกราฟิกอื่นออกหรือรวมไว้ได้ ไอคอนดวงอาทิตย์จะบดบังด้วยรูปร่างดวงจันทร์ <circle>
ที่มีมาสก์ SVG โดยเพียงแค่ย้ายรูปร่างวงกลมเข้าและออกจากพื้นที่มาสก์
จะเกิดอะไรขึ้นหาก CSS ไม่โหลด
การทดสอบ SVG ราวกับว่า CSS ไม่โหลดขึ้นมานั้นอาจเป็นเรื่องดีเพื่อให้แน่ใจว่าผลลัพธ์จะไม่ใหญ่มากหรือทำให้เกิดปัญหาเกี่ยวกับเลย์เอาต์ แอตทริบิวต์ความสูงและความกว้างในบรรทัดของ SVG รวมถึงการใช้ currentColor
จะให้กฎรูปแบบขั้นต่ำสำหรับเบราว์เซอร์เพื่อใช้ในกรณีที่ CSS ไม่โหลด ซึ่งทำให้เป็นรูปแบบการป้องกันที่ดีต่อการผันผวนของเครือข่าย
เลย์เอาต์
คอมโพเนนต์สวิตช์ธีมมีพื้นที่ผิวน้อย คุณจึงไม่จำเป็นต้องใช้ตารางกริดหรือ Flexbox สำหรับเลย์เอาต์ แต่จะใช้การจัดตําแหน่ง SVG และการเปลี่ยนรูปแบบ CSS แทน
รูปแบบ
.theme-toggle
รูปแบบ
องค์ประกอบ <button>
คือคอนเทนเนอร์สำหรับรูปร่างและรูปแบบของไอคอน บริบทหลักนี้จะมีสีและขนาดที่ปรับเปลี่ยนได้เพื่อส่งต่อไปที่ SVG
งานแรกคือเปลี่ยนปุ่มเป็นรูปวงกลมและนำสไตล์ปุ่มเริ่มต้นออก
.theme-toggle {
--size: 2rem;
background: none;
border: none;
padding: 0;
inline-size: var(--size);
block-size: var(--size);
aspect-ratio: 1;
border-radius: 50%;
}
ต่อไป ให้เพิ่มรูปแบบการโต้ตอบ เพิ่มรูปแบบเคอร์เซอร์สำหรับผู้ใช้เมาส์ เพิ่ม touch-action: manipulation
เพื่อรับประสบการณ์การแตะที่รวดเร็ว
นำไฮไลต์แบบโปร่งแสงบางส่วนที่ iOS ใช้กับปุ่มออก สุดท้าย ให้สถานะโฟกัสมีที่ว่างบางส่วนในการหายใจจากขอบขององค์ประกอบ
.theme-toggle {
--size: 2rem;
background: none;
border: none;
padding: 0;
inline-size: var(--size);
block-size: var(--size);
aspect-ratio: 1;
border-radius: 50%;
cursor: pointer;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
outline-offset: 5px;
}
SVG ภายในปุ่มต้องมีสไตล์ด้วย SVG ควรมีขนาดพอดีกับปุ่ม และปลายเส้นควรโค้งมนเพื่อให้ดูนุ่มนวล
.theme-toggle {
--size: 2rem;
background: none;
border: none;
padding: 0;
inline-size: var(--size);
block-size: var(--size);
aspect-ratio: 1;
border-radius: 50%;
cursor: pointer;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
outline-offset: 5px;
& > svg {
inline-size: 100%;
block-size: 100%;
stroke-linecap: round;
}
}
การปรับขนาดแบบปรับเปลี่ยนได้ด้วยการค้นหาสื่อ hover
ปุ่มไอคอนมีขนาดค่อนข้างเล็กที่ 2rem
ซึ่งเหมาะสำหรับผู้ใช้เมาส์ แต่อาจใช้งานยากสำหรับเคอร์เซอร์ที่ควบคุมได้ยาก เช่น นิ้ว ทําให้ปุ่มเป็นไปตามหลักเกณฑ์ด้านขนาดการแตะหลายข้อโดยใช้คําค้นหาสื่อโฮเวอร์เพื่อระบุการเพิ่มขึ้นของขนาด
.theme-toggle {
--size: 2rem;
…
@media (hover: none) {
--size: 48px;
}
}
รูปแบบ SVG ของดวงอาทิตย์และดวงจันทร์
ปุ่มจะเก็บข้อมูลด้านอินเทอร์แอกทีฟของคอมโพเนนต์สวิตช์ธีม ส่วน SVG ที่อยู่ด้านในจะเก็บข้อมูลด้านภาพและภาพเคลื่อนไหว เพื่อทำให้ไอคอนดูสวยงาม และมีชีวิตชีวา
ธีมสว่าง
หากต้องการให้ภาพเคลื่อนไหวในการปรับขนาดและหมุนเกิดขึ้นจากกึ่งกลางของรูปร่าง SVG ให้ตั้งค่า transform-origin: center center
รูปร่างใช้สีที่ปรับเปลี่ยนได้ซึ่งปุ่มระบุไว้ ดวงจันทร์และดวงอาทิตย์ใช้ปุ่มที่จัดเตรียมไว้ให้ var(--icon-fill)
และ var(--icon-fill-hover)
สำหรับการเติมเต็ม ส่วนแสงอาทิตย์ใช้ตัวแปรสำหรับโรคหลอดเลือดสมอง
.sun-and-moon {
& > :is(.moon, .sun, .sun-beams) {
transform-origin: center center;
}
& > :is(.moon, .sun) {
fill: var(--icon-fill);
@nest .theme-toggle:is(:hover, :focus-visible) > & {
fill: var(--icon-fill-hover);
}
}
& > .sun-beams {
stroke: var(--icon-fill);
stroke-width: 2px;
@nest .theme-toggle:is(:hover, :focus-visible) & {
stroke: var(--icon-fill-hover);
}
}
}
ธีมมืด
รูปแบบดวงจันทร์ต้องนำแสงแดดออก ปรับขนาดวงกลมดวงอาทิตย์ให้ใหญ่ขึ้น และย้ายมาสก์วงกลม
.sun-and-moon {
@nest [data-theme="dark"] & {
& > .sun {
transform: scale(1.75);
}
& > .sun-beams {
opacity: 0;
}
& > .moon > circle {
transform: translateX(-7px);
@supports (cx: 1px) {
transform: translateX(0);
cx: 17px;
}
}
}
}
สังเกตว่าธีมสีเข้มไม่มีการเปลี่ยนแปลงหรือการเปลี่ยนสี คอมโพเนนต์ปุ่มหลักจะมีสีต่างๆ ซึ่งปรับเปลี่ยนได้อยู่แล้วในบริบทที่มืดและสว่าง ข้อมูลการเปลี่ยนควรอยู่หลังคำค้นหาสื่อที่ต้องการการเคลื่อนไหวของผู้ใช้
แอนิเมชัน
ปุ่มควรจะใช้งานได้และเก็บสถานะได้ แต่ยังไม่มีการเปลี่ยนในขณะนี้ ส่วนต่อไปนี้จะอธิบายวิธีและสิ่งที่จะเปลี่ยน
การแชร์คำค้นหาสื่อและการนำเข้าการค่อยๆ เปลี่ยน
ปลั๊กอิน Custom Media ของ PostCSS ช่วยให้ใช้ไวยากรณ์ข้อกำหนด CSS ฉบับร่างสำหรับตัวแปรคำค้นหาสื่อได้ ซึ่งช่วยให้ใส่ทรานซิชันและภาพเคลื่อนไหวตามค่ากำหนดการเคลื่อนไหวของระบบปฏิบัติการของผู้ใช้ได้อย่างง่ายดาย
@custom-media --motionOK (prefers-reduced-motion: no-preference);
/* usage example */
@media (--motionOK) {
.sun {
transition: transform .5s var(--ease-elastic-3);
}
}
หากต้องการใช้ easing ของ CSS ที่ไม่เหมือนใครและใช้งานง่าย ให้นําเข้าส่วน easings ของ Open Props ดังนี้
@import "https://unpkg.com/open-props/easings.min.css";
/* usage example */
.sun {
transition: transform .5s var(--ease-elastic-3);
}
ดวงอาทิตย์
การเปลี่ยนเฟรมของดวงอาทิตย์จะดูสนุกสนานกว่าดวงจันทร์ ซึ่งจะได้เอฟเฟกต์นี้ด้วยการใช้ easing แบบ bouncy แสงอาทิตย์ควรสะท้อนกลับมาเล็กน้อยขณะที่หมุน และศูนย์กลางของดวงอาทิตย์ควรเด้งตัวขึ้นเล็กน้อยเมื่อมีการหมุนตัว
สไตล์เริ่มต้น (ธีมสว่าง) จะกำหนดการเปลี่ยนรูปแบบ และสไตล์ธีมมืดจะกำหนดการปรับแต่งสำหรับการเปลี่ยนเป็นธีมสว่าง
.sun-and-moon {
@media (--motionOK) {
& > .sun {
transition: transform .5s var(--ease-elastic-3);
}
& > .sun-beams {
transition:
transform .5s var(--ease-elastic-4),
opacity .5s var(--ease-3)
;
}
@nest [data-theme="dark"] & {
& > .sun {
transform: scale(1.75);
transition-timing-function: var(--ease-3);
transition-duration: .25s;
}
& > .sun-beams {
transform: rotateZ(-25deg);
transition-duration: .15s;
}
}
}
}
คุณจะดูไทม์ไลน์การเปลี่ยนภาพเคลื่อนไหวได้ในแผงภาพเคลื่อนไหวในเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome คุณสามารถตรวจสอบระยะเวลาของภาพเคลื่อนไหวทั้งหมด องค์ประกอบ และเวลาของการเปลี่ยน
ดวงจันทร์
ตำแหน่งแสงสว่างและแสงมืดของดวงจันทร์ได้รับการตั้งค่าไว้แล้ว ให้เพิ่มสไตล์ทรานซิชันภายใน --motionOK
Media Query เพื่อทำให้ภาพเคลื่อนไหวอยู่เสมอโดยคำนึงถึงค่ากำหนดการเคลื่อนไหวของผู้ใช้
การกำหนดเวลาพร้อมกับการหน่วงเวลาและระยะเวลาเป็นสิ่งสำคัญในการทำให้การเปลี่ยนนี้ราบรื่น เช่น หากดวงอาทิตย์ถูกบดบังเร็วเกินไป การเปลี่ยนฉากจะไม่ดูเป็นธรรมชาติหรือสนุกสนาน แต่ดูยุ่งเหยิง
.sun-and-moon {
@media (--motionOK) {
& .moon > circle {
transform: translateX(-7px);
transition: transform .25s var(--ease-out-5);
@supports (cx: 1px) {
transform: translateX(0);
cx: 17px;
transition: cx .25s var(--ease-out-5);
}
}
@nest [data-theme="dark"] & {
& > .moon > circle {
transition-delay: .25s;
transition-duration: .5s;
}
}
}
}
ต้องการการเคลื่อนไหวที่ลดลง
ในโจทย์ GUI ส่วนใหญ่ เราพยายามคงภาพเคลื่อนไหวบางอย่างไว้ เช่น การเฟดความทึบแสง ไว้สำหรับผู้ใช้ที่ต้องการลดการเคลื่อนไหว อย่างไรก็ตาม คอมโพเนนต์นี้ทำงานได้ดีขึ้นเมื่อสถานะมีการเปลี่ยนแปลงทันที
JavaScript
JavaScript ทำงานหลายอย่างในคอมโพเนนต์นี้ ตั้งแต่การจัดการข้อมูล ARIA สำหรับโปรแกรมอ่านหน้าจอไปจนถึงการรับและตั้งค่าจากพื้นที่เก็บข้อมูลในเครื่อง
ประสบการณ์การโหลดหน้าเว็บ
สิ่งสำคัญคือต้องไม่มีการกะพริบสีเมื่อโหลดหน้าเว็บ หากผู้ใช้ที่มีรูปแบบสีเข้มระบุว่าต้องการสีอ่อนสำหรับคอมโพเนนต์นี้ แล้วโหลดหน้าเว็บซ้ำ หน้าเว็บจะมืดก่อนแล้วค่อยสว่างขึ้น
การป้องกันการบล็อกนี้หมายความว่าต้องเรียกใช้ JavaScript บล็อกจํานวนเล็กน้อยโดยมีเป้าหมายเพื่อตั้งค่าแอตทริบิวต์ HTML data-theme
ให้เร็วที่สุด
<script src="./theme-toggle.js"></script>
โดยระบบจะโหลดแท็ก <script>
ธรรมดาในเอกสาร <head>
ก่อน ก่อนที่จะโหลดมาร์กอัป CSS หรือ <body>
เมื่อเบราว์เซอร์พบสคริปต์ที่ไม่มีเครื่องหมายเช่นนี้ ก็จะเรียกใช้โค้ดและดำเนินการก่อน HTML ที่เหลือ การใช้ช่วงเวลาการบล็อกนี้อย่างประหยัดจะช่วยให้คุณตั้งค่าแอตทริบิวต์ HTML ได้ก่อนที่ CSS หลักจะแสดงหน้าเว็บ จึงป้องกันไม่ให้หน้าเว็บกะพริบหรือมีสี
JavaScript จะตรวจสอบค่ากําหนดของผู้ใช้ในพื้นที่เก็บข้อมูลในเครื่องก่อน และเปลี่ยนไปตรวจสอบค่ากําหนดของระบบหากไม่พบข้อมูลใดๆ ในพื้นที่เก็บข้อมูล
const storageKey = 'theme-preference'
const getColorPreference = () => {
if (localStorage.getItem(storageKey))
return localStorage.getItem(storageKey)
else
return window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light'
}
ระบบจะแยกวิเคราะห์ฟังก์ชันเพื่อตั้งค่าค่ากําหนดของผู้ใช้ในพื้นที่เก็บข้อมูลในเครื่องต่อ
const setPreference = () => {
localStorage.setItem(storageKey, theme.value)
reflectPreference()
}
ตามด้วยฟังก์ชันสำหรับแก้ไขเอกสารที่มีค่ากำหนด
const reflectPreference = () => {
document.firstElementChild
.setAttribute('data-theme', theme.value)
document
.querySelector('#theme-toggle')
?.setAttribute('aria-label', theme.value)
}
สิ่งที่ควรทราบในตอนนี้คือสถานะการแยกวิเคราะห์เอกสาร HTML เบราว์เซอร์ยังไม่รู้จักปุ่ม "#theme-toggle" เนื่องจากยังไม่ได้แยกวิเคราะห์แท็ก <head>
จนเสร็จสมบูรณ์ อย่างไรก็ตาม เบราว์เซอร์มี document.firstElementChild
หรือที่เรียกว่าแท็ก <html>
ฟังก์ชันจะพยายามตั้งค่าทั้ง 2 รายการเพื่อให้ซิงค์กันอยู่เสมอ แต่ในการเรียกใช้ครั้งแรกจะตั้งค่าได้เฉพาะแท็ก HTML querySelector
จะไม่พบผลลัพธ์ใดๆ ในตอนแรก และโอเปอเรเตอร์แบบเชนที่ไม่บังคับจะทำให้มั่นใจได้ว่าไม่มีข้อผิดพลาดทางไวยากรณ์เมื่อไม่พบ และพยายามเรียกใช้ฟังก์ชัน setAttribute
จากนั้นระบบจะเรียกใช้ฟังก์ชัน reflectPreference()
นั้นทันทีเพื่อให้เอกสาร HTML มีการตั้งค่าแอตทริบิวต์ data-theme
ดังนี้
reflectPreference()
ปุ่มยังคงต้องใช้แอตทริบิวต์ ดังนั้นโปรดรอเหตุการณ์การโหลดหน้าเว็บ จากนั้นจึงค้นหา เพิ่ม Listener และตั้งค่าแอตทริบิวต์ใน
window.onload = () => {
// set on load so screen readers can get the latest value on the button
reflectPreference()
// now this script can find and listen for clicks on the control
document
.querySelector('#theme-toggle')
.addEventListener('click', onClick)
}
ประสบการณ์การสลับปุ่ม
เมื่อคลิกปุ่ม จะต้องสลับธีมทั้งในหน่วยความจำ JavaScript และในเอกสาร จะต้องตรวจสอบค่าธีมปัจจุบันและตัดสินใจเกี่ยวกับสถานะใหม่ เมื่อตั้งค่าสถานะใหม่แล้ว ให้บันทึกและอัปเดตเอกสาร โดยทำดังนี้
const onClick = () => {
theme.value = theme.value === 'light'
? 'dark'
: 'light'
setPreference()
}
กำลังซิงค์กับระบบ
ความโดดเด่นของการสลับธีมนี้คือการซิงค์กับค่ากำหนดของระบบเมื่อมีการเปลี่ยนแปลง หากผู้ใช้เปลี่ยนค่ากำหนดของระบบขณะที่หน้าเว็บและคอมโพเนนต์นี้แสดงอยู่ สวิตช์ธีมจะเปลี่ยนให้ตรงกับค่ากำหนดใหม่ของผู้ใช้ ราวกับว่าผู้ใช้โต้ตอบกับสวิตช์ธีมในเวลาเดียวกับที่ระบบเปลี่ยน
ทําได้โดยการใช้ JavaScript และ matchMedia
ฟังเหตุการณ์เพื่อตรวจหาการเปลี่ยนแปลงในคําค้นหาสื่อ
window
.matchMedia('(prefers-color-scheme: dark)')
.addEventListener('change', ({matches:isDark}) => {
theme.value = isDark ? 'dark' : 'light'
setPreference()
})
บทสรุป
ตอนนี้คุณก็รู้แล้วว่าฉันทำท่านั้นได้อย่างไร คุณจะทำยังไงบ้างคะ‽ 🙂
มาเพิ่มความหลากหลายให้แนวทางของเราและเรียนรู้วิธีทั้งหมดในการสร้างเนื้อหาบนเว็บกัน สร้างเดโม แล้วทวีตลิงก์มาหาเรา เราจะเพิ่มลงในส่วนรีมิกซ์ของชุมชนด้านล่าง