使用CSS切换不同背景的字体颜色
曾經獲得其中的一個,“我可以使用CSS做到這一點!” 看著某人展示自己JavaScript肌肉的片刻? 這正是我在CSSconf EU 2018上觀看Dag-Inge Aas和Ida Aalen演講時的感受 。
他們設在挪威, WCAG的可訪問性不僅是一種良好的做法,而且實際上是法律所要求的(去,挪威!)。 在開發允許用戶選擇其主要產品的顏色主??題的功能時,他們面臨一個挑戰:根據容器的選定背景顏色自動調整字體顏色。 如果背景較暗,則最好使用白色文本以使其符合WCAG對比度 。 但是,如果選擇淺背景色會怎樣呢? 文本難以辨認并且無法訪問。
他們采用了一種優雅的方法,并使用“ color” npm軟件包解決了該問題,添加了有條件的邊框并自動生成第二色。
但這是一個JavaScript解決方案。 這是我的純CSS替代方法。
挑戰
這是我要完成的標準:
- 根據背景顏色將字體color更改為黑色或白色
- 僅當背景真的很淺時 ,才對邊框應用相同的邏輯,使用較深的背景基色變化來提高按鈕的可見性
- 自動生成60°色相旋轉的輔助顏色
使用HSL顏色和CSS變量
為此,我想到的最簡單的方法就是運行HSL顏色。 將背景聲明設置為HSL,其中每個參數都是CSS定制屬性,這允許使用一種非常簡單的方法來確定亮度并將其用作條件語句的基礎。
:root {--hue: 220;--sat: 100;--light: 81; }.btn {background: hsl(var(--hue), calc(var(--sat) * 1%), calc(var(--light) * 1%)); }這應該允許我們通過更改變量并運行if / else語句更改前景色來將背景交換為運行時所需的任何顏色。
除了……我們在CSS上沒有if / else語句…… 還是我們?
引入CSS條件語句
自從引入CSS變量以來,我們還附帶了條件語句。 或類似的。
該技巧基于以下事實: 某些CSS參數設置為最小值和最大值 。 例如,認為不透明。 有效范圍是0到1,因此我們通常將其保留在那里。 但是我們也可以聲明不透明度為2、3或1000,并且將不透明度設置為1,并以此進行解釋。 以相似的方式,我們甚至可以聲明一個負的不透明度值,并將其上限設置為0。
.something {opacity: -2; /* resolves to 0, transparent */opacity: -1; /* resolves to 0, transparent */opacity: 2; /*resolves to 1, fully opaque */opacity: 100; /* resolves to 1, fully opaque */ }將技巧應用于我們的字體顏色聲明
HSL顏色聲明的明度參數的行為類似,將任何負值的上限設置為0(無論色相和飽和度是什么,都會導致黑色),而任何高于100%的值都上限為100%(始終為白色) )。
因此,我們可以將顏色聲明為HSL,從亮度參數中減去所需的閾值,然后乘以100%以強制其超出限制之一(小于零或高于100%)。 由于我們需要將負結果轉換為白色,將正結果轉換為黑色,因此我們還必須將其乘以-1并將其取反。
:root {--light: 80;/* the threshold at which colors are considered "light." Range: integers from 0 to 100, recommended 50 - 70 */--threshold: 60; }.btn {/* Any lightness value below the threshold will result in white, any above will result in black */--switch: calc((var(--light) - var(--threshold)) * -100%);color: hsl(0, 0%, var(--switch)); }讓我們回顧一下這段代碼:從80的亮度開始,并考慮60的閾值,相減得出20,再乘以-100%,得出-2000%上限為0%。 我們的背景比閾值淺,因此我們認為它較淺并應用黑色文本。
如果我們將--light變量設置為20,則減法將導致-40,乘以-100%將變為4000%,上限為100%。 我們的淺色變量低于閾值,因此我們將其視為“深色”背景,并應用白色文本以保持較高的對比度。
產生條件邊界
如果元素的背景太亮,則很容易在白色背景下丟失。 我們可能有一個按鈕,甚至沒有注意到它。 為了在真正的淺色上提供更好的UI,我們可以基于完全相同的背景色(只是更深)設置邊框。
具有基于該背景色的深色邊框的淺色背景。為此,我們可以使用相同的技術,但將其應用于HSLA聲明的alpha通道。 這樣,我們可以根據需要調整顏色,然后使顏色完全透明或完全不透明。
:root {/* (...) */--light: 85;--border-threshold: 80; }.btn {/* sets the border-color as a 30% darker shade of the same color*/--border-light: calc(var(--light) * 0.7%);--border-alpha: calc((var(--light) - var(--border-threshold)) * 10);border: .1em solid hsla(var(--hue), calc(var(--sat) * 1%), var(--border-light), var(--border-alpha)); }假設色相為0且飽和度為100%,則上面的代碼將在背景亮度高于80時以原始亮度的70%提供完全不透明的純紅色邊框,或者提供完全透明的邊框(因此,在全部)如果天黑了。
設置第二種60°色相旋轉的顏色
可能是最簡單的挑戰。 有兩種可能的方法:
考慮到這一點,我們可以為第二色元素添加一個修飾符類,該修飾符類將色相值增加60。 由于自修改變量在CSS中不可用(即,沒有--hue: calc(var(--hue) + 60)這樣的東西),我們可以為我們的基本樣式和在背景和邊框聲明中使用它。
.btn {/* (...) */--h: var(--hue);background: hsl(var(--h), calc(var(--sat) * 1%), calc(var(--light) * 1%));border:.1em solid hsla(var(--h), calc(var(--sat) * 1%), var(--border-light), var(--border-alpha)); }然后在修飾符中重新聲明其值:
.btn--secondary {--h: calc(var(--hue) + 60); }這種方法的最好之處在于,由于CSS自定義屬性的作用域,它會自動將所有計算結果調整為新的色調并將其應用于屬性。
我們到了。 綜上所述, 這是我針對所有三個挑戰的純CSS解決方案 。 這應該像一種魅力,并且可以避免我們包含外部JavaScript庫。
請參見Pen CSS自動切換字體顏色,具體取決于元素背景…。 FAIL由法昆多考拉蒂尼( @facundocorradini )上CodePen 。
除非不是。 有些色調得到真正的問題(特別是黃色和青色),因為它們顯示方式亮度比其他人(如紅色和藍色),盡管具有相同的亮度值。 結果,盡管有些顏色非常亮,但仍將某些顏色視為深色并給出白色文本。
CSS的名字到底是怎么回事?
引入感知的亮度
我敢肯定,你們中的很多人可能已經注意到了這一點,但是對于我們其他人來說,我們發現的亮度與HSL的亮度并不相同 。 幸運的是,我們有一些方法可以權衡色調的亮度并調整我們的代碼,使其對色調也能做出響應。
要做到這一點,我們需要通過給三種系數分別對應于人眼感知其亮度的系數來考慮三種原色的感知亮度。 這通常稱為亮度 。
有幾種方法可以實現此目的。 在某些情況下,有些比其他更好,但沒有哪一種是100%完美的。 因此,我選擇了兩個最受歡迎的,它們足夠好 :
- sRGB亮度(ITU Rec。709) : L =(紅色* 0.2126 +綠色* 0.7152 +藍色* 0.0722)/ 255
- W3C方法(工作草案) : L =(紅色* 0.299 +綠色* 0.587 +藍色* 0.114)/ 255
實施亮度校正的計算
采用亮度校正方法的第一個明顯含義是,由于CSS沒有本機方法來訪問HSL聲明的RGB值,因此我們不能使用HSL。
因此,我們需要切換到背景的RBG聲明,從我們選擇的任何方法中計算亮度,并將其用于我們的前景顏色聲明中,該顏色可以(并且將仍然是HSL)。
:root {/* theme color variables to use in RGB declarations */--red: 200;--green: 60;--blue: 255;/* the threshold at which colors are considered "light". Range: decimals from 0 to 1, recommended 0.5 - 0.6 */--threshold: 0.5;/* the threshold at which a darker border will be applied.Range: decimals from 0 to 1, recommended 0.8+ */--border-threshold: 0.8; }.btn {/* sets the background for the base class */background: rgb(var(--red), var(--green), var(--blue));/* calculates perceived lightness using the sRGB Luma method Luma = (red * 0.2126 + green * 0.7152 + blue * 0.0722) / 255 */--r: calc(var(--red) * 0.2126);--g: calc(var(--green) * 0.7152);--b: calc(var(--blue) * 0.0722);--sum: calc(var(--r) + var(--g) + var(--b));--perceived-lightness: calc(var(--sum) / 255);/* shows either white or black color depending on perceived darkness */color: hsl(0, 0%, calc((var(--perceived-lightness) - var(--threshold)) * -10000000%)); }對于條件邊框,我們需要將聲明轉換為RGBA,然后再次使用alpha通道使其完全透明或完全不透明。 與以前幾乎相同,只是運行RGBA而不是HSLA。 通過從每個通道中減去50獲得較暗的陰影。
如果在速記邊框聲明的RGBA參數中使用變量,iOS上的WebKit上確實存在一個很奇怪的錯誤,它將顯示黑色邊框而不是適當的顏色。 解決方案是長期宣布邊界。
感謝Joel指出錯誤!
由于我們丟失了最初的HSL背景聲明,因此需要通過色相旋轉來獲得我們的次要主題顏色:
.btn--secondary {filter: hue-rotate(60deg); }這不是世界上最好的事情。 除了將色相旋轉應用于如前所述的潛在子元素外,這還意味著切換到黑/白和次要元素上的邊框可見性將取決于主要元素的色相,而不是其自身。 但據我所知,JavaScript實現存在相同的問題,因此我將其稱為足夠接近 。
到此為止,我們已經擁有了。
見筆取決于元件背景CSS自動WCAG對比度字體顏色由法昆科拉迪尼( @facundocorradini )上CodePen 。
一個純CSS解決方案,可以達到與原始JavaScript方法相同的效果,但是可以大大減少占用空間。
瀏覽器支持
IE由于使用CSS變量而被排除在外。 Edge沒有我們一直使用的上限行為。 它會看到該聲明,將其視作廢話,并將其完全丟棄,就像它會破壞或未知的規則一樣。 其他所有主要瀏覽器均應正常工作。
翻譯自: https://css-tricks.com/switch-font-color-for-different-backgrounds-with-css/
總結
以上是生活随笔為你收集整理的使用CSS切换不同背景的字体颜色的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机毕业设计ssm特种设备全生命周期管
- 下一篇: Linux文件打包及下载命令-tar(打