ข้ามไปยังเนื้อหาหลัก
ProgrammerThailand

AI & Vibe Coding

จาก Mockup เป็น HTML/CSS ด้วย AI

จาก Mockup เป็น HTML/CSS ด้วย AI

เครื่องมือ AI หลายตัวรับภาพได้แล้ว การส่ง screenshot ของ mockup แล้วขอ HTML/CSS กลับมาจึงเป็นงานที่ทำได้เร็วมาก แต่ถ้าส่งแค่ภาพแล้วพิมพ์ว่า "ทำให้เหมือนนี้" สิ่งที่ได้มักเป็น div ซ้อนกันหลายชั้น ความกว้างตายตัวเป็น px ใช้ได้บนจอเดียว และไม่มีสถานะ focus บทความนี้จะพาไปตั้งแต่การเตรียมภาพกับข้อกำหนด การเขียน prompt ให้ได้ semantic HTML ที่ responsive การตรวจด้วยตาตัวเองในหลายขนาดจอ และตัวอย่างการ์ดสินค้าด้วย CSS Grid ที่นำไปใช้ต่อใน view ของ Yii2 ได้

ภาพอย่างเดียวไม่พอ ต้องมีข้อกำหนดด้วย

ภาพ mockup บอกหน้าตาที่ขนาดจอเดียว แต่ไม่ได้บอกพฤติกรรม AI จึงต้องเดาเรื่องที่ภาพไม่ได้แสดง เช่น จอมือถือเรียงอย่างไร ข้อความยาวกว่าตัวอย่างแล้วจะเป็นอย่างไร ปุ่มเมื่อ hover หรือ focus หน้าตาแบบไหน ให้เตรียมสิ่งเหล่านี้ไปพร้อมภาพ

  • ภาพหลายขนาด ถ้ามี mockup มือถือและเดสก์ท็อป ส่งทั้งคู่ ถ้ามีแค่แบบเดียวให้อธิบายพฤติกรรมบนจออื่นเป็นข้อความ
  • design tokens สีหลัก สีพื้นหลัง ฟอนต์ ขนาดตัวอักษร ระยะห่าง เป็นค่าที่ชัดเจน ไม่ให้ AI ดูดสีจากภาพเอง ซึ่งมักคลาดเคลื่อน
  • เนื้อหาจริงหรือใกล้เคียงจริง โดยเฉพาะภาษาไทยที่ยาวและมีสระบนล่าง ข้อความ lorem ipsum ทำให้ไม่เห็นปัญหาการตัดบรรทัด
  • สถานะต่าง ๆ hover, focus, disabled, กรณีไม่มีรูป, กรณีข้อความยาวมาก
  • ข้อจำกัดทางเทคนิค เช่น ใช้ CSS ล้วนไม่มี framework หรือใช้ Bootstrap 5 ที่มากับโปรเจกต์ Yii2 รองรับ browser ไหนบ้าง

อย่าลืมว่าภาพ mockup จากงานลูกค้าอาจมีข้อมูลภายในหรือข้อมูลส่วนบุคคล ตรวจและเบลอส่วนที่ไม่ควรออกไปก่อนส่งให้บริการ AI ภายนอก

Prompt ที่ขอ semantic HTML และ responsive

ตัวอย่าง prompt ที่ใช้ได้จริง แนบภาพการ์ดสินค้าไปด้วย

แนบภาพ mockup ส่วน "สินค้าแนะนำ" ของหน้าแรก (เดสก์ท็อป 3-4 คอลัมน์)
ช่วยเขียน HTML และ CSS ตามข้อกำหนดนี้
- ใช้ semantic HTML: section ที่มีหัวข้อ, รายการการ์ดเป็น ul/li, แต่ละการ์ดใช้ article
- ทั้งการ์ดคลิกได้ผ่านลิงก์ที่ชื่อสินค้า (ไม่ห่อทั้งการ์ดด้วย a)
- mobile first: จอเล็ก 1 คอลัมน์ แล้วเพิ่มคอลัมน์อัตโนมัติด้วย CSS Grid ไม่ใช้ media query ถ้าไม่จำเป็น
- ใช้ CSS custom properties สำหรับสีและระยะ ค่าตามนี้: --color-primary #1d4ed8, --radius 0.75rem
- หน่วยใช้ rem และ % ไม่กำหนดความสูงตายตัวให้การ์ด
- รูปใช้ img ที่มี alt, width, height และ loading="lazy" อัตราส่วน 4:3
- มี :focus-visible ที่มองเห็นชัด
- ข้อความภาษาไทยยาวต้องไม่ล้นการ์ด
ห้ามใช้ JavaScript ห้ามใช้ library อื่น ส่งเป็น HTML หนึ่งบล็อกและ CSS หนึ่งบล็อก

สังเกตว่าเราบอกทั้ง "ให้ทำอะไร" และ "ห้ามทำอะไร" รายละเอียดพวกนี้คือสิ่งที่ AI มักทำต่างจากที่ต้องการถ้าไม่ระบุ

ตัวอย่างผลลัพธ์: การ์ดด้วย CSS Grid

นี่คือผลที่ได้หลังตรวจและปรับแล้ว ส่วน HTML:

<section class="products" aria-labelledby="products-title">
  <h2 id="products-title">สินค้าแนะนำ</h2>
  <ul class="card-grid">
    <li>
      <article class="card">
        <img src="/images/mug.jpg" alt="แก้วเซรามิกสีขาว ลายช้างไทย"
             width="400" height="300" loading="lazy">
        <div class="card-body">
          <h3 class="card-title">
            <a href="/product/view?id=12">แก้วเซรามิกลายช้าง ขนาด 350 มล.</a>
          </h3>
          <p class="card-text">เข้าไมโครเวฟได้ ล้างด้วยเครื่องล้างจานได้</p>
          <p class="card-price">฿290</p>
        </div>
      </article>
    </li>
    <!-- การ์ดอื่น ๆ -->
  </ul>
</section>

ส่วน CSS:

:root {
  --color-primary: #1d4ed8;
  --color-text: #1f2937;
  --color-muted: #4b5563;
  --color-border: #e5e7eb;
  --radius: 0.75rem;
  --space: 1rem;
}

.card-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(16rem, 100%), 1fr));
  gap: var(--space);
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  overflow: hidden;
  background: #fff;
}

.card img {
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.card-body {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: var(--space);
  flex: 1;
}

.card-title {
  margin: 0;
  font-size: 1.125rem;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.card-title a {
  color: var(--color-text);
  text-decoration: none;
}

/* ให้พื้นที่ทั้งการ์ดคลิกได้ โดยยังมีลิงก์เดียว */
.card-title a::after {
  content: "";
  position: absolute;
  inset: 0;
}

.card:hover .card-title a {
  text-decoration: underline;
}

.card-title a:focus-visible {
  outline: none;
}

.card:has(a:focus-visible) {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
}

.card-text {
  margin: 0;
  color: var(--color-muted);
}

.card-price {
  margin: auto 0 0;
  font-weight: 700;
  color: var(--color-primary);
}

จุดสำคัญที่ควรเข้าใจ ไม่ใช่แค่ copy ไปใช้:

  • repeat(auto-fill, minmax(min(16rem, 100%), 1fr)) ทำให้จำนวนคอลัมน์ปรับตามความกว้างเองโดยไม่ต้องเขียน media query และ min(16rem, 100%) กันการ์ดล้นบนจอที่แคบกว่า 16rem
  • เทคนิค ::after บนลิงก์ทำให้คลิกได้ทั้งการ์ด แต่ screen reader อ่านลิงก์เพียงชื่อสินค้า ไม่ต้องอ่านเนื้อหาทั้งการ์ดเป็นข้อความลิงก์
  • :has() ใช้แสดง focus ที่ระดับการ์ด ถ้าต้องรองรับ browser เก่าที่ยังไม่รองรับ selector นี้ ให้ใส่ outline ที่ลิงก์แทน
  • overflow-wrap: anywhere ช่วยเมื่อข้อความยาวไม่มีช่องว่าง ซึ่งพบบ่อยในภาษาไทยและ URL

ตรวจด้วยตาตัวเอง อย่าเชื่อแค่ "เหมือนภาพ"

AI ไม่ได้เห็นผลการ render จริงบน browser ของเรา ต่อให้มันบอกว่า "ตรงตาม mockup" ก็ต้องตรวจเอง เช็กลิสต์ที่ใช้:

  1. เปิด DevTools โหมด responsive ลากความกว้างจากจอแคบที่สุดไปจนกว้างที่สุด ดูว่ามีจุดไหนที่ layout แตกหรือมี scroll แนวนอน
  2. ใส่ข้อความไทยยาวเป็นสามเท่าของตัวอย่างในชื่อสินค้า และลองกรณีไม่มีรูป
  3. ซูม browser เป็น 200% ตัวอักษรต้องไม่ทับกันและยังอ่านได้
  4. กด Tab ไล่ทั้งหน้า ต้องเห็นตำแหน่ง focus ชัดทุกครั้ง
  5. เทียบสีและระยะกับ design tokens ไม่ใช่เทียบด้วยความรู้สึก
  6. ใช้เครื่องมือ validator ตรวจ HTML และดูว่ามีหัวข้อเรียงลำดับถูกต้อง

ถ้าพบปัญหา ให้ส่ง screenshot ของปัญหาพร้อมความกว้างจอกลับไปให้ AI แก้ ซึ่งได้ผลดีกว่าการบอกว่า "มือถือแสดงผลไม่สวย"

ปัญหาที่พบบ่อยในโค้ดจาก AI และวิธีแก้

  • div soup ทุกอย่างเป็น div แก้โดยระบุ element ที่ต้องการใน prompt และ review ว่ามี header, nav, main, section ถูกที่
  • ความสูงตายตัว เช่น height: 420px ที่การ์ด ทำให้ข้อความยาวล้น ให้ใช้ flex และ margin-top: auto ดันราคาไว้ล่างแทน
  • ใช้ div เป็นปุ่ม พร้อม onclick ให้เปลี่ยนเป็น button หรือ a ตามหน้าที่ รายละเอียดอยู่ในบทความ "ให้ AI ช่วยตรวจ Accessibility (a11y)"
  • รูปและไอคอนที่ไม่มีอยู่จริง AI อาจอ้าง path รูปหรือ icon font ที่ไม่มีในโปรเจกต์ ตรวจทุก src และ class ไอคอน
  • CSS ชนกับของเดิม class ชื่อกว้าง ๆ อย่าง .card อาจชนกับ Bootstrap ถ้าโปรเจกต์ใช้ Bootstrap อยู่ ให้ตั้ง prefix หรือขอให้ AI ใช้ utility class ของ Bootstrap แทน

เมื่อจะนำไปใช้ใน Yii2 ให้แยกการ์ดเป็น partial view แล้วใช้ Html::encode() กับชื่อและรายละเอียดสินค้าทุกครั้ง และสร้างลิงก์ด้วย Url::to() แทนการต่อสตริงเอง

สรุป

  • ส่งภาพพร้อมข้อกำหนด: design tokens, เนื้อหาจริง, สถานะต่าง ๆ และพฤติกรรมบนจอขนาดอื่น
  • ระบุใน prompt ให้ใช้ semantic HTML, mobile first, หน่วย rem และห้ามความสูงตายตัว
  • CSS Grid กับ auto-fill และ minmax ทำการ์ด responsive ได้โดยแทบไม่ต้องใช้ media query
  • ตรวจด้วยตาเองในหลายความกว้าง ข้อความยาว ซูม 200% และคีย์บอร์ด ก่อนรับโค้ด

ลองทำ

เลือกหนึ่งส่วนของหน้าเว็บที่คุณดูแล เช่น รายการข่าวหรือรายการบริการ ถ่าย screenshot แล้วเขียน prompt ตามโครงในบทความนี้ ขอ HTML และ CSS ด้วย CSS Grid จากนั้นตรวจตามเช็กลิสต์ 6 ข้อ จดว่าต้องแก้กี่จุด และจุดไหนที่เพิ่มลงใน prompt ครั้งหน้าแล้วจะไม่ต้องแก้อีก

ติดปัญหาตอนทำตาม? ถามในชุมชน

ความคิดเห็น (0)

ยังไม่มีความคิดเห็น — เริ่มคุยเป็นคนแรก ถามสิ่งที่สงสัย หรือแชร์ประสบการณ์ของคุณ