EST. 2026 — บันทึกงานเซิร์ฟเวอร์จริง SYSADMIN · SECURITY · AI · DIRECTADMIN เล่มที่ 01
THE SYSADMIN ALMANAC
หน้าหลัก / Web / วัด contrast จากพิกเซลจริง: แคปสองรอบ แล้วเทียบเฉพาะจุดที่มีตัวอักษร
Web

วัด contrast จากพิกเซลจริง: แคปสองรอบ แล้วเทียบเฉพาะจุดที่มีตัวอักษร

โดย Ton-Or ·14 พ.ย. 2026·อ่าน 12 นาที
วัด contrast จากพิกเซลจริง: แคปสองรอบ แล้วเทียบเฉพาะจุดที่มีตัวอักษร

ตัวเลข contrast ที่คำนวณจากสองสีใน CSS บอกได้เฉพาะเมื่อพื้นหลังเป็นสีเรียบสีเดียว พอพื้นหลังเป็นกระจกฝ้าเหนือรูปถ่าย ตัวเลขนั้นก็เป็นแค่ความเชื่อ ทางที่ตรงที่สุดคือวัดจากพิกเซลที่เบราว์เซอร์วาดออกมาจริง

สรุปใน 1 นาที

อาการ/ปัญหา
ตัวตรวจ contrast ที่อ่านสีจาก CSS ใช้ไม่ได้บนกระจกฝ้า gradient และรูปถ่าย
ใครควรอ่าน
คนทำเว็บที่ต้องวัด contrast บนพื้นหลังที่ไม่ใช่สีเรียบ
ทางแก้แบบสั้น
แคปหน้าสองรอบ รอบสองให้ตัวอักษรโปร่งใส หาพิกเซลของ glyph จากส่วนต่าง วัด contrast จากพิกเซลจริง แล้วแก้ด้วย token สีที่พลิกตาม dark mode
ข้ามไปขั้นตอน

พอดีผมทำ mockup เว็บแบบ glass คือกรอบกระจกฝ้าวางบนพื้นรูปถ่ายกับ gradient มีทั้งธีมสว่างและธีมมืด เครื่องตรวจ contrast ที่อ่านค่า color กับ background-color จาก CSS รายงานว่าผ่านเกือบหมด แต่พอผมเปิด dark mode ดูด้วยตา เจอตัวอักษรสีน้ำเงินแบรนด์วางบนพื้นกรมท่าที่แทบมองไม่เห็น กับการ์ดสีขาวที่ตัวอักษรข้างในจางจนต้องเพ่ง เครื่องตรวจบอกว่าผ่าน ตาผมบอกว่าอ่านไม่ออก ผมเลยเชื่อตา แล้วเขียนเครื่องมือใหม่ที่วัดจากพิกเซลที่ render จริงแทน

ชื่อโปรเจกต์และไฟล์จริงผมไม่เอามาเขียน สีแบรนด์ในตัวอย่างเป็นค่าสมมติ #1d6fd8 ส่วนโค้ดผมเขียนย่อใหม่ให้เห็นแก่นของวิธี ไม่ได้คัดทั้งไฟล์มาวาง

ทำไมการอ่านค่า CSS ถึงใช้ไม่ได้กับกระจกและรูปถ่าย

เครื่องตรวจแบบ CSS-only ทำสองอย่างคือ อ่านสีตัวอักษร แล้วไต่ขึ้นไปหา element บรรพบุรุษตัวแรกที่มี background-color มาเป็นพื้นหลัง จากนั้นคำนวณอัตราส่วนความสว่างตามสูตร WCAG วิธีนี้ถูกต้องเมื่อพื้นหลังเป็นสีทึบ แต่มันพังเมื่อเจอสามสถานการณ์

  • กระจกฝ้า: พื้นหลังของการ์ดเป็น rgba(255,255,255,.3) ที่ซ้อนเหนือรูป สีที่ตาเห็นคือผลผสมของการ์ดกับสิ่งที่อยู่ข้างหลัง ซึ่ง CSS ไม่รู้
  • gradient: ตัวอักษรบรรทัดเดียวกันอาจเริ่มบนส่วนอ่อนและจบบนส่วนเข้ม ค่าเฉลี่ยค่าเดียวใช้ไม่ได้
  • รูปถ่าย: ความสว่างหลังตัวอักษรเปลี่ยนไปทุกพิกเซล CSS ไม่มีข้อมูลนี้เลย
ภาพถ่ายการ์ดกระจกฝ้าใบเดียวกันสองภาพ ภาพซ้ายมีหัวข้อ ภาพขวาตัวอักษรหายไปเหลือแต่พื้นเบลอ มีไม้บรรทัดวางคั่นกลาง
การ์ดใบเดียวกันสองรอบ รอบแรกปกติ รอบสองเอาตัวอักษรออก ภาพรอบสองคือพื้นหลังจริงที่อยู่หลังตัวอักษรทุกพิกเซล

ข้อสุดท้ายคือสิ่งที่ผมต้องการ ถ้าผมได้ภาพของ "พื้นหลังล้วน ๆ" มาไว้ข้างภาพปกติ ผมก็รู้ได้ว่าหลังตัวอักษรแต่ละตัวมีสีอะไร

ไอเดีย: แคปสองรอบ ให้ตัวอักษรโปร่งใสในรอบที่สอง

หลักการมีแค่นี้ ถ่ายหน้าเว็บสองครั้งโดยไม่ขยับอะไรเลย รอบ A ถ่ายหน้าปกติ รอบ B ฉีด CSS ให้ตัวอักษรทุกตัวโปร่งใส เลย layout ไม่เปลี่ยน เพราะ color: transparent ไม่กระทบขนาดกล่อง ภาพ B เลยเป็นพื้นหลังจริงทั้งหมด จากนั้นเอาสองภาพมาลบกัน จุดที่ต่างกันคือพิกเซลของ glyph ส่วนสีของพิกเซลเดียวกันในภาพ B คือพื้นหลังจริงที่อยู่หลัง glyph นั้น

กลไกวัดภาพ Aหน้าปกติ->ภาพ Bตัวอักษรโปร่งใส->|A - B|หน้ากากของ glyph->พิกเซลของ Bตรงจุด glyph->ratioเทียบกับสีตัวอักษร
หนึ่งหน้า สองภาพ ลบกันแล้วได้พื้นหลังจริงใต้ตัวอักษร1 ภาพ Aหน้าเว็บปกติ1 ภาพ Bตัวอักษรโปร่งใส2 |A - B|จุดที่ต่าง = glyph3 พื้นหลังจริงค่าจาก B ตรงจุดนั้น4 ratiop5 และ p95CSS บอกว่า#fff บน #1d6fd8 = 4.9:1ผ่าน เพราะมองพื้นหลังเป็นสีเรียบพิกเซลจริงบนกระจกฝ้าและรูปถ่าย2.9:1 ไม่ผ่านเกณฑ์ 4.5ตัวเลขตัวอย่างสมมติ (illustrative)
ช่องล่างซ้ายคือสิ่งที่เครื่องตรวจแบบ CSS-only เห็น ช่องล่างขวาคือสิ่งที่ตาผู้ใช้เห็น ตัวเลข 2.9:1 เป็นตัวอย่างประกอบ ผมไม่ได้อ้างว่าเป็นผลตรวจของโปรเจกต์จริงตัวไหน

ขั้นตอนของสคริปต์ทีละข้อ

ผมใช้ Playwright กับ Chromium ที่ติดตั้งไว้ รันบน Node เจ็ดขั้นตามลำดับนี้ และแต่ละขั้นมีเหตุผลที่ผมเจอมาเอง ไม่ได้ใส่ไว้เฉย ๆ

  1. โหลดหน้า แล้วเลื่อนไปทั้งหน้าให้รูปแบบ lazy โหลดครบ ไม่งั้นพื้นหลังที่แคปได้เป็นกล่องว่างแทนรูป
  2. ตั้ง viewport ให้สูงเท่าหน้า (จำกัดสูงสุด 16000 px) เพราะการแคปแบบ fullPage จะ relayout ทำให้กล่องที่วัดพิกัดไว้ไม่ตรงกับพิกเซลที่ถ่าย
  3. ซ่อน element ที่เป็น position: fixed ปุ่มแชตหรือปุ่มแก้ไขที่ลอยอยู่พอ viewport สูงเท่าหน้าจะไปทับท้ายหน้า
  4. เก็บรายการ element ที่มี text node ของตัวเอง ข้ามตัวที่ซ่อน, opacity ใกล้ศูนย์, หรือเล็กกว่า 2 px พร้อมสีตัวอักษร ขนาด น้ำหนัก และกล่อง
  5. แคปภาพ A
  6. ฉีด CSS ให้ตัวอักษรโปร่งใส แล้วแคปภาพ B
  7. คำนวณต่อ element แล้วพิมพ์ [OK] หรือ [FAIL] n พร้อมแถวที่แย่สุด

โค้ดฉบับย่อที่ผมลองรันกับหน้าทดสอบเล็ก ๆ แล้ว ติดตั้งแค่ npm i playwright pngjs

// audit.cjs - วัด contrast จากพิกเซลที่ render จริง (ฉบับย่อ)
const { chromium } = require('playwright');
const { PNG } = require('pngjs');

const lin = c => { c /= 255; return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4; };
const lum = ([r, g, b]) => 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
const ratio = (a, b) => (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);
const pct = (arr, p) => arr[Math.min(arr.length - 1, Math.floor(arr.length * p))];

async function audit(url, scheme, width) {
  const b = await chromium.launch();
  const page = await b.newPage({ viewport: { width, height: 900 }, colorScheme: scheme });
  await page.goto(url, { waitUntil: 'networkidle' });

  // 1) เลื่อนให้รูป lazy โหลด แล้วขยาย viewport เท่าความสูงหน้า (กัน fullPage relayout)
  await page.evaluate(async () => {
    for (let y = 0; y < document.body.scrollHeight; y += 600) {
      scrollTo(0, y); await new Promise(r => setTimeout(r, 80));
    }
    scrollTo(0, 0);
  });
  const h = Math.min(16000, await page.evaluate(() => document.documentElement.scrollHeight));
  await page.setViewportSize({ width, height: h });

  // 2) ซ่อน fixed แล้วเก็บ element ที่มี text node ของตัวเอง
  const items = await page.evaluate(() => {
    for (const el of document.querySelectorAll('body *'))
      if (getComputedStyle(el).position === 'fixed') el.style.visibility = 'hidden';
    const out = [];
    for (const el of document.querySelectorAll('body *')) {
      const cs = getComputedStyle(el);
      if (cs.visibility === 'hidden' || cs.display === 'none' || +cs.opacity < 0.05) continue;
      if (![...el.childNodes].some(n => n.nodeType === 3 && n.textContent.trim())) continue;
      const r = el.getBoundingClientRect();
      if (r.width < 2 || r.height < 2) continue;
      out.push({ tag: el.tagName.toLowerCase(), text: el.textContent.trim().slice(0, 30),
        color: cs.color, size: parseFloat(cs.fontSize), weight: +cs.fontWeight,
        x: Math.round(r.left), y: Math.round(r.top + scrollY),
        w: Math.round(r.width), h: Math.round(r.height) });
    }
    return out;
  });

  // 3) รอบ A = ปกติ, รอบ B = ตัวอักษรโปร่งใส เหลือแต่พื้นหลังจริง
  const A = PNG.sync.read(await page.screenshot());
  await page.addStyleTag({ content: '*{color:transparent!important;-webkit-text-stroke-color:transparent!important;text-shadow:none!important;caret-color:transparent!important}' });
  const B = PNG.sync.read(await page.screenshot());
  await b.close();
  return { items, A, B };
}

ครึ่งหลังคือส่วนคำนวณ ซึ่งเป็นหัวใจของเรื่องนี้ ผมแยกเป็นฟังก์ชันของมันเอง

// ต่อจาก audit.cjs - คำนวณต่อ element
function score({ items, A, B }) {
  const fails = [];
  for (const it of items) {
    const m = it.color.match(/[\d.]+/g).map(Number);
    const fg = m.slice(0, 3), alpha = m.length > 3 ? m[3] : 1;

    // พิกเซลของ glyph = จุดที่ A ต่างจาก B (ผลรวมต่าง RGB >= 60)
    // สีพื้นหลัง = ค่าของ B ที่จุดเหล่านั้น (ขอบมนและ padding เลยไม่ถูกนับเป็นพื้นหลัง)
    const bg = [];
    for (let y = Math.max(0, it.y); y < Math.min(A.height, it.y + it.h); y++)
      for (let x = Math.max(0, it.x); x < Math.min(A.width, it.x + it.w); x++) {
        const i = (y * A.width + x) * 4;
        const d = Math.abs(A.data[i] - B.data[i]) + Math.abs(A.data[i + 1] - B.data[i + 1])
                + Math.abs(A.data[i + 2] - B.data[i + 2]);
        if (d >= 60) bg.push([B.data[i], B.data[i + 1], B.data[i + 2]]);
      }
    if (bg.length < 12) continue;       // glyph น้อยไป (ฉบับเต็มถอยไปใช้ทั้งกล่อง)

    // สีตัวอักษรที่มี alpha ถูกผสมกับค่าเฉลี่ยของพื้นหลัง
    const avg = [0, 1, 2].map(k => bg.reduce((s, p) => s + p[k], 0) / bg.length);
    const mixed = fg.map((c, k) => c * alpha + avg[k] * (1 - alpha));
    const L = lum(mixed);

    // เทียบกับ percentile ที่ 5 และ 95 ของความสว่างพื้นหลัง เอาตัวที่แย่กว่า
    const ls = bg.map(lum).sort((a, b) => a - b);
    const worst = Math.min(ratio(L, pct(ls, 0.05)), ratio(L, pct(ls, 0.95)));

    const large = it.size >= 24 || (it.size >= 18.66 && it.weight >= 700);
    const need = large ? 3 : 4.5;
    if (worst < need) fails.push({ ...it, worst: +worst.toFixed(2), need });
  }
  return fails;
}

ที่ใช้ percentile 5 กับ 95 แทนค่าเฉลี่ยก็เพราะพื้นหลังที่เป็นรูปถ่ายมีทั้งส่วนสว่างและมืดในกล่องเดียว ถ้าใช้ค่าเฉลี่ยตัวอักษรที่ครึ่งหนึ่งอยู่บนส่วนที่กลืนกับพื้นจะรอดไปได้ การเทียบกับปลายทั้งสองข้างแล้วเอาตัวที่แย่กว่า เท่ากับถามว่า "จุดที่แย่ที่สุดที่ตัวอักษรไปวางอยู่ อ่านออกไหม"

เกณฑ์ที่ใช้

ข้อความทั่วไปต้องได้ 4.5:1 ตัวใหญ่ (ตั้งแต่ 24 px หรือตั้งแต่ 18.66 px ถ้าเป็นตัวหนา) ใช้ 3:1 และ icon font ใช้ 3:1 ผมรันทั้งความกว้าง 1440 และ 390 กับทั้งโหมดสว่างและมืดผ่าน colorScheme ของ Playwright เพราะปัญหาจริงของผมโผล่เฉพาะ dark mode

ลองกับหน้าทดสอบเล็ก ๆ ก่อนเชื่อ

ก่อนเอาไปใช้กับงานจริง ผมสร้างหน้าทดสอบเล็ก ๆ ที่พื้นหลังเป็น gradient จากสีน้ำเงินไปขาว มีการ์ดโปร่งแสงวางทับ ข้างในเป็นตัวอักษรสีขาวหนึ่งบรรทัดกับสีดำหนึ่งบรรทัด แล้วรันสคริปต์ตามด้านบน ตัวสีดำผ่านทุกโหมด ตัวสีขาวบนการ์ดโปร่งแสงล้มในทุกรอบ

$ node audit.cjs file:///path/to/test.html
[FAIL] light 1440px - 1 element
   2.49:1 (ต้อง 4.5)  <p> "white on glass"
[FAIL] light 390px - 1 element
   1.7:1 (ต้อง 4.5)  <p> "white on glass"
[FAIL] dark 1440px - 1 element
   2.49:1 (ต้อง 4.5)  <p> "white on glass"
[FAIL] dark 390px - 1 element
   1.7:1 (ต้อง 4.5)  <p> "white on glass"

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

ข้อจำกัดที่ต้องรู้ก่อนใช้

สคริปต์ไม่วัดข้อความที่มาจาก ::before หรือ ::after (เช่นเลขขั้นตอนที่ใส่ผ่าน content) พวกนั้นต้องดูด้วยตา และข้อความที่อยู่บนวิดีโอหรือ canvas ที่เคลื่อนไหวได้ ผลที่ได้คือภาพ ณ จังหวะที่แคปเท่านั้น ผมไม่ได้วัดว่าสคริปต์ใช้เวลานานแค่ไหนกับหน้ายาว ๆ เลยไม่ขอบอกตัวเลข

อ่านรายการ FAIL ให้เป็น

เวลารายการ [FAIL] ยาว ถ้าไล่แก้ตามลำดับที่พิมพ์ออกมาจะเหนื่อยเปล่า ผมเลยเรียงจากอัตราส่วนแย่สุดก่อน แล้วดูว่าแถวที่แย่เหล่านั้นมีรูปแบบร่วมกันไหม เช่นเป็น class เดียวกัน อยู่ใน section เดียวกัน หรือใช้สีแบรนด์ตัวเดียวกันเป็นตัวอักษร ถ้ามีรูปแบบร่วม แปลว่าต้นเหตุอยู่ที่ token หรือ component ตัวเดียว แก้ที่นั่นทีเดียวแถวที่เหลือก็หายตามกัน สิ่งที่ผมไม่ทำคือเปิด DevTools แล้วเปลี่ยนสีทีละ element เพราะแก้ได้แต่ไม่ได้เรียนรู้อะไร ตัวสคริปต์เองก็พิมพ์ tag กับข้อความสั้น ๆ ของ element ออกมา เพื่อให้เห็นรูปแบบนั้นได้เร็ว

อย่าแก้ทีละจุด ใช้ token ที่พลิกตามโหมด

พอได้รายการ [FAIL] มาแล้ว สิ่งที่ล่อใจคือไล่แก้สีทีละ element ซึ่งผมลองแล้วไม่ได้ผล แก้จุดหนึ่งผ่านในโหมดสว่าง ไปพังในโหมดมืด แล้วพรุ่งนี้มีการ์ดใบใหม่ก็พังซ้ำ ทางที่ได้ผลคือเปลี่ยนวิธีคิดเรื่องสี ให้ใช้ semantic token ที่รู้ตัวเองว่าอยู่โหมดไหน

หน้าจอแดชบอร์ดโหมดมืดที่มีตัวอักษรสีน้ำเงินบนพื้นกรมท่า และมือถือถือการ์ดตัวอย่างสีอ่อนเทียบข้าง ๆ
สีแบรนด์ตัวเดียวกันอ่านง่ายบนพื้นขาวแต่จมบนพื้นกรมท่า ทางออกคือสีตัวอักษรอีกค่าสำหรับโหมดมืด ไม่ใช่การปรับสีแบรนด์ทุกที่
:root {
  --brand: #1d6fd8;                       /* สีแบรนด์ ใช้กับพื้น/เส้น/ปุ่มทึบเท่านั้น */
  --brand-text: #1d6fd8;                  /* สีแบรนด์เมื่อใช้เป็นตัวอักษรหรือไอคอน */
  --surface-2: rgba(255, 255, 255, .72);  /* การ์ดย่อยบนกระจก */
  --tint: rgba(29, 111, 216, .10);        /* พื้นของชิป/ปุ่ม ghost */
  --tint-border: rgba(29, 111, 216, .35);
  --ok: #17703f;                          /* ไอคอนสถานะสำเร็จ เข้มขึ้นในโหมดสว่าง */
}
@media (prefers-color-scheme: dark) {
  :root {
    --brand-text: #a9cbf6;                /* tint อ่อน แทนสีแบรนด์ตรง ๆ */
    --surface-2: rgba(255, 255, 255, .07);
    --tint: rgba(169, 203, 246, .12);
    --tint-border: rgba(169, 203, 246, .35);
    --ok: #86d9ad;                        /* อ่อนลงในโหมดมืด */
  }
}

.link, .icon-accent { color: var(--brand-text); }     /* ไม่ใช้ var(--brand) เป็นตัวอักษร */
.card-inner         { background: var(--surface-2); } /* ไม่ใช้ #fff ตายตัว */
.chip, .btn-ghost   { background: var(--tint); border: 1px solid var(--tint-border); color: var(--brand-text); }

สองแนวทางเทียบกันได้ตามนี้

แก้ทีละจุด

เปลี่ยนสีที่ element ที่ล้ม

ผ่านโหมดเดียว พังอีกโหมด และการ์ดใหม่ที่เพิ่มทีหลังพังซ้ำ ต้องไล่ตรวจเองทุกครั้ง ตัวเลือกสีกระจายอยู่ทั่วไฟล์

ใช้ token

ห้ามใช้สีแบรนด์ตรง ๆ เป็นตัวอักษร

ตัวอักษรและไอคอนใช้ --brand-text การ์ดย่อยใช้ --surface-2 ชิปใช้ --tint ทุกตัวพลิกตามโหมด แก้ที่เดียวทั้งเว็บเปลี่ยนตาม

นอกจากชุด token ข้างบน ยังมีเรื่องเฉพาะจุดที่เครื่องวัดจับได้และผมแก้ด้วยวิธีเฉพาะ

  • ข้อความบนรูป: เพิ่มความทึบของ overlay หรือ gradient ที่ครอบจนผ่าน แถบ CTA ของผมไปลงตัวที่ประมาณ .9
  • ตัวเลขแบบ outline ที่ใช้ -webkit-text-stroke ล้มบนพื้นมืด ผมใส่สีเติมด้วย --brand-text ให้มีเนื้อสีจริง
  • dropdown ในแถบเมนูแบบเบลอ: ตัวอักษรของ dropdown ทะลุเห็นพื้นหลัง วิธีที่ผมแก้คือย้ายการเบลอของ nav ไปอยู่ที่ ::before ของ nav แทน
/* ก่อน: เบลอที่ nav โดยตรง dropdown ที่ซ้อนอยู่ข้างในเบลอพื้นหลังไม่ได้ ตัวอักษรทะลุ */
/* .nav { backdrop-filter: blur(14px); } */

/* หลัง: ให้ ::before เป็นตัวเบลอ nav เองไม่มี backdrop-filter */
.nav { position: sticky; top: 0; }
.nav::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  backdrop-filter: blur(14px);
}

เรื่อง dropdown นี้ผมรู้แค่ว่าย้ายแล้วอาการหาย ส่วนกลไกในเบราว์เซอร์ที่ทำให้ backdrop-filter ซ้อนกันไม่เห็นพื้นหลังเดิม ผมไม่ได้พิสูจน์ในบทความนี้

วงจรที่ผมใช้ทุกครั้ง

2 ภาพต่อหน้า ต่อโหมด
16000 pxเพดานความสูง viewport
60เกณฑ์ผลต่าง RGB ของ glyph
12 pxglyph ขั้นต่ำก่อนวัด
5 / 95percentile ของพื้นหลัง
4.5 : 3เกณฑ์ปกติ : ตัวใหญ่

ลำดับที่ผมทำจริงคือรันสคริปต์กับสี่ชุด (สว่างกับมืด คูณ 1440 กับ 390) ดูรายการ [FAIL] เรียงจากแย่สุด แก้ที่ token ไม่ใช่ที่ element รันซ้ำจนได้ [OK] ทั้งสี่ชุด แล้วสุดท้ายเปิดภาพ crop ของโหมดมืดตรงส่วนที่ผมเคยชี้ด้วยตาว่าอ่านไม่ออก ดูให้เห็นเองอีกรอบ เพราะเครื่องมือวัดบอกได้ว่ามีเสียงดังจากตรงไหน แต่ตัดสินแทนตาไม่ได้ทั้งหมด โดยเฉพาะส่วนที่เป็น ::before ที่สคริปต์มองไม่เห็น

ส่วนตัวผมถ้าหน้าเว็บมีกระจกฝ้าหรือรูปเป็นพื้นหลัง ผมเลิกเชื่อเครื่องตรวจแบบอ่านค่า CSS อย่างเดียวแล้วครับ ใครจะเอาสคริปต์ย่อด้านบนไปปรับเกณฑ์หรือ percentile ให้เหมาะกับงานตัวเองก็ตามสะดวก เดี๋ยวกลับมาแก้เพิ่มให้ภายหลังครับ

เคยเจองานแบบนี้ไหม? ติดตรงไหน?

มาแลกวิธีกันต่อในบอร์ด LinuxThai

→ คุยต่อในบอร์ด

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

ยังไม่มีความคิดเห็น — เป็นคนแรกเลย