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

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

เผยแพร่: 24 สิงหาคม 2020

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

หากคุณเป็นนักพัฒนาเว็บมานานพอ คุณอาจจำสิ่งที่เรียกว่าแบบอักษรที่ใช้บนเว็บได้อย่างปลอดภัยได้ แบบอักษรเหล่านี้เป็นแบบอักษรที่ใช้ได้ในอินสแตนซ์ของระบบปฏิบัติการที่ใช้กันมากที่สุดเกือบทั้งหมด (ได้แก่ 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 แสดงตัวอย่างแบบอักษร Google Sans
แบบอักษร Google Sans ที่ติดตั้งในแล็ปท็อปของพนักงาน Google

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

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

Local Font Access API

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

ทำไมเราจึงต้องใช้ Local Font Access API ในเมื่อมีแบบอักษรบนเว็บอยู่แล้ว

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

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

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

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

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

Browser Support

  • Chrome: 103.
  • Edge: 103.
  • Firefox: not supported.
  • Safari: not supported.

Source

วิธีใช้ 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, TrueType, 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 ได้รับการออกแบบมาให้แสดงเฉพาะข้อมูลที่จำเป็นต่อการเปิดใช้กรณีการใช้งานที่กล่าวถึงเท่านั้น API ของระบบอาจสร้างรายการแบบอักษรที่ติดตั้งซึ่งไม่ได้อยู่ในลำดับแบบสุ่มหรือลำดับที่จัดเรียง แต่จะอยู่ในลำดับการติดตั้งแบบอักษร การแสดงรายการแบบอักษรที่ติดตั้งตามที่ API ของระบบดังกล่าวระบุอย่างตรงไปตรงมาอาจเปิดเผยข้อมูลเพิ่มเติมที่อาจใช้สำหรับการลายนิ้วมือ และกรณีการใช้งานที่เราต้องการเปิดใช้จะไม่ได้รับความช่วยเหลือจากการรักษาลำดับนี้ ด้วยเหตุนี้ API นี้จึงกำหนดให้ต้องจัดเรียงข้อมูลที่ส่งคืนก่อนที่จะส่งคืน

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

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

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

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

ความโปร่งใส

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

การคงอยู่ของสิทธิ์

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

ความคิดเห็น

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

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

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

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

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

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

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

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

คำขอบคุณ

Emil A. ได้แก้ไขข้อกำหนด API สำหรับการเข้าถึงแบบอักษรในเครื่อง Eklund, Alex Russell, Joshua Bell และ Olivier Yiptong บทความนี้ได้รับการตรวจสอบโดย Joe Medley Dominik Röttsches และ Olivier Yiptong