如何為 Web 開發文本編輯器
已發表: 2022-03-10我在 Readymag 工作,它開發了一個基於瀏覽器的設計工具,可以幫助人們創建網站、作品集和各種在線出版物,而無需編碼。 我們的工具中有許多小部件可用,文本小部件是使用最廣泛的小部件之一。
文本小部件是一個文本輸入字段,用戶可以在其中使用編輯器中的一系列控件設置文本樣式。 每個控件都將 CSS 屬性應用於文本。 從用戶的角度來看,它看起來就像一個普通的輸入文本的字段,但在其看似簡單的背後隱藏著大量複雜的過程。
在本文中,我將解釋我的公司面臨的挑戰以及我們用於在應用程序中創建文本小部件的解決方案。 我還將深入探討我們如何實現它以及我們在此過程中學到了什麼——以及在網絡上打字的一般工作原理。
在 Web 上編輯文本
有幾種方法可以在 Web 上實現文本輸入字段。 我們可以使用簡單的文本字段、多行textarea
元素或contenteditable
屬性來使輸入可編輯,或者document.designMode = on
。 它們有何不同?
input
和textarea
元素非常適合向頁面添加文本,但它們不提供豐富的文本格式體驗。 為此,我們可以使用contenteditable
屬性使幾乎所有元素都可編輯並啟用文本樣式。
如果您需要一次編輯整個頁面,可以使用document.designMode
。 此模式允許編輯給定文檔中的任何元素,甚至是iframe
。
我們選擇了contenteditable
屬性,它包含所有必要的文本編輯功能。 使用此屬性,頁面上的任何文本都可以編輯,如果我們想讓人們使用 CSS 設置文本樣式,這一點非常重要。 例如,用戶可以直接設置選定部分或整個文本的樣式。
文本樣式和字體屬性
通過提供對 CSS 開箱即用的所有選項的訪問,我們使用戶能夠以他們希望的任何方式設置文本樣式。 除了眾所周知的屬性(例如字體、樣式、顏色和裝飾)之外,我們還為用戶提供了使用 OpenType 字體功能的機會,例如連字、樣式集、分數等。 這些功能通過font-feature-settings
CSS 屬性起作用,它允許用戶自定義文本樣式。
注意:我強烈推薦閱讀 Sparanoid 的優秀文章,其中展示了 OpenType 的所有功能。
現代排版向前邁出了一大步,允許通過font-variation-settings
屬性在 Web 上使用可變字體。
每個可變字體都有可變屬性,您可以更改其值。 例如,在標準字體中,您可以使用嚴格指定的值( 400
等)更改字體600
,而500
可變字體中,您可以使用可用範圍內的任何值,從而提供更廣泛的可能性用於文本樣式。
.style-1 { font-weight: 600; } .style-2 { font-variation-settings: "wght" 777; }
您可以在下面看到一個示例,說明如何在文本小部件中使用可變字體。
除了註冊值( wght
、 wdth
、 slnt
等),字體製作者還可以創建自己獨特的字體特徵(如上例所示)。 為了讓我們的用戶有機會使用所有可能的字體功能,我們首先需要此信息。
您要使用的所有功能都應在字體文件中定義。 讓我們看看它的規格。 每種字體都可以以表格的形式表示,提供渲染其字符時使用的所有不同信息。
我們使用兩個表來收集有關字體的信息:
- 字形替換錶
字形替換錶 (GSUB) 包含一個字形渲染數據列表。GSUB.featureList
對像是字體特徵及其屬性的枚舉。 您可以在 GitHub 上的表格中查看數據示例。 在這個表中,tag
字段是最有趣的。 這是字體功能的名稱,表示此字體可使用此功能。 我們可以安全地在font-feature-settings
屬性中使用tag
。 - 字體變化表
字體變體表 (fvar) 是與字體關聯的變量屬性的表示。 GitHub 上也提供了該表的示例。 每個對像都是一個字體屬性,帶有對可能值(min
、max
、 default )和本地化名稱(如果有)的描述。 我們將這些值與font-variation-settings
屬性一起使用。
借助這兩個表,我們可以滿足所有需求:使用可變字體屬性和各種字體特徵。 結果數據顯示在編輯器的文本小部件控件中,用戶可以在其中設置文本樣式而無需使用任何代碼。
使用鍵盤
文本輸入是文本小部件用戶體驗的最重要方面之一。 除了啟用處理文本的快捷方式外,我們還必須應對一些不尋常的挑戰。 使用箭頭鍵導航文本絕對是其中之一。
在用戶進行編輯時,文本小部件還會顯示隱藏字符,例如不間斷空格和換行符。 它們被實現為插入文本中的 SVG 圖標,這帶來了一個問題:如果我們使用contenteditable
,那麼這些圖標會阻止用戶使用箭頭鍵移動光標。
解決方案很簡單:使用span
和:before
偽元素。 這樣,瀏覽器會將圖標視為文本,並且箭頭鍵效果很好。
span:before { content: ""; height: 1em; position: relative; background-repeat: no-repeat; background-image: url("data:image/svg+xml,..."); background-position: center bottom; background-size: 1em; }
捷徑
在文本小部件中粘貼文本有兩個鍵盤快捷鍵。
Cmd / Ctrl + V從剪貼板粘貼文本並保留原始文檔中的所有樣式。 如果文本是從 Pages、Notes、Word 或 Google Docs 等應用程序複製的,那麼您的剪貼板將包含 HTML 信息,而不僅僅是純文本。 可以在保留原始樣式的同時解析和粘貼此 HTML。
您可以按如下方式獲取 HTML 數據:
// https://www.w3.org/TR/clipboard-apis/#reading-from-clipboard document.addEventListener('paste', (e) => { const text = e.clipboardData.getData('text/plain'); const html = e.clipboardData.getData('text/html'); handlePaste(); });
此外,我們還有Cmd + Shift + V快捷鍵。 當您使用此鍵盤組合插入文本時,瀏覽器會將純數據留在有效負載中,因此樣式由粘貼目標控制。 這些快捷方式默認存在於瀏覽器中,但您需要記住在您的項目中實現它們。
文本選擇和焦點
文本選擇可幫助用戶查看當前正在編輯的文本。 讓我們嘗試一個簡單的例子:一個帶有按鈕的輸入字段來控製文本的粗細。
在這個例子中,我們可以選擇一段文本,然後按下Bold
按鈕,之後文本中的選擇將保持不變。 但是如果我們的例子更複雜怎麼辦? 假設我們向文本大小選擇器添加了一個輸入字段。 在這種情況下,焦點將轉移到新的輸入。
解決此問題有兩種選擇:
- 在每個輸入事件之後,我們強制焦點移回文本塊。 在這種情況下,選擇會在一定數量的輸入事件後開始閃爍——我們不希望這樣。
- 我們可以將文本塊添加到
iframe
。 您可能知道,iframe
有自己的全局window
對象。 因此,只要選擇在iframe
內,即使外部焦點移動,它也會持續存在。
我們最終得到了一個iframe
包裝的文本小部件。 因此,只要選擇在iframe
內,即使外部焦點移動,它也會持續存在。 看看下面的截圖。 我們在頁面上有兩個選擇:文本小部件中的選定片段和控件中文本大小的選定值。
文本輸入期間的性能
文本編輯界面的響應能力很重要。 密切監控每秒幀數 (FPS) 值,尤其是在涉及高速編輯文本或更改字體大小等任務時。
Readymag 有兩個視口:桌面和移動。 文本樣式可以在每個中顯示不同。 在輸入文本時,編輯器將執行各種計算以在視口之間同步數據。 通過使用瀏覽器 API 實現高響應性: requestAnimationFrame
和requestIdleCallback
:
- 每次刷新屏幕時都會調用
requestAnimationFrame
; -
requestIdleCallback
僅在瀏覽器空閒時調用。
這是在不阻塞主線程的情況下執行繁瑣操作的好方法。
可訪問性
啟用可訪問性是當今 Web 開發中最重要的實踐之一。 如果您的網站在設計時考慮到了可訪問性,它將讓更多人訪問您的產品。 這意味著不僅要適應殘疾人,還要適應不同平台上的用戶:桌面和触摸設備、屏幕閱讀器、聽力設備等。 要了解使項目易於訪問的重要性,我建議查看最近的可訪問性統計數據。
要開始整合 Web 可訪問性實踐,請首先查看 Web 內容可訪問性指南 (WCAG),這是關於該主題的最全面的資源。 而只要 Readymag 是一個發布工具,除了 WCAG,我們還需要遵循 Authoring Tool Accessibility Guidelines (ATAG)。
我們的團隊目前正處於將可訪問性集成到編輯器中的階段。 在隨後的文章中,我們將分享更多關於我們在 Readymag 完全集成可訪問性的過程。 您還可以使用我們的可訪問性清單檢查使用 Readymag 所做的任何工作。
最佳實踐
最後,這裡有一些技巧可以幫助您在 Web 上開發文本編輯器:
- 仔細考慮佈局。
提前確定您需要哪些功能以及如何使用文本編輯器中的元素。 - 設置視覺測試。
處理文本時,不能完全依賴快照測試結果。 您可能會在測試中得到正確的結果,期待給定的塊 CSS,但有時結果可能不是您所期望的。 - 在不同的瀏覽器中測試您的工作。
雖然大多數瀏覽器都很好地支持新的在線功能,但在不同的瀏覽器中顯示相同的樣式通常會出現問題。 - 使用功能標誌更安全地開發新功能。
- 輸入文本時在瀏覽器中測量 FPS。
不要在單個線程中執行 CPU 密集型任務。 - 不要害怕嘗試。
- 最後但同樣重要的是,試試 Readymag 中的 Text Widget 。
一些有用的鏈接
- “OpenType 功能的完整 CSS 演示”,Sparanoid
- “Web 上的可變字體簡介”,web.dev
- “令人敬畏的排版,”喬爾·加勒蘭
- “可變字體”,尼克·謝爾曼
- 字體包
- OpenType.js