สร้างการ์ด

ภาพรวม

การ์ดจะจัดกลุ่มเนื้อหาที่เกี่ยวข้อง 1 รายการหรือตัวเลือก 1 รายการ ซึ่งเป็นรูปแบบภาพ ไม่ใช่โมเดลความหมายหรือการโต้ตอบที่ตายตัว ดังนั้นให้คงความหมายของเนื้อหาไว้และใช้การโต้ตอบแบบเนทีฟที่ตรงกับวัตถุประสงค์

หลักเกณฑ์

เลือกความหมายของเนื้อหาและการโต้ตอบแยกกัน ดังนี้

  • ใช้ <article> เป็นรูทของการ์ด ไม่ว่าจะลิงก์ไปยังปลายทางหรือไม่ก็ตาม
  • ใช้ลิงก์แบบเนทีฟสำหรับการนำทาง เมื่อการ์ดทั้งใบเป็นปลายทางเดียว ลิงก์เดียวอาจรวม <article> ไว้เฉพาะในกรณีที่การ์ดไม่มีองค์ประกอบแบบอินเทอร์แอกทีฟอื่นๆ (a, button, input, select, textarea)
  • เก็บลิงก์และปุ่มสำหรับการดำเนินการอิสระไว้เป็นตัวควบคุมแบบเนทีฟแยกต่างหาก
  • ใช้ปุ่มตัวเลือกหรือช่องทำเครื่องหมายที่มี <label> ที่เชื่อมโยง หรือ option ใน <select> แบบเนทีฟ เมื่อการ์ดเป็นตัวเลือก

จัดเรียงสื่อ ชื่อ เนื้อหาสนับสนุน และการดำเนินการตามลำดับแหล่งที่มาที่มีความหมาย อย่าใช้ CSS order เพื่อขัดแย้งกับลำดับดังกล่าว (ดูเลย์เอาต์ CSS และการออกแบบที่ปรับเปลี่ยนตามอุปกรณ์)

การใช้งาน

ใช้มาร์กอัปให้น้อยที่สุดและให้ตัวเลือก CSS จดจำแต่ละภูมิภาค เพื่อให้การ์ดแบบง่ายยังคงเรียบง่ายและ Rich Card ยังคงเป็นไปได้ การ์ดมีได้สูงสุด 4 ส่วนตามลำดับแหล่งที่มานี้ และสามารถละเว้นส่วนใดก็ได้ ภูมิภาคเป็นองค์ประกอบย่อยโดยตรงของการ์ด ไม่ได้จัดกลุ่มในองค์ประกอบ Wrapper เช่น .card__body ซึ่งจะป้องกันไม่ให้วางและจัดรูปแบบภูมิภาคตามตัวเลือก ขอบเขตที่มีองค์ประกอบเดียวคือองค์ประกอบนั้นเอง ไม่ได้รวมอยู่ด้วย โดยย่อหน้าเดียวคือ <p> ใช้ Wrapper เฉพาะเมื่อภูมิภาคมีองค์ประกอบหลายรายการ

  • สื่อ: <img>, <picture>, <video> หรือ <svg> เป็นองค์ประกอบย่อยแรก เพิ่มคลาส .media ลงในเนื้อหา Hero ที่กำหนดเองซึ่งไม่ใช่องค์ประกอบใดองค์ประกอบหนึ่งข้างต้นเท่านั้น และอย่ารวม <img> ธรรมดาไว้ในองค์ประกอบ .media
  • ส่วนหัว: ส่วนหัวที่อยู่เดี่ยวๆ ใช้ <hgroup> เฉพาะเมื่อส่วนหัวมีคำบรรยายหรือแท็กไลน์ และใช้ <header> เมื่อส่วนนั้นมีมากกว่าชื่อ เช่น ข้อมูลผู้เขียนหรือป้าย เมื่อการ์ดมีปลายทางหลัก ลิงก์จะอยู่ภายในส่วนหัว
  • เนื้อหา: <p>, <ul> หรือ <dl> รายการเดียวที่แยกเป็นอิสระจากกัน เมื่อเนื้อหามีหลายองค์ประกอบ เช่น ย่อหน้าหลายย่อหน้า หรือย่อหน้าบวกกับรายการ ให้จัดกลุ่มไว้ใน <div> เดียวเพื่อให้พื้นที่เป็นรายการตารางกริดรายการเดียว
  • ส่วนท้าย: <footer> ที่มีการดำเนินการแยกต่างหากเป็นลิงก์และปุ่มแบบเนทีฟ ลิงก์ "อ่านเพิ่มเติม" อาจใช้ URL ของลิงก์ส่วนหัวร่วมกัน แต่ให้ตั้งชื่อที่เข้าถึงได้ซึ่งสื่อความหมายและขึ้นต้นด้วยข้อความที่มองเห็นได้ โดยใช้ข้อความที่ซ่อนไว้ (เช่น Read more<span> about poached eggs</span>) เนื่องจากลิงก์ "อ่านเพิ่มเติม" ที่เหมือนกันจะทำให้เกิดความกำกวมในรายการลิงก์ของโปรแกรมอ่านหน้าจอ อย่าเพิ่มลิงก์ส่วนท้ายอื่นๆ ที่ซ้ำกับ URL ของส่วนหัว

การ์ดที่เรียบง่ายที่สุดคือ <article> ที่มีส่วนหัวและย่อหน้า เลือกลิงก์และรูปแบบการดำเนินการที่ตรงกับลักษณะการทำงานของการ์ด โปรดดูรูปแบบการโต้ตอบ

สำหรับรูปภาพหรือวิดีโอการ์ดที่ควรเติมเต็มพื้นที่อัตราส่วนคงที่ ให้ตั้งค่า aspect-ratio และ object-fit: cover ใน <img> หรือ <video> เอง เพื่อให้เติมเต็มพื้นที่โดยไม่บิดเบี้ยว (อาจมีการครอบตัด) ใช้ aspect-ratio ของคอนเทนเนอร์ .media สำหรับเนื้อหา Hero อื่นๆ เท่านั้น หรือคงสัดส่วนที่แท้จริงของสื่อไว้ ใส่ข้อความแสดงแทนที่เหมาะสมให้กับรูปภาพที่ให้ข้อมูล และใช้ alt="" สำหรับรูปภาพเพื่อการตกแต่ง

ปรับให้เข้ากับพื้นที่ว่าง

จัดเลย์เอาต์ตามพื้นที่ว่างของการ์ด ไม่ใช่วิวพอร์ต หากต้องการปรับองค์ประกอบย่อยของการ์ด (สื่อ ข้อความ การดำเนินการ) ให้กำหนดการ์ดเป็นคอนเทนเนอร์ขนาด (container-type: inline-size) และเขียนกฎ @container สำหรับองค์ประกอบย่อยของการ์ด หลีกเลี่ยงการปรับขนาดจากตารางกริดหรือรายการหลัก เนื่องจากความกว้างจริงของการ์ดอาจขึ้นอยู่กับจำนวนคอลัมน์ ช่องว่าง และอื่นๆ ซึ่งทำให้เบรกพอยต์ที่อิงตามหลักมีสัญญาณรบกวน

ในคอนเทนเนอร์แคบ ให้วางซ้อนภูมิภาคตามลำดับแหล่งที่มา ในคอนเทนเนอร์แบบกว้าง ให้วางสื่อในคอลัมน์ด้านข้างถัดจากส่วนอื่นๆ แต่เฉพาะสำหรับการ์ดที่มีสื่อเท่านั้น โดยกำหนดขอบเขตของกฎเหล่านั้นด้วย :has() ในองค์ประกอบย่อยของสื่อ (เช่น .card:has(> img)) เพื่อไม่ให้คำจำกัดความของคอลัมน์และการวาง grid-column มีผลกับการ์ดที่ไม่มีสื่อ การ์ดที่ไม่มีสื่อจะยังคงเป็นคอลัมน์เดียวในทุกความกว้าง และต้องไม่จองคอลัมน์สื่อที่ว่างเปล่า

จัดตำแหน่งการ์ดในตารางกริด

เมื่อการ์ดในแถวควรใช้ความสูงของภูมิภาคร่วมกัน ให้ใช้ subgrid: ทำให้การ์ดแต่ละใบครอบคลุมแทร็กแถวที่ใช้ร่วมกัน 4 แทร็ก (สื่อ, ส่วนหัว, เนื้อหา, ส่วนท้าย) และวางภูมิภาคตามตัวเลือกองค์ประกอบ โดยถือว่าทุกอย่างที่ไม่ใช่สื่อ ส่วนหัว หรือ <footer> เป็นเนื้อหา การ์ดที่ละเว้นขอบเขตจะปล่อยให้แทร็กว่างเปล่า ดังนั้นขอบเขตที่เหลือจะยังคงเรียงตามการ์ดที่อยู่ติดกัน แต่ละแทร็กจะมีรายการตารางกริด 1 รายการ ดังนั้นให้รวมขอบเขตเนื้อหาไว้ใน <div> เฉพาะเมื่อมีองค์ประกอบมากกว่า 1 รายการและการ์ดใช้แทร็กร่วมกัน การ์ดที่ไม่ได้จัดแนวกับองค์ประกอบข้างเคียงไม่จำเป็นต้องมี Wrapper หรือ Subgrid

รูปแบบการโต้ตอบ

การ์ดเนื้อหา

ใช้ <article> เป็นรูทของการ์ด เก็บลิงก์และปุ่มไว้เป็นตัวควบคุมเนทีฟแยกต่างหาก

การ์ดปลายทางเดียว

เมื่อการ์ดทั้งใบเป็นปลายทางเดียวและไม่มีการดำเนินการแยกต่างหาก ให้ใช้ลิงก์เนทีฟ 1 รายการ ลิงก์สามารถรวม <article> ได้ อย่าฝังลิงก์ ปุ่ม หรือตัวควบคุมแบบฟอร์มอื่นๆ ไว้ในลิงก์ และใช้ข้อความ "อ่านเพิ่มเติม" เป็น <p> หรือ <span> ธรรมดา เนื่องจากชื่อที่เข้าถึงได้ของลิงก์คือข้อความทั้งหมดของการ์ด โปรดทำให้เนื้อหาสั้น หากการ์ดมีข้อความหรือการดำเนินการอื่นๆ จำนวนมาก ให้ใช้รูปแบบลิงก์แบบยืดด้านล่างเพื่อให้เฉพาะส่วนหัวเป็นลิงก์

<a href="/recipes/poached-eggs">
  <article class="card">
    <h3>Poached eggs</h3>
    <p>Two poached eggs served on toasted sourdough.</p>
  </article>
</a>

การ์ดที่คลิกได้ซึ่งมีการดำเนินการแยกกัน

หากการคลิกการ์ดทริกเกอร์การดำเนินการแทนการไปยังส่วนต่างๆ ให้ใช้ <button> แทนลิงก์

เมื่อการ์ดเนื้อหาลิงก์ไปยังปลายทางหลัก มีองค์ประกอบแบบอินเทอร์แอกทีฟอื่นๆ และต้องคลิกได้ทั้งหมด ให้ทำดังนี้

  • ใช้การเลือกรับแบบครั้งเดียวในลิงก์หลัก โดยใส่ .card-link ในลิงก์เดียวต่อการ์ด (ลิงก์ส่วนหัว) ส่วนท้ายและลิงก์อื่นๆ จะไม่ได้รับคลาสนี้ ไม่เช่นนั้นแต่ละรายการจะขยายการวางซ้อนของตัวเอง และรายการสุดท้ายจะครอบคลุมทั้งการ์ด
  • ลิงก์ชื่อและขยายพื้นที่การกดตัวชี้ให้ครอบคลุมการ์ดด้วย ::after
.card:has(a.card-link) {
    position: relative;
}

.card a.card-link::after {
    content: "";
    position: absolute;
    inset: 0;
}
  • ยกระดับองค์ประกอบแบบอินเทอร์แอกทีฟด้วย position: relative; z-index: 1 เพื่อให้ยังคงใช้งานได้ กำหนดเป้าหมายประเภทขององค์ประกอบ (เช่น a, button) แทนที่จะกำหนดให้เลือกใช้ผ่านคลาส
  • อย่าใช้ z-index กับคอนเทนเนอร์ทั้งหมด เนื่องจากจะทำให้คอนเทนเนอร์จับเหตุการณ์เคอร์เซอร์ที่ไม่ทำให้เกิดการดำเนินการใดๆ
.card:has(a.card-link) {
    /* Keep other interactive elements above the overlay */
    a:not(.card-link), button, input, x-button {
        position: relative;
        z-index: 1;
    }
}
  • จัดรูปแบบการ์ดเมื่อวางเมาส์เหนือ/โฟกัส แทนที่จะเป็นลิงก์ที่ยืดออก
.card {
    a.card-link {
        &:focus-visible {
            outline: none; /* Draw it on the card instead */
        }
    }
    
    &:has(a.card-link:focus-visible) {
        /* Focus ring */
    }

    &:has(a.card-link:hover) {
        /* Hover styles */
    }
}

การ์ดตัวเลือก

สำหรับการ์ดที่แสดงตัวเลือกที่กำหนดไว้ล่วงหน้า ให้ใช้ <label class="card"> โดยมีช่องทำเครื่องหมายหรือปุ่มตัวเลือกเป็นรายการย่อยโดยตรง

จัดรูปแบบการ์ดที่เลือกด้วย :has(:checked) อย่าเปลี่ยนพร็อพเพอร์ตี้ที่ส่งผลต่อเลย์เอาต์ เช่น border-width, padding หรือ font-weight ในการเลือก เนื่องจากจะทำให้การ์ดและองค์ประกอบที่อยู่ติดกันขยับ ให้เน้นด้วย outline, box-shadow หรือเส้นขอบโปร่งใสที่เปลี่ยนเฉพาะสีเท่านั้น

.card {
  border: 2px solid transparent;

  &:has(> :checked) {
    border-color: var(--accent);
  }
}

ช่องทำเครื่องหมายหรือปุ่มตัวเลือกที่มองเห็นได้เป็นตัวบ่งชี้การเลือกที่ไม่ใช่สีอยู่แล้ว ดังนั้นการเปลี่ยนสีเพียงอย่างเดียวจึงเพียงพอ หากตัวควบคุมถูกซ่อนไว้ (ให้ตัวควบคุมยังคงโฟกัสได้และอยู่ในแผนผังการช่วยเหลือพิเศษ โดยไม่ใช้ display: none) ให้เพิ่มตัวบ่งชี้ที่ไม่ใช่สีซึ่งไม่ส่งผลต่อเลย์เอาต์ เช่น ไอคอนเครื่องหมายถูกหรือ outline ที่หนาขึ้น

เมื่อตัวเลือกอยู่ในเครื่องมือเลือกแบบเลื่อนลงซึ่งมีตัวเลือกที่จัดวางเป็นการ์ด ให้ใช้ <select> แบบเนทีฟที่มี appearance: base-select และจัดสไตล์องค์ประกอบ ::picker(select) และ <option> แทนที่จะแทนที่การเลือกด้วยการ์ด <div> โปรดดูรายละเอียดเพิ่มเติมและทางเลือกอื่นๆ ที่หัวข้อเลย์เอาต์เครื่องมือเลือกแบบกำหนดเอง