做者: JowayYoung
倉庫: Github、 CodePen
博客: 官網、 掘金、 思否、 知乎
公衆號: IQ前端
特別聲明:原創不易,未經受權不得轉載或抄襲,如需轉載可聯繫筆者受權
暗黑模式這個概念最先起源於MacOS系統
的Mojave
,提供淺色主題
和深色主題
兩種皮膚供用戶選擇,深色主題
就是咱們常說的暗黑模式
。爲了眼睛健康,筆者在手機、平板和電腦上都選擇了暗黑模式
。css
隨着蘋果官方逐漸要求各大系統平臺都得適配暗黑模式
,因此筆者也探索出一種應該是市面上最低成本的網站暗黑模式適配方案
。html
認識筆者的朋友應該都知道筆者是一位重度CSS發燒友,固然此次也是使用純CSS實現這個方案。是的,不加任何一段JS,側面再次證實CSS的強大。前端
思路很簡單,使用一個按鈕來回切換主題樣式。按鈕未選中則切換到淺色主題
,按鈕選中則切換到深色主題
。可用:checked
和+
打輔助完成這個任務。ios
使用<input>
模擬按鈕,當按鈕處於選中狀態時觸發:checked
,經過+
帶動後面相鄰的網站主體<div>
進入暗黑模式
,選中狀態取消時則退出暗黑模式
。git
<body> <input class="ios-switch" type="checkbox"> <div class="main">網站主體</div> </body>
更多選擇器的功能和分類請回看筆者這篇文章《多是最全最易記的CSS選擇器分類大法》。github
打算設計一個美觀的按鈕,但是沒有特別思路,就打開iPhone,把設置裏的切換按鈕
用純CSS實現一番。segmentfault
尺寸和顏色都是與iPhone切換按鈕一致。思路是使用<input>
模擬按鈕,聲明appearance:none
將其默認外觀抹去,使用::before
模擬背景區域,使用::after
模擬點擊區域,在觸發:checked
後添加一些小動畫進行修飾,近乎完美地實現了iPhone切換按鈕
。瀏覽器
<input class="ios-switch" type="checkbox">
.btn { border-radius: 31px; width: 102px; height: 62px; background-color: #e9e9eb; } .ios-switch { position: relative; appearance: none; cursor: pointer; transition: all 100ms; @extend .btn; &::before { position: absolute; content: ""; transition: all 300ms cubic-bezier(.45, 1, .4, 1); @extend .btn; } &::after { position: absolute; left: 4px; top: 4px; border-radius: 27px; width: 54px; height: 54px; background-color: #fff; box-shadow: 1px 1px 5px rgba(#000, .3); content: ""; transition: all 300ms cubic-bezier(.4, .4, .25, 1.35); } &:checked { background-color: #5eb662; &::before { transform: scale(0); } &::after { transform: translateX(40px); } } }
請戳這裏查看在線演示與源碼。sass
還記得4月4日那次全網開啓悼念模式嗎?筆者發表了一篇文章《一行代碼全站進入悼念模式》,巧妙地使用filter
這個強大的CSS屬性。app
html { filter:grayscale(1); }
真的是一行代碼,本次也不例外,一行代碼全站進入暗黑模式
。
html { filter: invert(1) hue-rotate(180deg); }
filter
的兼容性不差,各位同窗可放心使用,還有一些細節地方需注意,本文就不重複講解了,詳情可回看《一行代碼全站進入悼念模式》。
filter
是一個很是神奇的屬性,能將Photoshop
一些基礎的濾鏡效果應用到網站上。筆者平時很是喜歡使用filter
,在筆者的CodePen上有許多純CSS特效都使用了filter
,細心的同窗可能會發現筆者特別喜歡使用hue-rotate()
這個函數結合CSS變量
動態生成過渡顏色,詳情請回看《妙用CSS變量,讓你的CSS變得更心動》。
本次的暗黑模式
使用到兩個濾鏡函數:invert()
、hue-rotate()
。
0%
則無變化,值爲0~100%
則是線性乘子效果,值爲100%
則徹底反轉0deg
則無變化,值爲0~360deg
則逐漸減弱,值超過360deg
則至關繞N圈再計算剩餘的值invert()
簡單理解就是黑變白,白變黑,黑白顛倒
。hue-rotate()
簡單理解就是沖淡顏色
。爲了確保主題色調不會改變,將色相旋轉聲明爲180deg
比較合理。
依據上述分析的思路,當按鈕處於選中狀態時使用+
連帶後面的同胞元素也進入選中狀態。若同胞元素無背景色需聲明background-color:#fff
,不然沒法讓濾鏡效果起效,爲了讓這個同胞元素在使用濾鏡效果時過渡得更天然,聲明transition:all 300ms
。
.ios-switch { ... &:checked { ... & + .main { filter: invert(1) hue-rotate(180deg); } } } .main { background-color: #fff; transition: all 300ms; }
在CodePen上爲了更好地展現效果,就使用<iframe>
引入咱們最愛的掘金社區,免費爲其增長暗黑模式
切換功能😉。同時在排版上作了少許修改,請戳這裏查看在線演示與源碼。
細心的同窗可能會發現,怎麼圖片都變成照B超的感受了。
按照設計原則來講,換膚只針對組件,像一些媒體類型的元素,例如背景、圖片、視頻等,都是不能直接處理的,需保持其原樣。既然暗黑模式
是使用了濾鏡的反相和色相旋轉實現,那麼對這些媒體元素再次使用濾鏡的反相和色相旋轉就能復原了。使用過Photoshop濾鏡
的同窗應該會更清楚。
img, video { filter: invert(1) hue-rotate(180deg); }
還有一個問題,背景怎樣處理?衆所周知,背景是使用background
系列屬性進行聲明的,所以沒法經過特定的選擇器進行標註。可是,可換種思路處理,就是給有背景的元素加上一個特定類名,將其包含到上述規則裏便可。
經過Chrome DevTools
查看掘金社區
的網站源碼,發現這些頭像、縮略圖和展現圖都有一些特定類名,將其特定類名添加到規則裏。
img, video, .avatar, .image, .thumb { filter: invert(1) hue-rotate(180deg); }
在通用網站裏,這個類名可自行定義,最可行的方法就是定義一個特定類名.exclude
。不使用濾鏡效果的元素通通加上.exclude
。
.exclude { filter: invert(1) hue-rotate(180deg); }
上述爲了方便演示代碼,在CodePen Demo裏使用<iframe>
引入咱們最愛的掘金社區
。因爲沒法對<iframe>
進行樣式聲明,因此轉移到掘金社區上,經過Chrome DevTools
直接改造。
在Chrome瀏覽器
裏按F12
或Cmd+Alt+I
打開Chrome DevTools
,分析網站的HTML結構。
<body> <div id="__nuxt">...</div> </body>
往<body>
裏插入切換按鈕
。
<body> <input class="ios-switch" type="checkbox"> <div id="__nuxt">...</div> </body>
把如下SCSS代碼
轉換成CSS代碼
插入到<head>
新建的<style>
裏。推薦一個在線SASS轉CSS
的工具網站,複製如下代碼到網站裏直接轉換,完成後再貼到<style>
裏。
.btn { border-radius: 31px; width: 102px; height: 62px; background-color: #e9e9eb; } .ios-switch { position: relative; appearance: none; cursor: pointer; transition: all 100ms; @extend .btn; &::before { position: absolute; content: ""; transition: all 300ms cubic-bezier(.45, 1, .4, 1); @extend .btn; } &::after { position: absolute; left: 4px; top: 4px; border-radius: 27px; width: 54px; height: 54px; background-color: #fff; box-shadow: 1px 1px 5px rgba(#000, .3); content: ""; transition: all 300ms cubic-bezier(.4, .4, .25, 1.35); } &:checked { background-color: #5eb662; &::before { transform: scale(0); } &::after { transform: translateX(40px); } & + #__nuxt { filter: invert(1) hue-rotate(180deg); img, video, .avatar, .image, .thumb { filter: invert(1) hue-rotate(180deg); } } } } #__nuxt { background-color: #fff; transition: all 300ms; }
完成後發現切換按鈕
沒有出現,可經過position:absolute
將其絕對定位到想要顯示的位置。
.ios-switch { position: absolute; right: 0; top: 0; z-index: 99999; outline: none; }
或在<div id="__nuxt">
裏任意地方建立一個<label>
,經過聲明<input class="ios-switch" id="toggle" hidden>
和<label for="toggle">
互相綁定,將<input>
的觸發區域轉移到<label>
上。具體怎樣實現,可參照筆者這個純CSS標籤導航欄實現。
若以爲講解有點亂,可稍做整理,三步完成上述操做。
打開掘金社區網站
按F12
或Cmd+Alt+I
打開Chrome DevTools
往<head>
裏插入<style>
爲了方便複製粘貼,筆者將上述分析得出的CSS代碼進行壓縮。
<style>.btn,.ios-switch::before,.ios-switch{border-radius:31px;width:102px;height:62px;background-color:#e9e9eb;}.ios-switch{position:relative;appearance:none;cursor:pointer;transition:all 100ms;}.ios-switch::before{position:absolute;content:"";transition:all 300ms cubic-bezier(0.45,1,0.4,1);}.ios-switch::after{position:absolute;left:4px;top:4px;border-radius:27px;width:54px;height:54px;background-color:#fff;box-shadow:1px 1px 5px rgba(0,0,0,0.3);content:"";transition:all 300ms cubic-bezier(0.4,0.4,0.25,1.35);}.ios-switch:checked{background-color:#5eb662;}.ios-switch:checked::before{transform:scale(0);}.ios-switch:checked::after{transform:translateX(40px);}.ios-switch:checked + #__nuxt{filter:invert(1) hue-rotate(180deg);}.ios-switch:checked + #__nuxt img,.ios-switch:checked + #__nuxt video,.ios-switch:checked + #__nuxt .avatar,.ios-switch:checked + #__nuxt .image,.ios-switch:checked + #__nuxt .thumb{filter:invert(1) hue-rotate(180deg);}#__nuxt{background-color:#fff;transition:all 300ms;}.ios-switch{position:absolute;right:0;top:0;z-index:99999;outline:none;}</style>
往<body>
裏插入<input>
<body> <input class="ios-switch" type="checkbox"> <div id="__nuxt">...</div> </body>
就這樣,一個純CSS的實現方案就能讓網站瞬間擁有暗黑模式
切換功能,有沒有又對CSS另眼相看了。
整個純CSS實現方案
圍繞着:checked
、+
和filter
三個點進行,缺一不可。看似簡單,若不是經常使用CSS作特效也很難想象出區區三個點打輔助也能完成一個這麼強大的功能。
<body> <input class="ios-switch" type="checkbox"> <div class="main">網站主體</div> </body>
.ios-switch { ... &:checked { ... & + .main { filter: invert(1) hue-rotate(180deg); img, video, .exclude { filter: invert(1) hue-rotate(180deg); } } } } .main { background-color: #fff; transition: all 300ms; }
相比於CSS+JS實現方案
而言,無需維護一整套暗黑模式
樣式代碼,無需操做DOM
,沒有了往常複雜的操做。除非要作一整套高度定製的暗黑模式
才需一個CSS+JS實現方案
,不然用該方案便可。
本方案具備如下特色。
試試無妨,完成了以爲效果不錯就趕忙找你老闆加薪去😜,哈哈!
對於筆者而言,CSS是一門天馬行空的語言,說它簡單也行說它困難也行。若你很喜歡CSS,想了解更多純CSS特效,可回看筆者往期的文章,也可瀏覽筆者我的官網的純CSS特效專輯,保證知足你的眼球。
4000+
點贊量,110k+
閱讀量500+
點贊量,13k+
閱讀量最後,筆者很好奇咱們最愛的掘金社區
會不會採納這種純CSS實現的換膚方案,各位掘友怎樣看呢?
❤️關注+點贊+收藏+評論+轉發❤️,原創不易,鼓勵筆者創做更多高質量文章
關注公衆號IQ前端
,一個專一於CSS/JS開發技巧的前端公衆號,更多前端小乾貨等着你喔
資料
免費領取學習資料進羣
拉你進技術交流羣IQ前端
,更多CSS/JS開發技巧只在公衆號推送