整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          CSS色域、色彩空間、CSS Color 4新標準

          近期,三大主流瀏覽器引擎均發布最新版本,支持W3C的CSS Color 4標準,包含新的取色方法color()和相應語法,可展示更多的色域及色彩空間,這意味著web端能展示更豐富更高清的色彩。雖然目前只有最新版本的現代瀏覽器才支持,我們可以先提前了解一下這項新標準。

          本文首先會先簡單介紹幾個色彩的基礎概念,了解為何需要新標準,之后會介紹新標準中的方法和語法使用。

          基礎概念

          色域(color gamut)

          指顏色的可選范圍。如sRGB色域,目前web廣泛應用的色域標準,使用紅(red)綠(green)藍(blue)作為基礎色,色值范圍0~255,三種基礎色互相混合起來可展示255*255*255種顏色,這大致可理解為sRGB的色域。

          現代web css使用的sRGB色域僅滿足基礎性的色彩需求,能展示的色彩范圍遠小于人類肉眼所能感知的顏色范圍,也遠低于高清展示的要求。

          以下是sRGB與其他幾種色域標準的色值范圍大小比較:

          ??以下是sRGB與人類肉眼可感知的色域比較:

          ?色彩空間(color space)

          色彩空間可以理解為一個基于某一色域標準下構建的空間數學模型,例如一些簡單的方塊、圓柱的3D模型,可以用來標記出色域中每個顏色的空間位置,各個顏色之間的關系等。

          再用sRGB舉例,紅(red)綠(green)藍(blue)三種基礎色可設置為3個直線坐標軸,每種顏色便可標記為這個立方體中的一個點,在css中便是使用rgb()方法來取色,參數為指定顏色在色彩空間中的坐標(R, G, B)。

          再再比如css的另一個取色方法hsl(),使用的是一套完全不同的色彩空間HSL,H色相(hue)是取值范圍為0~360的角度,可作為角軸;S飽和度(Saturation)和L亮度(Lightness)作為兩個直線軸,可構建為一個圓柱形的空間,css中使用hsl(H, S, L)表示顏色。

          ??一種色域標準可以使用不同的色彩空間來描述,不同的色域標準也可以使用的是同一類的色彩空間表示。例如sRGB可以使用rgb()、hsl()、hwb()等方式進行描述,而像Display-P3、Rec2020色域都可以使用(R,G,B)的色彩空間來描述,只是空間的邊界范圍有所不同。

          為什么要支持高清色彩

          高清意味著更高范圍的色域,讓我們先直觀感覺一下窄色域與廣色域的視覺差距:

          ??在實際的css顏色取值中,我們常用的方法有很多rgb()、rgba()、hsl()、hwb(),對應不同的色彩空間,但取的都是同一色域范圍內的顏色,即sRGB,大概只能展示人類肉眼可感知的色彩中的30%,仿佛在使用一臺90年代的電視機播放4K電影。

          雖然目前的網絡顯示設備很多還是sRGB標準,并不支持顯示更廣色域標準的色彩,僅部分HDR顯示器、或視頻錄制設備、電影制造中使用了如Display P3這類更廣的色域標準。但對于高清的需求只會越來越多,支持更廣色域標準注定也是未來web端顯示的目標之一。

          為應對這一趨勢,W3C的CSS Color 4標準定義了新方法color()和其他語法能更靈活的指定各種不同色域標準下的顏色,以及更好的色彩漸變展示。最近,主流三大web瀏覽器也都已支持了W3C的新標準。

          CSS Color 4

          回顧現有的色彩空間

          2000年以來,我們有多種方式指定色值:hex色值(#rgb、#rrggbb)、rgb()、rgba()、或是一些特定顏色的字符(如white、pink等);2010年左右開始,瀏覽器開始支持hsl()方法;2017年,hex色值擴展了對于透明度的支持,#rrggbbaa;之后各種瀏覽器又陸續增加對hwb()方法的支持。

          不同的方法對應的是不同的色彩空間,但色域都是同一個,即sRGB。

          HEX

          ?使用十六進制的數字來分別表示R、G、B、A的值

          .valid-css-hex-colors {
            /* 一般標準 */
            --3-digits: #49b;
            --6-digits: #4499bb;
          
            /* 帶透明度 */
            --4-digits-opaque: #f9bf; /* 不透明 */
            --8-digits-opaque: #ff99bbff; /* 不透明 */
            --4-digits-with-opacity: #49b8; /* 透明度88% */
            --8-digits-with-opacity: #4499bb88; /* 透明度88% */
          }
          
          

          RGB

          ??使用0~255的十進制數字,或是0%~100%的百分比來指明R、G、B,透明度A使用百分比或0~1的數字表示

          .valid-css-rgb-colors{
            --classic:rgb(64, 149, 191);
            --modern:rgb(64 149 191);
            --percents:rgb(25% 58% 75%);
          
            --classic-with-opacity-percent:rgba(64, 149, 191, 50%);
            --classic-with-opacity-decimal:rgba(64, 149, 191, .5);
          
            --modern-with-opacity-percent:rgb(64 149 191 / 50%);
            --modern-with-opacity-decimal:rgb(64 149 191 / .5);
          
            --percents-with-opacity-percent:rgb(25% 58% 75% / 50%);
            --percents-with-opacity-decimal:rgb(25% 58% 75% / 50%);
          
            --empty-channels:rgb(none none none);
          }
          
          

          HSL

          ??這種色彩空間更符合人類自然理解,無需了解紅綠藍基礎色是如何混合的。參數分別表示:

          ?H:hue,色相,取值0deg~360deg

          ?S:Saturation,飽和度,取值0%~100%

          ?L:Lightness,亮度,取值0%~100%

          .valid-css-hsl-colors{
            --classic:hsl(200deg, 50%, 50%);
            --modern:hsl(200 50% 50%);
          
            --classic-with-opacity-percent:hsla(200deg, 50%, 50%, 50%);
            --classic-with-opacity-decimal:hsla(200deg, 50%, 50%, .5);
          
            --modern-with-opacity-percent:hsl(200 50% 50% / 50%);
            --modern-with-opacity-decimal:hsl(200 50% 50% / .5);
          
            /* 無色相和飽和度,僅用亮度可表示黑白色 */
            --empty-channels-white:hsl(none none 100%);
            --empty-channels-black:hsl(none none 0%);
          }
          
          

          HWB

          ??形式上和HSL類似,但使用的3個維度為:

          ?H:Hue,色相,取值0deg~360deg;

          ?W:Whiteness,白色的濃度(0~100%);

          ?B:Blackness,黑色的濃度(0~100%);

          .valid-css-hwb-colors{
            --modern:hwb(200deg 25% 25%);
            --modern2:hwb(200 25% 25%);
          
            --modern-with-opacity-percent:hwb(200 25% 25% / 50%);
            --modern-with-opacity-decimal:hwb(200 25% 25% / .5);
          
            /* 無色相和飽和度,僅用亮度可表示黑白色 */
            --empty-channels-white:hwb(none 100% none);
            --empty-channels-black:hwb(none none 100%);
          }
          
          

          ?新方法color()

          ??新的color()方法的參數類似于rgb()方法,使用R、G、B三個直線軸上的數值來指明色彩,不同的是color()方法的第一個參數可以接收除sRGB以外的其他色域下的色彩空間標識符,且R、G、B的值僅支持0~1或0%~100%。

          .valid-css-color-function-colors {
            --srgb: color(srgb 1 1 1);
            --srgb-linear: color(srgb-linear 100% 100% 100% / 50%);
            --display-p3: color(display-p3 1 1 1);
            --rec2020: color(rec2020 0 0 0);
            --a98-rgb: color(a98-rgb 1 1 1 / 25%);
            --prophoto: color(prophoto-rgb 0% 0% 0%);
            --xyz: color(xyz 1 1 1);
          }
          
          

          方法定義:color(colorspace c1 c2 c3[ / A])

          ? 參數colorspace:標識符,指明使用哪種色彩空間,可選值包括:srgb,srgb-linear,display-p3,a98-rgb,prophoto-rgb,rec2020,xyz,xyz-d50, andxyz-d65.

          ?參數c1、c2、c3:可以是number(0~1)、百分比或none,對應指定色彩空間下的各參數值,比如srgb,srgb-linear,display-p3對應的是R、G、B的值,具體需要看指定色彩空間描述顏色的維度。

          ?參數A:可選項,可以是number(0~1)、百分比或none,指明顏色的透明度

          使用color()描述不同的色彩空間

          sRGB

          不再支持0~255取值,改為0~1范圍,其實和百分比的形式是等價的。如果傳了大于1的數值也默認當作1來解析。

          .valid-css-srgb-colors{
            --percents:color(srgb 34% 58% 73%);
            --decimals:color(srgb .34 .58 .73);
          
            --percents-with-opacity:color(srgb 34% 58% 73% / 50%);
            --decimals-with-opacity:color(srgb .34 .58 .73 / .5);
          
            /* 色值為none或空時,表示黑色 */
            --empty-channels-black:color(srgb none none none);
            --empty-channels-black2:color(srgb);
          }
          
          

          Linear sRGB

          Linear sRGB和sRGB是不同的色彩空間,sRGB的取值是通過一個伽馬曲線函數做過校正的,并不是線性變化的,更適應人眼的感知特性,即對明暗的感知是非線性的;而Linear sRGB的顏色變化是線性的,以下是明暗從0-1漸變時,兩種色彩空間實際的漸變走向。


          .valid-css-srgb-linear-colors{
            --percents:color(srgb-linear 34% 58% 73%);
            --decimals:color(srgb-linear .34 .58 .73);
          
            --percents-with-opacity:color(srgb-linear 34% 58% 73% / 50%);
            --decimals-with-opacity:color(srgb-linear .34 .58 .73 / .5);
          
            /* 色值為none或空時,表示黑色 */
            --empty-channels-black:color(srgb-linear none none none);
            --empty-channels-black2:color(srgb-linear);
          }
          
          

          ?Display P3、Rec2020

          display P3是最早由蘋果公司推行的。如今這一標準已成為HDR顯示的基礎標準,能顯示的顏色比sRGB多50%。而Rec2020標準比display P3的色域更廣,可以用來顯示4K甚至8K的影像,但目前支持這一標準的終端顯示器還很少。兩種色域都是使用RGB來描述的。

          .valid-css-display-p3-colors{
            --percents:color(display-p3 34% 58% 73%);
            --decimals:color(display-p3 .34 .58 .73);
          
            --percent-opacity:color(display-p3 34% 58% 73% / 50%);
            --decimal-opacity:color(display-p3 .34 .58 .73 / .5);
          
            /* 無色度色相,展示為黑色 */
            --empty-channels-black:color(display-p3 none none none);
            --empty-channels-black2:color(display-p3);
          }
          
          .valid-css-rec2020-colors {
            --percents: color(rec2020 34% 58% 73%);
            --decimals: color(rec2020 .34 .58 .73);
          
            --percent-opacity: color(rec2020 34% 58% 73% / 50%);
            --decimal-opacity: color(rec2020 .34 .58 .73 / .5);
          
            /* 無色度色相,展示為黑色 */
            --empty-channels-black: color(rec2020 none none none);
            --empty-channels-black2: color(rec2020);
          }
          
          
          


          CIE標準

          讓我們先回到開頭的兩張色域圖,會發現基于RGB描述的色域基本是一個三角形,因為都是使用3個基礎色混合而成,但人眼所能感知的色域是形似馬蹄的圖形(具體如何繪制出的,感興趣的可自行搜索了解)。基于RGB標準的色彩空間,都很難完全覆蓋人眼能感知的所有顏色。而基于CIE標準(國際照明委員會制定的一種測定顏色的國際標準,它描述了人眼對顏色的感知和色彩的測量方法)的色彩空間,理論上是能夠包括人視覺所能感知到的所有顏色。

          CSS Color 4新標準也新增了對于CIE標準色域的支持。下面介紹的lab()、lch()、oklab()、oklch()都是基于CIE的取色新方法。


          lab()

          ?lab()方法描述的是基于CIE標準的色彩空間中的顏色,能夠覆蓋人眼所能看到的全色域。和與基于RGB來描述色彩的維度不同,lab使用的維度分別為:

          ?L:lightness,視覺上線性漸變的亮度,取值范圍0~100或0%~100%;

          ?A:代表更貼合人眼視覺特性的兩個色軸之其一:紅-綠,取值范圍均為 -125~125 或 -100%~100%。當A為正值,則為更偏紅色;為負值時,更偏綠;

          ?B:代表更貼合人眼視覺特性的兩個色軸之其二:藍-黃,取值范圍均為 -125~125 或 -100%~100%。值為正值,更偏黃;為負值,更偏藍。

          .valid-css-lab-colors{
            --percent-and-degrees:lab(58% -16 -30);
            --minimal:lab(58 -16 -30);
          
            --percent-opacity:lab(58% -16 -30 / 50%);
            --decimal-opacity:lab(58% -16 -30 / .5);
          
            /* 后兩個參數為none是可表示純灰度 */
            --empty-channels-white:lab(100 none none);
            --empty-channels-black:lab(none none none);
          }
          
          

          lch()

          lch使用的維度分別是:

          ?L:lightness,視覺上線性漸變的亮度,取值范圍0~100或0%~100%;

          ?C:chroma,顏色的純度,類似于飽和度,取值范圍0~230,但實際上,這個值是沒有上限的;

          ?H:hue,色相,類似hsl和hwb,是個角軸,取值范圍0deg~360deg;

          .valid-css-lch-colors{
            --percent-and-degrees:lch(58% 32 241deg);
            --just-the-degrees:lch(58 32 241deg);
            --minimal:lch(58 32 241);
          
            --percent-opacity:lch(58% 32 241 / 50%);
            --decimal-opacity:lch(58% 32 241 / .5);
          
            /* 后兩個參數為none是可表示純灰度 */
            --empty-channels-white:lch(100 none none);
            --empty-channels-black:lch(none none none);
          }
          
          

          oklab()

          ?oklab是校正版的lab,優化了圖片處理質量,在CSS中意味著漸變優化和顏色處理函數優化,消除了色相偏移(hue shift,即在lab中改變顏色純度,色相也會變化),使用的維度和lab()是一致的。

          .valid-css-oklab-colors{
            --percent-and-degrees:oklab(64% -.1 -.1);
            --minimal:oklab(64 -.1 -.1);
          
            --percent-opacity:oklab(64% -.1 -.1 / 50%);
            --decimal-opacity:oklab(64% -.1 -.1 / .5);
          
            /* 后兩個參數為none是可表示純灰度 */
            --empty-channels-white:oklab(100 none none);
            --empty-channels-black:oklab(none none none);
          }
          
          

          oklch()

          ??相應的,oklch是lch的校正版,取色的邏輯和hsl類似,在圓色盤中選擇一個角度從而選中一個色相,再通過調節亮度和純度,也就是hsl中的飽和度,純度和飽和度基本可認為是等價的,區分僅在于純度和亮度的調節通常是同步進行的,否則純度很容易超出目標色域的范圍。這里有一個oklch的拾色器,可以體驗下。

          .valid-css-oklch-colors{
            --percent-and-degrees:oklch(64% .1 233deg);
            --just-the-degrees:oklch(64 .1 233deg);
            --minimal:oklch(64 .1 233);
          
            --percent-opacity:oklch(64% .1 233 / 50%);
            --decimal-opacity:oklch(64% .1 233 / .5);
          
            /* 后兩個參數為none是可表示純灰度 */
            --empty-channels-white:oklch(100 none none);
            --empty-channels-black:oklch(none none none);
          }
          
          

          color-mix()

          ?除了新增的一些取色方法外,新標準還有一個混色函數,可以將上邊提到的各種不同色彩空間的中顏色進行混合計算出新顏色。

          color-mix(in lch, plum, pink);
          color-mix(in lch, plum 40%, pink);
          color-mix(in srgb, #34c9eb 20%, white);
          color-mix(in hsl longer hue,hsl(120 100% 50%) 20%, white);
          
          

          方法定義:color-mix(method, color1[ p1], color2[ p2])

          ?參數method:指定混色的色彩空間,以 in <color space> 的形式,<color space>包含:srgb,srgb-linear,lab,oklab,xyz,xyz-d50, xyz-d65,hsl,hwb,lch, oroklch

          ?參數color1、color2:為對應method中指定色彩空間中的任一顏色;

          ?參數p1、p2:為可選參數,取值范圍為0%~100%,可以指明混色的比例,如果為空,默認color1和color2各為50%;

          項目中如何使用高清色彩

          在我們應用一項新語法時,我們通常會有兩種策略:優雅降級和漸進增強,具體實施方案:

          優雅降級

          這種實施起來比較簡單,即同時使用新舊取色方法,讓瀏覽器自動判斷展示哪種

          /* 原代碼 */
          color: red;
          color:color(display-p3 1 0 0);
          
          /* 如果瀏覽器不支持display-p3,則會只解析第一行 */
          color: red;
          
          /* 如果瀏覽器支持,則會最終使用第二行 */
          color:color(display-p3 1 0 0);
          
          

          漸進增強

          使用@supports和@media先判斷當前瀏覽器是否支持新的色域標準,并在條件的情況下提供新的色值。

          色域媒體查詢

          ?dynamic-range:取值standard或high,用于判斷當前硬件設備是否支持高清、高對比度、高色彩精度,不過這一屬性判斷的比較籠統,并不能準確判斷瀏覽器是否支持新色域和色彩空間。

          @media(dynamic-range: high){
            /* safe to use HD colors */
            color: color(display-p3 34% 58% 73%);
          }
          
          

          ?color-gamut:取值 srgb、p3 或 rec2020,對應可判斷用戶設備是否支持sRGB、Display P3 或 REC2020色域。

          @media(color-gamut: srgb){
            /* safe to use srgb colors */
            color: #4499bb;
          }
          
          @media(color-gamut: p3){
            /* safe to use p3 colors */
            color: color(display-p3 34% 58% 73%);
          }
          
          @media(color-gamut: rec2020){
            /* safe to use rec2020 colors */
            color: color(rec2020 34% 58% 73%);
          }
          
          

          除了可以直接使用css媒體查詢,還可用途JavaScript中的window.matchMedia()方法來進行媒體查詢。


          const hasHighDynamicRange = window.matchMedia('(dynamic-range: high)').matches;
          
          console.log(hasHighDynamicRange);// true || false
          
          const hasP3Color = window.matchMedia('(color-gamut: p3)').matches;
          
          console.log(hasP3Color);// true || false
          
          


          色彩空間查詢

          ?使用@supports判斷某個css方法或屬性是否支持


          @supports(background:rgb(0 0 0)){
            /* rgb color space supported */
            background:rgb(0 0 0);
          }
          
          
          @supports(background:color(display-p3 0 0 0)){
            /* display-p3 color space supported */
            background:color(display-p3 0 0 0);
          }
          
          
          @supports(background:oklch(0 0 0)){
            /* oklch color space supported */
            background:oklch(0 0 0);
          }
          
          

          應用實例

          在實際應用中,在新舊標準過渡期間,可以綜合使用上邊的查詢方法,下面是一個兼容新舊標準的實例:

          :root{
            --neon-red:rgb(100% 0 0);
            --neon-blue:rgb(0 0 100%);
          }
          
          /* 設備是否支持展示高清 */
          @media(dynamic-range: high){
          
            /* 瀏覽器是否能解析display-p3 */
            @supports(color:color(display-p3 0 0 0)){
          
              /* 安全使用display-p3 */
              --neon-red:color(display-p3 1 0 0);
              --neon-blue:color(display-p3 0 0 1);
            }
          }
          
          


          開發調試

          如果更新了最新版本的chrome瀏覽器的話,就能發現DevTools里的拾色器已經支持了CSS Color 4中的新語法,點擊頁面元素中的顏色屬性,在彈出的拾色器中,中間色值右側的箭頭,之前的版本中,點擊箭頭是在hex、rgb、hsl和hwb之間切換,但新版本中,點擊箭頭會出現下拉框,可以看到所有新增的色彩空間和方法,以及當前色值所對應的可替換色值。

          ??同時在選擇了不同的色彩空間后,色彩的可調節參數也會相應改變。

          ??當我們選擇了一個非sRGB色域的色值后,會發現拾色器的上方區域里會展示一條sRGB的分界線,可以清晰地看出當前選擇的顏色所在的色域。這能幫助開發者分辨高清色與非高清色。

          ??而當我們選擇一個超出sRGB范圍的顏色后,再來點擊色值右側的箭頭彈出選項列表時,會發現sRGB色域下的色值后邊會帶上一個三角嘆號。這說明當前色值已超出了sRGB所能描述的范圍,只能使用相近的顏色作為替代。

          ??關于chrome DevTools更多關于高清顏色的更新,可參閱官方文檔。

          總結

          sRGB之外的色域和色彩空間目前雖然還剛剛在web端起步,但未來的設計和開發要求可能會慢慢出現,尤其是H5動畫、游戲、3D圖像等等,對于色彩顯示的要求不會永遠停留在sRGB階段,希望本文簡陋的介紹能讓大家多少開始了解一些關于色彩的東西。如有錯誤或疏漏,歡迎指正討論。

          參考文章:

          1. https://web.dev/articles/color-spaces-and-functions?hl=en

          2. https://developer.chrome.com/articles/high-definition-css-color-guide/

          3. https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color

          作者:京東科技 鄭莉

          來源:京東云開發者社區 轉載請注明來源

          在學習和工作中,我們經常需要使用日志來記錄程序的運行狀態和調試信息。而為了更好地區分不同的日志等級,我們可以使用不同的顏色來呈現,使其更加醒目和易于閱讀。

          在下圖運行結果中,我們使用了 colorlog 庫來實現彩色日志輸出。通過定義不同日志等級對應的顏色,我們可以在控制臺中以彩色的方式顯示日志信息。例如,DEBUG 級別的日志使用白色,INFO 級別的日志使用綠色,WARNING 級別的日志使用黃色,ERROR 級別的日志使用紅色,CRITICAL 級別的日志使用藍色。

          但是在查看日志文件時,我們會發現日志信息是系統默認的字體顏色,并且前后多了一些特殊符號,例如 [32m 等。這是因為在控制臺中使用的是 ANSI 轉義序列來實現彩色文本效果,而這些特殊符號是 ANSI 轉義序列的一部分。如下圖所示:

          現在有一個需求,在前端頁面直接查看日志內容并還原彩色文本效果,因此,我們將進行以下內容講解:

          1. 什么是 ANSI 轉義序列?
          2. 如何在前端頁面直接查看日志內容?
          3. 如何在前端頁面還原彩色文本效果?

          本文代碼點擊此處跳轉,往期系列文章請訪問博主的 項目實戰專欄,博文中的所有代碼全部收集在博主的 GitHub 倉庫中;

          ANSI 轉義序列

          ANSI 轉義序列是美國國家標準化組織(American National Standards Institute,ANSI)制定的標準,是一種用于控制文本終端顯示的特殊字符序列。它們以 3[ 開頭,以字母和數字組合的形式表示不同的控制功能。

          ANSI 轉義序列可以用于控制文本的顏色、背景色、文本樣式(如粗體、斜體等)、光標位置、清屏等操作。通過在輸出文本中插入適當的 ANSI 轉義序列,可以實現豐富的終端顯示效果。

          以下是一些常用的 ANSI 轉義序列示例:

          • 3[0m:重置所有屬性,恢復默認設置;
          • 3[31m:設置文本顏色為紅色;
          • 3[42m:設置背景顏色為綠色;
          • 3[1m:設置文本為粗體;
          • 3[4m:設置文本為下劃線;
          • 3[2J:清屏;

          需要注意的是,ANSI 轉義序列在不同的終端和操作系統上的支持程度可能會有所不同。在某些終端中,可能無法正確解釋和顯示 ANSI 轉義序列。

          我們以 3[31m 和 3[42m 為例,輸出一個綠底紅字的句子 Hello World! --sidiot.,代碼如下所示:

          log.debug("3[42m3[31mHello World! --sidiot.3[0m3[0m")

          運行結果:

          前端頁面直接查看日志內容

          這里的話,我們使用 Python 的 http.server 模塊來啟動一個簡單的 HTTP 服務器。

          比較快捷的方式就是在日志文件夾中打開終端,輸入 python -m http.server 8888 即可,運行結果如下所示:

          不過這種方式相對來說還是不太安全的,因此我們可以通過設置白名單的方式,來規避一些潛在的安全隱患,代碼如下所示:

          import http.server
          import socketserver
          
          class HTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
              def check_client_address(self):
                  # 設置白名單,只允許特定的IP地址或主機訪問
                  whitelist = ['127.0.0.1', 'localhost']
          
                  client_address = self.client_address[0]
                  if client_address not in whitelist:
                      self.send_response(403)
                      self.end_headers()
                      self.wfile.write(b'Forbidden. Please contact sidiot.')
                      return False
          
                  return True
          
              def do_GET(self):
                  if not self.check_client_address():
                      return
                  
                  super().do_GET()
          
          with socketserver.TCPServer(('0.0.0.0', 8888), HTTPRequestHandler) as httpd:
              httpd.serve_forever()

          目前本機的 IP 為 192.168.124.23,當我們以 127.0.0.1 來訪問 8888 服務端口時,訪問是成功的,但是當我們用 192.168.124.23 來訪問服務端口時,訪問是失敗的。

          運行結果:

          現在我們點擊文件,它會直接通過瀏覽器直接下載,但是我們需要的是在網頁上能夠直接閱覽文件中的內容,因此我們可以從 do_GET() 下手。

          我們可以設計一個根據傳入的文件名參數,讀取本地文件并作為響應結果進行返回的方法,然后根據一定的規則進行觸發,代碼如下所示:

          def read_file(self):
              try:
                  self.send_response(200)
                  self.send_header("Content-Type", "text/plain; charset=utf-8")
                  self.end_headers()
                  self.wfile.write(open(self.path[6:], 'rb').read())
          
              except FileNotFoundError:
                  self.send_response(404)
                  self.end_headers()
                  self.wfile.write(b'File not found!')
          
          def do_GET(self):
              if self.check_client_address():
                  if self.path.startswith("/?log="):
                      self.read_file()
                  else:
                      super().do_GET()

          上述代碼通過檢查請求的資源路徑來處理 GET 請求。如果請求的資源路徑前綴是 /?log=,且是當前目錄下存在的日志文件,它會讀取文件并將其內容作為響應發送。否則,它會使用基類的默認行為處理普通的 GET 請求。

          運行結果:

          至此,我們已經實現了前端頁面直接查看日志內容的功能。

          前端頁面還原彩色文本效果

          原理分析

          當我們想要在前端頁面展示 ANSI 字體的彩色效果時,我們只需要簡單地將 ANSI 轉義序列轉換成相應的 HTML 代碼就可以實現了。這個轉換過程實際上可以通過編寫一個 Python 函數來實現,該函數可以接受包含 ANSI 控制碼的字符串作為輸入,并將其轉換為帶有相應樣式的 HTML 代碼輸出,代碼如下所示:

          def convert_ansi_to_html(ansi_text):
              ansi_to_html = {
                  '\x1b[31m': '<span style="color: red;">',
                  '\x1b[42m': '<span style="background-color: green;">',
                  ...,
              }
              html_text = re.sub(r'\x1b[[0-9;]*m', lambda match: ansi_to_html.get(match.group(0), ''), ansi_text)
          
              return html_text
          
          
          if __name__ == '__main__':
              ansi = "\033[42m\033[31mHello World! --sidiot.\033[0m\033[0m"
              print(ansi)
              html = convert_ansi_to_html(ansi)
              print(f"convert content: {html}")

          需要注意的是,在 ANSI 轉義序列中,\x1b 和 3 都代 表ASCII 碼中的 Escape 字符,用于開始一個轉義序列。

          運行結果:

          使用 ansiconv 轉換

          接下來,我們借助已有的庫函數 ansiconv 進行 ANSI 的轉換。

          通過 pip 進行安裝:

          pip install ansiconv

          根據 ansiconv 的官方文檔使用其中的三個方法 to_plain(),to_html() 和 base_css() 來實現在前端頁面展示 ANSI 字體的彩色效果,代碼如下所示:

          import ansiconv
          
          ansi = "\033[42m\033[31mHello World! --sidiot.\033[0m\033[0m"
          print(f"Ansi: {ansi}")
          plain = ansiconv.to_plain(ansi)
          html = ansiconv.to_html(ansi)
          print(f"Convert Plain: {plain}")
          print(f"Convert HTML: {html}")

          在 base_css() 中會有相關的 CSS 映射表,如下所示:

          css_rule('.ansi31', color="#FF0000"),
          css_rule('.ansi42', background_color="#00FF00"),

          運行結果:

          研究 ansiconv 源碼

          我們將通過研究 ansiconv 的源碼,以便深入了解它是如何將 ANSI 轉換成純文本或 HTML 代碼的工作原理。

          to_plain() 的源碼如下所示:

          上述代碼使用正則表達式匹配字符串中的 ANSI 轉義序列,并將其替換為空字符串,從而得到不包含轉義序列的純文本。

          正則表達式的含義如下:

          • \x1B:匹配 ESCAPE 字符;
          • \[:匹配左方括號;
          • [0-9;]*:匹配零個或多個數字或分號;
          • [ABCDEFGHJKSTfmnsulh]:匹配 ANSI 轉義序列中的控制字符;

          我們通過 re.findall() 方法來獲取所有匹配的結果,這樣夠清晰地捕獲所有符合條件的匹配項,從而更好地理解 ansiconv 是如何進行 ANSI 到純文本的轉換,代碼如下所示:

          ansi = "\033[42m\033[31mHello World! --sidiot.\033[0m\033[0m"
          print(re.findall(r'\x1B[[0-9;]*[ABCDEFGHJKSTfmnsulh]', ansi))

          運行結果:


          to_html() 的源碼如下所示:

          上述代碼將 ANSI 字符串分割成塊,并對每個塊調用 _block_to_html() 函數進行解析和轉換,同時還處理了 ANSI 命令 "A",模擬向上移動光標的行為。如果 replace_newline 為 True,則 HTML 字符串中的換行符 \n 將替換為 <br />\n 以保留 HTML 輸出中的換行符。

          其中 _block_to_html() 的源碼如下所示:

          上述代碼使用正則表達式匹配 ANSI 代碼,并根據匹配結果生成對應的 HTML 代碼。

          正則表達式的含義:

          • ^:表示匹配字符串的開頭。
          • \[:匹配左方括號 [。
          • (?P<code>\d+(?:;\d+)*)?:這是一個命名捕獲組,用于匹配 ANSI 代碼中的數字部分。它由以下組成: \d+:匹配一個或多個數字。 (?:;\d+)*:這是一個非捕獲組,用于匹配分號 ; 和一個或多個數字的重復出現。(?: ... ) 表示非捕獲組,* 表示重復零次或多次。
          • (?P<command>[Am]):這是另一個命名捕獲組,用于匹配 ANSI 代碼中的命令部分。它由以下組成: [Am]:匹配字符 A 或 m。

          我們可以通過運行源碼里的部分代碼來幫助理解,代碼如下所示:

          text = ("\x1B[0;32;45msidiot\n"
                  "\033[42m\033[31mHello World! --sidiot.\033[0m\033[0m")
          print(text)
          blocks = text.split('\x1B')
          print(blocks)
          for block in blocks:
              match = re.match(r'^[(?P<code>\d+(?:;\d+)*)?(?P<command>[Am])', block)
              if match is not None:
                  print("\nmatch:", match, ", code:", match.group('code'), ", command:", match.group('command'))

          運行結果:

          實際應用

          通過深入理解 ANSI 轉換思路和 ansiconv 源碼,我們可以為之前的 http.server 服務帶來全新的優化。

          首先,將原先的 read_file() 方法進行優化,代碼如下所示:

          def read_file(self, content_type, file_io):
              try:
                  self.send_response(200)
                  self.send_header("Content-Type", f"{content_type}; charset=utf-8")
                  self.end_headers()
                  self.wfile.write(file_io)
          
              except FileNotFoundError:
                  self.send_response(404)
                  self.send_header("Content-Type", "text/plain; charset=utf-8")
                  self.end_headers()
                  self.wfile.write(b'File not found!')

          上述代碼通過接收 content_type 和 file_io 兩個參數,實現將自定義內容作為響應返回給客戶端。

          然后修改請求路徑,使其能夠返回純文本HTML 兩種不同類型的內容,代碼如下所示:

          def do_GET(self):
              if self.check_client_address():
                  if self.path.startswith("/?plain="):
                      file = open(self.path[8:], 'rb').read()
                      plain = ansiconv.to_plain(file.decode('UTF-8'))
                      self.read_file("text/plain", plain.encode())
                  elif self.path.startswith("/?html="):
                      file = open(self.path[7:], 'rb').read()
                      conv = ansiconv.to_html(file.decode('UTF-8'))
                      css = ansiconv.base_css()
                      html = """
                      <html>
                        <head><style>{0}</style></head>
                        <body>
                          <pre class="ansi_fore ansi_back">{1}</pre>
                        </body>
                      </html>
                      """.format(css, conv)
                      print(html)
                      self.read_file("text/html", html.encode())
                  else:
                      super().do_GET()

          這里要注意的是,需要設置 CSS 樣式,不然 class 類是無法進行渲染的。

          純文本運行結果:

          HTML 運行結果:

          后記

          在本文中,我們探討了如何實現將 ANSI 字體在前端頁面進行彩色展示的方法。在前端頁面中直接顯示 ANSI 轉義序列是不起作用的,因為瀏覽器不會解析和處理這些轉義序列。

          為了在前端頁面實現彩色展示,我們介紹了一種方法,即將 ANSI 轉義序列轉換為對應的 HTML 代碼。通過解析 ANSI 轉義序列并將其轉換為適當的 HTML 標簽和樣式,我們可以在前端頁面上還原彩色文本的效果。

          在本文中,我們使用了 Python 中的 ansiconv 庫來實現 ANSI 轉換。該庫提供了 to_plain 和 to_html 兩個方法,分別用于將 ANSI 轉義序列轉換為純文本和 HTML 代碼。我們還展示了如何使用這些方法來轉換 ANSI 字符串,并在前端頁面上顯示轉換后的結果。

          通過本文的介紹,讀者可以了解到如何在前端頁面實現彩色文本的展示,從而提升用戶體驗和可讀性。無論是在日志查看器、終端模擬器還是其他需要展示彩色文本的應用中,這種技術都能發揮重要作用。

          以上就是 從終端到瀏覽器:實現 ANSI 字體在前端頁面的彩色展示 的所有內容了,希望本篇博文對大家有所幫助!歡迎大家持續關注我的博客,一起分享學習和成長的樂趣!?

          作者:sidiot
          鏈接:https://juejin.cn/post/7381820436274184202

          reamweaver的CSS面板分類

          type(類型)

          background(背景)

          block(區塊)

          box(方框) 或盒子意思

          border(邊框)

          list(列表)

          positioning(定位)

          extensions(擴展)

          共八個部分

          1. type(類型)

          type面板主要是對文字的字體,大小,顏色,效果等基本樣式進行設置。

          注意:屬性名帶*號的是指樣式效果不能在編輯文檔時顯示,要用瀏覽器打開才能看到效果。

          (1)font-family:設置字體系列。什么叫字體系列呢?是指對文字設定幾個字體,當遇到第一個字體不能顯示的文字時會自動用系列中的第二個

          字體或后面的字體顯示。

          注意:一般英文字體我們用"Verdana, Arial, Helvetica, sans-serif"這個系列比較好看。如果不用這些字體系列,你就需要自己編輯字體系列,

          也可以直接手動在下拉框里寫字體名,字體之間用逗號隔開。中文網頁默認字體是宋體, 一般就空著不要選取任何字體。

          默認值: not specified(取決于瀏覽器,系統默認的字體, 如: 微軟雅黑)


          注意:

          1.如果有漢字, 那么我們要加引號

          2.如果有多個英文字母組成的單詞, 我們也要加引號; "microsoft yahei" 中間用空格隔開

          3.font-family:"黑體","宋體","華文隸書"; 首先找黑體, 沒有黑體找宋體...

          為了避免在CSS中使用 font 或 font-family 設置中文字體時亂碼, 可以使用 Unicode 編碼來表示字體。

          /* 示例:使用Unicode字體編碼設置字體為"微軟雅黑" */
          font-family: "\5FAE\8F6F\96C5\9ED1";


          (2)font-size:定義文字的大小。你可以通過選取數字和度量單位來選擇具體的字體大小,或者你也可以選擇一個相對的字體大小。

          最好使用pixels作為單位,這樣不會在瀏覽器中文本變形。一般字體用比較標準的12px或14px, 默認值為16px。

          注意:CSS中長度的單位分絕對長度單位和相對長度單位:

          絕對長度單位有:

          pt:磅(point)

          mm、cn、in、pc:(毫米、厘米、英寸、活字)根據顯示的實際尺寸來確定長度。

          此類單位不隨顯示器的分辨率改變而改變。

          相對長度單位有:

          px:(像素)根據顯示器的分辨率來確定長度。

          em:當前文本的尺寸。例如:{font-size:2em}是指文字大小為原來的2倍。

          比如自身font-size: 30px; 那么此時1em=30px;

          ex:當前字母"x"的高度,一般為字體尺寸的一半。

          %:是以當前文本的百分比定義尺寸。例如:{ font-size:300%}是指文字大小為原來的3倍。

          small、large:表示比當前小一個級別或大一個級別的尺寸。

          默認值:medium(標準大小)


          (3)font-style:定義字體樣式為normal、italic、oblique。默認設置為normal。

          注意: italic 斜體 oblique 歪斜體 italic和oblique實際效果是一樣的。

          默認值:normal


          (4)line-height:設置文本所在行的行高。默認為normal。可以是行內元素、行內塊元素, 通常與height設置的高度值相同, 可以做到垂直居中的作用。

          你也可以自己鍵入一個精確的數值并選取一個計量單位。

          比較直觀的寫法用百分比, 例如140%是指行高等于文字大小的1.4倍。

          最常用的方法: line-height:1.5em; /*行間距,相對數值,1.5倍行距,*/ 可有效的避免文字發生重疊

          默認值: normal


          (5)text-decoration:在文本中添加underline(下劃線)、overline(上劃線)、line-through(中劃線)、blink(閃爍效果)。

          這些效果可以同時存在,將效果前的復選框選定即可。

          注意:鏈接的默認設置是underline,我們可以通過選none去除下劃線。blink(閃爍效果)只在mozilla瀏覽器里可以看到, IE、opera不支持

          默認值: none


          (6)font-weight:給字體指定粗體字的磅值。

          normal 默認值。定義標準的字符。

          bold 定義粗體字符。

          bolder 定義更粗的字符。

          lighter 定義更細的字符。

          100

          200

          300

          400

          500

          600

          700

          800

          900

          inherit 規定應該從父元素繼承字體的粗細。

          定義由粗到細的字符。400 等同于 normal, 而 700 等同于 bold。

          默認值: normal


          (7)font-variant:允許你選取字體的變種, 選small-caps(小型大寫字母)時, 此樣式區域內所有字母大寫。

          normal表示正常的字體, 為默認值;

          默認值: normal


          (8)text-transform:將選區中每個單詞的第一個字母轉為大寫, 或者令單詞全部大寫或全部小寫。

          參數:capitalize(單詞首字母大寫)、uppercase(轉換成大寫)、lowercase(轉換成小寫)、none(不轉換)。

          默認值:none


          (9)color:定義文字顏色。包括對表單輸入的文字顏色。

          CSS中顏色的值有三種表示方法:

          #RRGGBB格式,是由紅綠藍三種顏色的值組合,每種顏色的值為"00 – FF"的兩位十六進制正整數。

          例如:#FF0000表示紅色,#FFFF00表示黃色。

          rgb(R,G,B)格式, RGB為三色的值, 取0~255, 例如:rgb(255,0,0)表示紅色, rgb(255,255,0)表示黃色。

          用顏色名稱。CSS可以使用已經定義好的顏色名稱。例如:red表示紅色, yellow表示黃色。

          顏色值的縮寫:

          p{color:#000000} 可以縮寫為:p{color:#000}

          p{color:#336699} 可以縮寫為:p{color:#369}

          默認值: not specified


          color: transparent; 透明色


          rgba() 解釋: rgba(紅0-255, 綠0-255, 藍0-255, 透明度0-1)


          注意: 如果文字的顏色通過單獨的類選擇去設置沒有改變顏色, 則應該通過組合選擇器(.header .top .topR .blue)去設置, 改變它的優先級。




          2. background(背景)

          background面板主要是對元素的背景進行設置,包括背景顏色、背景圖象、背景圖象的控制。

          一般是對body(頁面)、table(表格)、div(區域)的設置。

          (1)background-color:設置元素的背景色。包括對input表單輸入框的背景顏色;

          默認值: transparent(背景顏色為透明)


          rgba() 解釋: rgba(紅0-255, 綠0-255, 藍0-255, 透明度0-1) 一般用于背景色


          (2)background-image:設置元素的背景圖像。

          默認值:none

          CSS3支持多重背景圖,只要加上一個url指定圖片路徑,并用逗號(,)將兩組url分隔就可以了

          background-image:url(a.jpg),url(b.jpg);


          base64使用

          background-image: url("data:image/png;base64,iVBORw0KGgo=...");


          (3)background-repeat:確定背景圖像是否以及如何重復。

          repeat 默認值。背景圖像將在垂直方向和水平方向重復。

          repeat-x 背景圖像將在水平方向重復。

          repeat-y 背景圖像將在垂直方向重復。

          no-repeat 背景圖像將僅顯示一次。

          inherit 規定應該從父元素繼承background-repeat屬性的設置。

          注意:如果定義的元素的body,可以控制頁面背景是否重復。

          默認值: repeat


          (4)background-attachment:固定背景圖像或者跟隨內容滾動。

          參數fixed表示固定背景(不隨屏幕滾動而滾動,決定背景圖像是否要固定在原來的位置), scroll表示跟隨內容滾動的背景。

          注意:如果定義的元素的body, 可以使頁面背景固定。

          默認值: scroll


          (5)background-position(X):指定背景圖像的水平位置。

          可以指定為left(左邊), center(居中),right(右邊);

          也可以指定數值,如20px是指背景距離左邊20象素。

          background-position(Y):指定背景圖像的垂直位置。

          可以指定為top(頂部), center(居中), bottom(底部);也可以指定數值。

          background-position屬性值:

          left top

          center top

          right top

          left center

          center center

          right center

          left bottom

          center bottom

          right bottom

          如果您僅規定了一個關鍵詞,那么第二個值將是"center"。

          注意:采用英文單詞的水平位置和垂直位置的屬性值可以調換

          x% y% 第一個值是水平位置,第二個值是垂直位置。左上角是 0% 0%。右下角是 100% 100%。如果您僅規定了一個值,另一個值將是 50%。

          xpos ypos 第一個值是水平位置,第二個值是垂直位置。左上角是 0 0。單位是像素 (0px 0px) 或任何其他的 CSS 單位。

          如果您僅規定了一個值,另一個值將是50%。

          您可以混合使用 % 和 position 值。

          默認值:0% 0%


          主站蜘蛛池模板: 精品无码一区在线观看| 久久精品道一区二区三区| 99精品国产一区二区三区不卡| 欧洲精品一区二区三区| 中文字幕一区精品| 欧美日韩国产免费一区二区三区| 国产综合无码一区二区辣椒 | 亚洲综合av一区二区三区| 国产一区二区三区在线视頻| 亚无码乱人伦一区二区| 精品人伦一区二区三区潘金莲| 国产一区二区福利久久| 亚洲乱码av中文一区二区| 久久精品一区二区三区四区| chinese国产一区二区| 夜夜精品视频一区二区| 国产91大片精品一区在线观看| 国产视频一区二区在线播放| 日本一区二区三区免费高清在线| 色婷婷av一区二区三区仙踪林| 亚洲视频一区在线观看| 久久一区二区明星换脸| 日本大香伊一区二区三区| 国产伦精品一区二区三区视频金莲 | 久久精品一区二区国产| 亚洲国产专区一区| 日本一区二区三区免费高清在线| 手机福利视频一区二区| 亚洲欧美日韩中文字幕一区二区三区 | 色偷偷av一区二区三区| 国产婷婷色一区二区三区| 国产AV国片精品一区二区| 国产福利电影一区二区三区久久老子无码午夜伦不 | 少妇特黄A一区二区三区| 亚洲永久无码3D动漫一区| 天堂Aⅴ无码一区二区三区| 精品伦精品一区二区三区视频| 亚洲AV无码一区二区三区在线观看 | 麻豆一区二区99久久久久| 乱码精品一区二区三区| 日韩人妻精品无码一区二区三区|