ใช้แบบอักษรขั้นสูงกับแบบอักษรในเครื่อง

เรียนรู้วิธีที่ Local Font Access API อนุญาตให้คุณเข้าถึงแบบอักษรที่ติดตั้งในเครื่องของผู้ใช้และรับรายละเอียดระดับต่ำเกี่ยวกับแบบอักษร

แบบอักษรที่ปลอดภัยสำหรับเว็บ

หากคุณทํางานด้านการพัฒนาเว็บมาอย่างยาวนาน คุณอาจคุ้นเคยกับสิ่งที่เรียกว่าแบบอักษรที่ปลอดภัยบนเว็บ แบบอักษรเหล่านี้เป็นที่รู้จักกันว่ามีให้บริการในอินสแตนซ์เกือบทั้งหมดของระบบปฏิบัติการที่ใช้มากที่สุด (ได้แก่ Windows, macOS, ดิสทริบิวชัน Linux ที่พบบ่อยที่สุด, Android และ iOS) ในช่วงต้นทศวรรษ 2000 Microsoft เป็นหัวหอกของโครงการริเริ่มที่เรียกว่าแบบอักษรหลัก TrueType สำหรับเว็บที่จัดหาแบบอักษรดังกล่าวให้ดาวน์โหลดฟรีโดยมีวัตถุประสงค์ที่ว่า "เมื่อใดก็ตามที่คุณเข้าชมเว็บไซต์ที่ระบุแบบอักษรดังกล่าว คุณจะเห็นหน้าเว็บตรงตามที่นักออกแบบเว็บไซต์ตั้งใจไว้" ใช่ ซึ่งรวมถึงเว็บไซต์ที่ตั้งค่าเป็น Comic Sans MS ต่อไปนี้คือตัวอย่างสแต็กแบบอักษรที่ปลอดภัยสำหรับเว็บแบบคลาสสิก (พร้อมแบบอักษรสำรองขั้นสุดท้ายสำหรับsans-serif)

body {
  font-family: Helvetica, Arial, sans-serif;
}

แบบอักษรเว็บ

ยุคสมัยที่แบบอักษรสำหรับความปลอดภัยของเว็บมีความสำคัญอย่างยิ่งยวดนั้นหายไปนานแล้ว ปัจจุบันเรามีแบบอักษรเว็บ ซึ่งบางแบบอาจเป็นแบบอักษรที่เปลี่ยนแปลงได้ ซึ่งเราสามารถปรับแต่งเพิ่มเติมได้โดยการเปลี่ยนค่าสำหรับแกนต่างๆ ที่เปิดเผย คุณสามารถใช้แบบอักษรบนเว็บได้โดยประกาศบล็อก @font-face ที่จุดเริ่มต้นของ CSS ซึ่งจะระบุไฟล์แบบอักษรที่จะดาวน์โหลด

@font-face {
  font-family: 'FlamboyantSansSerif';
  src: url('flamboyant.woff2');
}

หลังจากนั้น คุณจะใช้แบบอักษรเว็บที่กำหนดเองได้โดยระบุ font-family ตามปกติ

body {
  font-family: 'FlamboyantSansSerif';
}

แบบอักษรในเครื่องเป็นเวกเตอร์ลายนิ้วมือ

แบบอักษรเว็บส่วนใหญ่มาจากเว็บ แต่ข้อเท็จจริงที่น่าสนใจคือพร็อพเพอร์ตี้ src ในประกาศ @font-face นอกเหนือจากฟังก์ชัน url() แล้ว ยังยอมรับฟังก์ชัน local() ด้วย ซึ่งจะช่วยให้โหลดแบบอักษรที่กำหนดเองในเครื่องได้ (ว้าว) หากผู้ใช้ติดตั้ง FlamboyantSansSerif ในระบบปฏิบัติการไว้ ระบบจะใช้สำเนาในเครื่องแทนที่จะดาวน์โหลด

@font-face {
  font-family: 'FlamboyantSansSerif';
  src: local('FlamboyantSansSerif'), url('flamboyant.woff2');
}

แนวทางนี้ช่วยสร้างกลไกสำรองที่อาจช่วยประหยัดแบนด์วิดท์ได้ น่าเสียดายบนอินเทอร์เน็ต ที่เราไม่สามารถทำสิ่งดีๆ ปัญหาของฟังก์ชัน local() คืออาจมีการละเมิดเพื่อใช้ลายนิ้วเบราว์เซอร์ ปรากฏว่ารายการแบบอักษรที่ผู้ใช้ติดตั้งนั้นดูออกจะค่อนข้างชัดเจน บริษัทจำนวนมากมีแบบอักษรของบริษัทเองที่ติดตั้งไว้ในแล็ปท็อปของพนักงาน เช่น Google มีแบบอักษรขององค์กรชื่อ Google Sans

แอป macOS Font Book ที่แสดงตัวอย่างแบบอักษร Google Sans
แบบอักษร Google Sans ที่ติดตั้งในแล็ปท็อปของพนักงาน Google

ผู้โจมตีอาจพยายามระบุบริษัทที่ผู้ใช้ทำงานด้วยโดยทดสอบว่ามีการใช้แบบอักษรขององค์กรที่รู้จักจำนวนมากหรือไม่ เช่น Google Sans ผู้โจมตีจะพยายามแสดงผลข้อความที่ตั้งค่าแบบอักษรเหล่านี้บนผืนผ้าใบและวัดค่าแบบอักษร หากสัญลักษณ์ตรงกับรูปร่างที่รู้จักของแบบอักษรขององค์กร ผู้โจมตีก็จะพบคำที่ตรงกัน หากรูปอักขระไม่ตรงกัน ผู้โจมตีจะทราบว่ามีการใช้แบบอักษรแทนที่เริ่มต้นตั้งแต่ไม่ได้ติดตั้งแบบอักษรขององค์กร อ่านรายละเอียดทั้งหมดเกี่ยวกับการโจมตีด้วยลายนิ้วเบราว์เซอร์รูปแบบนี้และรูปแบบอื่นๆ ได้ที่บทความสํารวจโดย Laperdix et al.

นอกจากแบบอักษรของบริษัทแล้ว แม้แต่รายการแบบอักษรที่ติดตั้งไว้ก็สามารถระบุตัวตนได้ สถานการณ์ของเวกเตอร์การโจมตีนี้เริ่มเลวร้ายมากจนกระทั่งเมื่อเร็วๆ นี้ ทีม WebKit ได้ตัดสินใจ ที่จะ"รวมเฉพาะแบบอักษรและแบบอักษรของเว็บ [ในรายการแบบอักษรที่ใช้ได้] ที่มาพร้อมกับระบบปฏิบัติการ แต่ไม่รวมแบบอักษรที่ผู้ใช้ติดตั้งในเครื่อง" (นี่คือบทความเกี่ยวกับการให้สิทธิ์ การเข้าถึงแบบอักษรในเครื่อง)

Local Font Access API

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

เหตุใดเราจึงต้องใช้ Local Font Access API เมื่อมีแบบอักษรของเว็บ

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

  • เครื่องมือออกแบบจำเป็นต้องเข้าถึงไบต์แบบอักษรเพื่อใช้เลย์เอาต์ OpenType ของตนเอง และอนุญาตให้เครื่องมือออกแบบเชื่อมต่อในระดับที่ต่ำกว่าได้ เพื่อดำเนินการต่างๆ เช่น การใช้ฟิลเตอร์เวกเตอร์หรือการเปลี่ยนรูปแบบรูปร่างของสัญลักษณ์
  • นักพัฒนาแอปอาจมีสแต็กแบบอักษรเดิมสำหรับแอปพลิเคชันที่จะนําไปใช้กับเว็บ หากต้องการใช้สแต็กเหล่านี้ โดยปกติจะต้องมีสิทธิ์เข้าถึงข้อมูลแบบอักษรโดยตรง แต่แบบอักษรของเว็บไม่ได้ให้ไว้
  • แบบอักษรบางรายการอาจไม่ได้รับอนุญาตให้แสดงผ่านเว็บ ตัวอย่างเช่น Linotype มีใบอนุญาตสำหรับแบบอักษรบางแบบที่มีไว้สำหรับการใช้งานบนเดสก์ท็อปเท่านั้น

Local Font Access API เป็นการพยายามแก้ปัญหาเหล่านี้ ซึ่งประกอบด้วย 2 ส่วน ดังนี้

  • API การระบุแบบอักษร ซึ่งช่วยให้ผู้ใช้ให้สิทธิ์เข้าถึงชุดแบบอักษรของระบบที่ใช้ได้ทั้งหมด
  • จากผลลัพธ์การแจกแจงแต่ละรายการ ความสามารถในการขอการเข้าถึงคอนเทนเนอร์ SFNT ระดับต่ำ (แบบไบต์) ที่มีข้อมูลแบบอักษรทั้งหมด

การสนับสนุนเบราว์เซอร์

การรองรับเบราว์เซอร์

  • Chrome: 103
  • ขอบ: 103
  • Firefox: ไม่รองรับ
  • Safari: ไม่รองรับ

แหล่งที่มา

วิธีใช้ Local Font Access API

การตรวจหาองค์ประกอบ

หากต้องการตรวจสอบว่าระบบรองรับ Local Font Access API หรือไม่ ให้ใช้

if ('queryLocalFonts' in window) {
  // The Local Font Access API is supported
}

การระบุแบบอักษรในเครื่อง

หากต้องการดูรายการแบบอักษรที่ติดตั้งในเครื่อง คุณต้องเรียกใช้ window.queryLocalFonts() การดำเนินการนี้จะทริกเกอร์ข้อความแจ้งสิทธิ์เป็นครั้งแรก ซึ่งผู้ใช้สามารถอนุมัติหรือปฏิเสธได้ในครั้งแรก หากผู้ใช้อนุญาตให้ค้นหาแบบอักษรในเครื่องได้ เบราว์เซอร์จะแสดงผลอาร์เรย์ที่มีข้อมูลแบบอักษรซึ่งคุณนำไปใช้วนซ้ำได้ แบบอักษรแต่ละแบบจะแสดงเป็นออบเจ็กต์ FontData ที่มีพร็อพเพอร์ตี้ family (เช่น "Comic Sans MS"), fullName (เช่น "Comic Sans MS"), postscriptName (เช่น "ComicSansMS") และ style (เช่น "Regular")

// Query for all available fonts and log metadata.
try {
  const availableFonts = await window.queryLocalFonts();
  for (const fontData of availableFonts) {
    console.log(fontData.postscriptName);
    console.log(fontData.fullName);
    console.log(fontData.family);
    console.log(fontData.style);
  }
} catch (err) {
  console.error(err.name, err.message);
}

หากสนใจเฉพาะแบบอักษรชุดย่อย คุณยังกรองแบบอักษรตามชื่อ PostScript ได้อีกด้วยโดยเพิ่มพารามิเตอร์ postscriptNames

const availableFonts = await window.queryLocalFonts({
  postscriptNames: ['Verdana', 'Verdana-Bold', 'Verdana-Italic'],
});

การเข้าถึงข้อมูล SFNT

สิทธิ์เข้าถึง SFNT โดยสมบูรณ์เข้าถึงได้ผ่านเมธอด blob() ของออบเจ็กต์ FontData SFNT คือรูปแบบไฟล์แบบอักษรที่อาจมีแบบอักษรอื่นๆ เช่น PostScript, OpenType, Web Open Font Format (WOFF) และอื่นๆ

try {
  const availableFonts = await window.queryLocalFonts({
    postscriptNames: ['ComicSansMS'],
  });
  for (const fontData of availableFonts) {
    // `blob()` returns a Blob containing valid and complete
    // SFNT-wrapped font data.
    const sfnt = await fontData.blob();
    // Slice out only the bytes we need: the first 4 bytes are the SFNT
    // version info.
    // Spec: https://docs.microsoft.com/en-us/typography/opentype/spec/otff#organization-of-an-opentype-font
    const sfntVersion = await sfnt.slice(0, 4).text();

    let outlineFormat = 'UNKNOWN';
    switch (sfntVersion) {
      case '\x00\x01\x00\x00':
      case 'true':
      case 'typ1':
        outlineFormat = 'truetype';
        break;
      case 'OTTO':
        outlineFormat = 'cff';
        break;
    }
    console.log('Outline format:', outlineFormat);
  }
} catch (err) {
  console.error(err.name, err.message);
}

สาธิต

คุณดูการทำงานของ Local Font Access API ได้ในเดโมด้านล่าง อย่าลืมดูซอร์สโค้ดด้วย การแสดงตัวอย่างจะแสดงองค์ประกอบที่กำหนดเองชื่อ <font-select> ที่ใช้เครื่องมือเลือกแบบอักษรในเครื่อง

ข้อควรพิจารณาเกี่ยวกับความเป็นส่วนตัว

สิทธิ์ "local-fonts" ดูเหมือนว่าจะมีแพลตฟอร์มที่ตรวจหาลายนิ้วมือได้สูง อย่างไรก็ตาม เบราว์เซอร์สามารถแสดงผลทุกอย่างที่ต้องการได้ฟรี เช่น เบราว์เซอร์ที่เน้นความเป็นส่วนตัวอาจเลือกที่จะแสดงเฉพาะชุดแบบอักษรเริ่มต้นที่ฝังอยู่ในเบราว์เซอร์ ในทํานองเดียวกัน เบราว์เซอร์ไม่จําเป็นต้องแสดงข้อมูลตารางในลักษณะที่ปรากฏบนดิสก์

Local Font Access API ได้รับการออกแบบให้แสดงเฉพาะข้อมูลที่จําเป็นเพื่อเปิดใช้ Use Case ที่กล่าวถึงเท่านั้น System API อาจแสดงรายการแบบอักษรที่ติดตั้งไว้ไม่เรียงตามลำดับแบบสุ่มหรือจัดเรียง แต่เรียงตามลำดับการติดตั้งแบบอักษร การแสดงรายการแบบอักษรที่ติดตั้งไว้ตามที่กำหนดไว้โดย API ของระบบดังกล่าว จะแสดงข้อมูลเพิ่มเติมที่อาจใช้ในการพิมพ์ลายนิ้วมือ และ Use Case ที่เราต้องการเปิดใช้จะไม่ได้รับการสนับสนุนโดยการรักษาลำดับนี้ไว้ API นี้จึงต้องจัดเรียงข้อมูลที่ส่งคืนก่อนที่จะส่งคืน

ความปลอดภัยและสิทธิ์

ทีม Chrome ได้ออกแบบและติดตั้งใช้งาน Local Font Access API โดยใช้หลักการหลักที่ระบุไว้ในการควบคุมการเข้าถึงฟีเจอร์ที่มีประสิทธิภาพของแพลตฟอร์มเว็บ ซึ่งรวมถึงการควบคุมของผู้ใช้ ความโปร่งใส และลักษณะการใช้งานที่สะดวกสบาย

การควบคุมของผู้ใช้

ผู้ใช้จะควบคุมการเข้าถึงแบบเต็มรูปแบบของแบบอักษรได้ และระบบจะไม่อนุญาตให้เข้าถึง เว้นแต่จะได้รับสิทธิ์ "local-fonts" ตามที่ระบุไว้ในรีจิสทรีสิทธิ์

ความโปร่งใส

คุณสามารถดูได้ว่าเว็บไซต์ได้รับสิทธิ์เข้าถึงแบบอักษรในเครื่องของผู้ใช้หรือไม่ในชีตข้อมูลเว็บไซต์

การเก็บรักษาสิทธิ์

สิทธิ์ "local-fonts" จะยังคงอยู่เมื่อมีการโหลดหน้าเว็บซ้ำ ซึ่งจะเพิกถอนผ่านชีตข้อมูลเว็บไซต์ได้

ความคิดเห็น

ทีม Chrome ต้องการทราบประสบการณ์ของคุณเมื่อใช้ Local Font Access API

บอกเราเกี่ยวกับการออกแบบ API

มีบางอย่างเกี่ยวกับ API ที่ทำงานไม่ได้ตามที่คาดหวังหรือไม่ หรือมีเมธอดหรือพร็อพเพอร์ตี้ที่ขาดหายไปซึ่งคุณต้องนำไปใช้กับแนวคิดของคุณ หากมีคำถามหรือความคิดเห็นเกี่ยวกับรูปแบบการรักษาความปลอดภัย แจ้งปัญหาเกี่ยวกับข้อกำหนดใน GitHub repo ที่เกี่ยวข้อง หรือแสดงความคิดเห็นในปัญหาที่มีอยู่

รายงานปัญหาเกี่ยวกับการติดตั้งใช้งาน

หากพบข้อบกพร่องในการใช้งาน Chrome หรือการติดตั้งใช้งานแตกต่างจากข้อกําหนดหรือไม่ รายงานข้อบกพร่องที่ new.crbug.com โปรดระบุรายละเอียดให้มากที่สุดเท่าที่จะทำได้ ระบุวิธีการง่ายๆ ในการจำลองข้อบกพร่อง และป้อน Blink>Storage>FontAccess ในช่องคอมโพเนนต์ Glitch เหมาะอย่างยิ่งสำหรับการแชร์การจำลองข้อบกพร่องที่รวดเร็วและง่ายดาย

แสดงการสนับสนุน API

คุณวางแผนที่จะใช้ Local Font Access API ไหม การสนับสนุนแบบสาธารณะของคุณจะช่วยให้ทีม Chrome จัดลำดับความสำคัญของฟีเจอร์ต่างๆ และแสดงให้เห็นว่าการสนับสนุนฟีเจอร์เหล่านี้สำคัญกับผู้ให้บริการเบราว์เซอร์รายอื่นๆ เพียงใด

ส่งทวีตถึง @ChromiumDev โดยใช้แฮชแท็ก #LocalFontAccess และบอกเราว่าคุณกำลังใช้ฟีเจอร์นี้ที่ไหนและอย่างไร

ขอขอบคุณ

ข้อกำหนด Local Font Access API ได้รับการแก้ไขโดย Emil A. Eklund, Alex Russell, Joshua Bell และ Olivier Yiptong บทความนี้ได้รับการตรวจสอบโดย Joe Medley, Dominik Röttsches และ Olivier Yiptong รูปภาพหลักโดย Brett Jordan จาก Unsplash