整合營銷服務商

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

          免費咨詢熱線:

          HTML樣式:好看的顏色字體是有方法的

          TML 樣式實例 - 背景顏色

          background-color 屬性為元素定義了背景顏色:

          <html>
          <body style="background-color:yellow">
          <h2 style="background-color:red">This is a heading</h2>
          <p style="background-color:green">This is a paragraph.</p>
          </body>
          </html>
          

          HTML樣式:好看的顏色字體是有方法的

          23 年的 CSS 新特性中,有一個非常重要的功能更新 -- 相對顏色

          簡單而言,相對顏色的功能,讓我們在 CSS 中,對顏色有了更為強大的掌控能力。

          其核心功能就是,讓我們能夠基于一個現有顏色 A,通過一定的轉換規則,快速生成我們想要的顏色 B

          其功能能夠涵蓋:

          • 精簡
          • 調暗
          • 飽和度
          • 降低飽和度
          • 色度增強
          • 調整不透明度
          • 反轉
          • 補充
          • 轉換
          • 對比度
          • 調色板

          當然,今天我們不會一個一個去過這些功能,更多的時候,我們只需要知道我們能夠實現這些功能。

          本文,我們將從實際實用角度出發,基于實際的案例,看看 CSS 相對顏色,能夠如何解決我們的一些實際問題。

          快速語法入門

          首先,我們通過一張圖,一個案例,快速入門 CSS 相對顏色語法:

          相對顏色語法的目標是允許從另一種顏色派生顏色。

          上圖顯示了將原始顏色 green 轉換為新顏色的顏色空間后,該顏色會轉換為以 r、g、b 和 alpha 變量表示的各個數字,這些數字隨后會直接用作新的 rgb() 顏色的值。

          舉個例子:

          <p> CSS Relative Color </p>
          
          p {
              color: rgb(255, 0, 0);
          }

          實現一個 color 為紅色(rgb 值為 rgb(255, 0, 0))的字體:

          基于上面的相對顏色語法,我如何通過一個紅色生成綠色文字呢?示意如下:

          p {
              --color: rgb(255, 0, 0);
              color: rgb(from var(--color) calc(r - 255) calc(g + 255) b);  /* result = rgb(0, 255, 0) */
          }
          

          效果如下,我們就得到綠色字體:

          解釋一下:

          1. 原本的紅色顏色,我們把它設置為 CSS 變量 --color: rgb(255, 0, 0)
          2. 想通過紅色得到綠色,對于紅色的 rgb 值 rgb(255, 0, 0) 而言,需要轉換成 rgb(0, 255, 0)
          3. 使用 CSS 相對顏色語法,就是 rgb(from var(--color) calc(r - 255) calc(g + 255) b)

          通過這個 DEMO,我們把幾個核心基礎語法點學習一下:

          1. from 關鍵字

          from 關鍵字,它是相對顏色的核心。它表示會將 from 關鍵字后的顏色定義轉換為相對顏色!在 from 關鍵字后面,CSS 會期待一種顏色,即能夠啟發生成另一種顏色

          1. from 關鍵字 后的顏色表示,支持不同顏色表示或者是 CSS 變量

          第二個關鍵點,from 后面通常會接一個顏色值,這個顏色值可以是任意顏色表示法,或者是一個 CSS 變量,下面的寫法都是合法的:

          p {
              color: rgba(from #ff0000) r g b);
              color: rgb(from rgb(255, 0, 0) r g b);
              color: rgb(from hsl(0deg, 100%, 50%) r g b);
              color: rgb(from var(--hotpink) r g b);
          }
          
          1. 對轉換后的變量使用 calc() 或其他 CSS 函數

          另外一個非常重要的基礎概念就是,我們可以對 (from color r g b) 后的轉換變量 r g b 使用 calc() 或其他 CSS 函數。

          就是我們上面的例子:

          p {
              --color: rgb(255, 0, 0);
              color: rgb(from var(--color) calc(r - 255) calc(g + 255) b);  /* result = rgb(0, 255, 0) */
          }
          
          1. 相對顏色語法支持,各種顏色表示函數:

          相對顏色的基礎的使用規則就是這樣,它不僅支持 rgb 顏色表示法,它支持所有的顏色表示法:

          • sRGB 顏色空間:hsl()、hwb()、rgb();
          • CIELAB 顏色空間:lab()、lch();
          • Oklab 顏色空間:oklab()、oklch();

          使用 CSS 相對顏色,實現統一按鈕點擊背景切換

          通常頁面上的按鈕,都會有 hover/active 的顏色變化,以增強與用戶的交互。

          像是這樣:

          最常見的寫法,就是我們需要在 Normal 狀態、Hover 狀態、Active 狀態下寫 3 種顏色:

          p {
              color: #ffcc00;
              transition: .3s all;
          }
          /* Hover 偽類下為 B 顏色 */
          p:hover {
              color: #ffd21f;
          }
          /** Active 偽類下為 C 顏色 **/
          p:active {
              color: #ab8a05;
          }
          

          在之前,我們介紹過一種利用濾鏡 filter: contrast() 或者 filter: brightness() 的統一解決方案,無需寫多個顏色值,可以根據 Normal 狀態下的色值,通過濾鏡統一實現更亮、或者更暗的偽類顏色。

          在今天,我們也可以利用 CSS 相對顏色來做這個事情:

          div {
              --bg: #fc0;
              background: var(--bg);
              transition: .3s all;
          }
          
          div:hover {
              background: hsl(from var(--bg) h s calc(l * 1.2));
          }
          div:active {
              background: hsl(from var(--bg) h s calc(l * 0.8));
          }
          

          我們通過 hsl 色相、飽和度、亮度顏色表示法表示顏色。實現:

          1. 在 :hover 狀態下,根據背景色,將背景亮度 l 調整為原背景色的 1.2 倍
          2. 在 :avtive 狀態下,根據背景色,將背景亮度 l 調整為原背景色的 0.8 倍

          在實際業務中,這是一個非常有用的用法。

          使用 CSS 相對顏色,實現文字顏色自適應背景

          相對顏色,還有一個非常有意思的場景 -- 讓文字顏色能夠自適應背景顏色進行展示。

          有這么一種場景,有的時候,無法確定文案的背景顏色的最終表現值(因為背景顏色的值可能是后臺配置,通過接口傳給前端),但是,我們又需要能夠讓文字在任何背景顏色下都正常展現(譬如當底色為黑色時文字應該是白色,當背景為白色時,文字應該為黑色)。

          像是這樣:

          在不確定背景顏色的情況下,無論什么情況,文字顏色都能夠適配背景的顏色。

          在之前,純 CSS 沒有特別好的方案,可以利用 mix-blend-mode: difference 進行一定程度的適配:

          div {
              // 不確定的背景色
          }
          p {
              color: #fff;
              mix-blend-mode: difference;
          }
          

          實操過這個方案的同學都會知道,在一定情況下,前景文字顏色還是會有一點瑕疵。并且,混合模式這個方案最大的問題是會影響清晰度

          有了 CSS 相對顏色后,我們有了更多的純 CSS 方案。

          利用 CSS 相對顏色,反轉顏色

          我們可以利用相對顏色的能力,基于背景色顏色進行反轉,賦值給 color。

          一種方法是將顏色轉換為 RGB,然后從 1 中減去每個通道的值。

          代碼非常簡單:

          p {
              /** 任意背景色 **/
              --bg: #ffcc00;
              background: var(--bg);
          
              color: rgb(from var(--bg) calc(1 - r) calc(1 - g) calc(1 - b));  /** 基于背景反轉顏色 **/
          }
          

          用 1 去減,而不是用 255 去,是因為此刻,會將 rgb() 表示法中的 0~255 映射到 0~1。

          效果如下:

          配個動圖,我們利用背景色的反色當 Color 顏色,適配所有背景情況:

          完整的 DEMO 和代碼,你可以戳這里:CodePen Demo -- CSS Relatvie Color Adapt BG

          當然,這個方案還有兩個問題:

          1. 如果顏色恰好是在 #808080 灰色附近,它的反色,其實還是它自己!會導致在灰色背景下,前景文字不可見;
          2. 絕大部分情況雖然可以正常展示,但是并不是非常美觀好看

          為了解決這兩個問題,CSS 顏色規范在 CSS Color Module Level 6 又推出了一個新的規范 -- color-contrast()

          利用 color-contrast(),選擇高對比度顏色

          color-contrast() 函數標記接收一個 color 值,并將其與其他的 color 值比較,從列表中選擇最高對比度的顏色。

          利用這個 CSS 顏色函數,可以完美的解決上述的問題。

          我們只需要提供 #fff 白色和 #000 黑色兩種可選顏色,將這兩種顏色和提供的背景色進行比較,系統會自動選取對比度更高的顏色。

          改造一下,上面的代碼,它就變成了:

          p {
              /** 任意背景色 **/
              --bg: #ffcc00;
              background: var(--bg);
          
              color: color-contrast(var(--bg) vs #fff, #000);  /** 基于背景色,自動選擇對比度更高的顏色 **/
          }
          

          這樣,上面的 DEMO 最終效果就變成了:

          此方案的優勢在于:

          1. 可以限定前景 color 顏色為固定的幾個色值,以保證 UI 層面的統一及美觀
          2. 滿足任何情況下的背景色

          當然,唯一限制這個方案的最大問題在于,當前,color-contrast 還只是一個實驗室功能,未大規模被兼容。

          總結一下

          到今天,我們可以利用 CSS 提供的各類顏色函數,對顏色有了更為強大的掌控力。

          很多交互效果,不借助 JavaScript 的運算,也能計算出我們想要的最終顏色值。本文簡單的借助:

          1. 使用 CSS 相對顏色,實現統一按鈕點擊背景切換
          2. 使用 CSS 相對顏色,實現文字顏色自適應背景

          兩個案例,介紹了 CSS 相對顏色的功能。


          原文鏈接:https://juejin.cn/post/7321410822789742618

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

          在下圖運行結果中,我們使用了 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


          主站蜘蛛池模板: 亚洲av无码一区二区三区天堂| 色欲综合一区二区三区| 国产一区玩具在线观看| 乱子伦一区二区三区| 亚洲日韩AV一区二区三区四区| 中文字幕无线码一区| 日本一区免费电影| 国产精品伦子一区二区三区| 无码人妻一区二区三区免费看| 高清一区二区在线观看| 日韩成人一区ftp在线播放| 中文字幕一区二区三区久久网站| 插我一区二区在线观看| 一区二区三区在线视频播放| 相泽南亚洲一区二区在线播放| 亚洲一区二区无码偷拍| 亚洲一区二区三区播放在线| 人妻体内射精一区二区三四| 无码人妻一区二区三区在线| 国产精品日本一区二区不卡视频| 久久无码一区二区三区少妇 | 99久久精品国产免看国产一区| 国产伦精品一区二区三区不卡 | 精品国产一区二区三区久久蜜臀 | 人妻体体内射精一区二区| 国产一区二区三区在线2021| 国产亚洲福利精品一区| 午夜天堂一区人妻| 人妻体内射精一区二区三区| 精品一区精品二区制服| 亚洲福利一区二区三区| 国产情侣一区二区| 无码精品人妻一区二区三区影院| 一区二区三区精品高清视频免费在线播放 | 四虎成人精品一区二区免费网站| 伊人色综合一区二区三区影院视频| 人妖在线精品一区二区三区| 国产精品无码一区二区三区免费| 波多野结衣av高清一区二区三区| 一区二区三区四区在线视频| 手机看片福利一区二区三区|