整合營銷服務商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          12個你未必知道的CSS小知識

          12個你未必知道的CSS小知識

          然CSS并不是一種很復雜的技術,但就算你是一個使用CSS多年的高手,仍然會有很多CSS用法/屬性/屬性值你從來沒使用過,甚至從來沒聽說過。

          1.CSS的color屬性并非只能用于文本顯示

          對于CSS的color屬性,相信所有Web開發(fā)人員都使用過。如果你并不是一個特別有經(jīng)驗的程序員,我相信你未必知道color屬性除了能用在文本顯示,還可以用作其它地方。

          你可以先看一下下面的演示:

          HTML代碼

          <img alt="Example alt text" ><ul>
          <li>Example list item</li></ul><ol>
          <li>Example list item</li></ol><hr>

          CSS代碼

          body {
          color: yellow;
          background: #444;
          font-size: 20px;
          font-family: Arial, sans-serif;
          text-align: center;}ul {
          border: solid 2px;
          text-align: left;}ol {
          text-align: left;}hr {
          border-color: inherit;}

          請注意,上面的代碼里只使用了一個color屬性,就是在body元素上,設置成了yellow。但是,你也看到了,所有這個頁面上的東西都變成了黃色,包括:

          • 無法顯示的圖片的alt文字

          • list元素的邊框

          • 無序list元素前面的小點

          • 有序list元素前面的數(shù)字

          • 還有hr元素

          有趣的是,這個hr元素,缺省情況下它并不從body上繼承color的屬性,但我使用border-color: inherit強制讓它繼承。這是個很詭異的特征。

          在CSS規(guī)范里是這樣說的:

          這個屬性聲明了元素文本內(nèi)容的前景色(foreground color)。除此之外,它的值還被用于其它地方間接的引用….比如,其它可以接受顏色值的屬性。

          我無法想象出還有什么地方的屬性能用“前景色”來描述,如果你知道,請在評論里告訴我。

          2.CSS里的visibility屬性有個collapse屬性值:collapse

          對于CSS里的visibility屬性,相信你用過不下幾百次。大多時候,你會把它的值設置成visible(這是所有頁面元素的缺省值),或者是hidden。后者相當于display: none,但仍然占用頁面空間。

          其實visibility可以有第三種值,就是collapse。當一個元素的visibility屬性被設置成collapse值后,對于一般的元素,它的表現(xiàn)跟hidden
          是一樣的。但例外的是,如果這個元素是table相關的元素,例如table行,table group,table列,table column group,它的表現(xiàn)卻跟display: none一樣,也就是說,它們占用的空間也會釋放。

          但遺憾的是,各種瀏覽器對collapse值的處理方式不一樣。看一下下面的演示:

          HTML代碼

          <table cellspacing="0" class="table">
          <tr>
          <th>Fruits</th>
          <th>Vegetables</th>
          <th>Rocks</th>
          </tr>
          <tr>
          <td>Apple</td>
          <td>Celery</td>
          <td>Granite</td>
          </tr>
          <tr>
          <td>Orange</td>
          <td>Cabbage</td>
          <td>Flint</td>
          </tr></table><p><button>collapse行1</button></p><p><button>hide行1</button></p><p><button>重置</button></p>

          CSS代碼

          body {
          text-align: center;
          padding-top: 20px;
          font-family: Arial, sans-serif;}table {
          border-collapse: separate;
          border-spacing: 5px;
          border: solid 1px black;
          width: 500px;
          margin: 0 auto;}th, td {
          text-align: center;
          border: solid 1px black;
          padding: 10px;}.vc {
          visibility: collapse;}.vh {
          visibility: hidden;}button {
          margin-top: 5px;}

          Javascript代碼

          var btns=document.getElementsByTagName('button'),
          rows=document.getElementsByTagName('tr');btns[0].addEventListener('click', function () {
          rows[1].className='vc';}, false);btns[1].addEventListener('click', function () {
          rows[1].className='vh';}, false);btns[2].addEventListener('click', function () {
          rows[1].className='';}, false);

          演示

          CSS-Tricks的Almanac建議說不要使用這個值,因為瀏覽器的不統(tǒng)一。

          據(jù)我的觀察:

          • 在谷歌瀏覽器里,使用collapse值和使用hidden值沒有什么區(qū)別。 (See this bug report and comments)

          • 在火狐瀏覽器、Opera和IE11里,使用collapse值的效果就如它的字面意思:table的行會消失,它的下面一行會補充它的位置。

          說實話,估計這個值很少人會使用它,但你要知道確實可以使用這樣的一個值,如果以前不知道它,那么,現(xiàn)在,在有些罕見的地方,你也許就會變得聰明一點了。

          3.CSS的background簡寫方式里新增了新的屬性值

          在CSS2.1里,background屬性的簡寫方式包含五種屬性值 – background-color, background-image, background-repeat, background-attachment, and background-position。從CSS3開始,又增加了3個新的屬性值,加起來一共8個。下面是按順序分別代表的意思:

          background: [background-color] [background-image] [background-repeat]
          [background-attachment] [background-position] / [ background-size]
          [background-origin] [background-clip];

          注意里面的反斜杠,它更font和border-radius里簡寫方式使用的反斜杠的用法相似。反斜杠可以在支持這種寫法的瀏覽器里在position后面接著寫background-size。除此之外,你開可以增加另外兩個描述它的屬性值: background-originbackground-clip

          .它的語法用起來像下面這個樣子:

          .example {
          background: aquamarine url(img.png)
          no-repeat
          scroll
          center center / 50%
          content-box content-box;}

          你可以用下面的演示檢測你的瀏覽器是否支持這種寫法:

          關于瀏覽器的支持情況,大概所有的現(xiàn)代瀏覽器都支持這些新屬性值,但對于一些非常老舊的瀏覽器(IE6/7/8),最好在代碼里提供一些萬一不支持的補救機制。

          4.CSS的clip屬性只在絕對定位的元素上才會生效

          之前說到了background-clip,你可能會想到clip
          屬性。它的用法是下面這個樣子:

          .example {
          clip: rect(110px, 160px, 170px, 60px);}

          它的作用是按指定的尺寸、規(guī)定的大小裁剪元素。很多簡單,但唯一你需要注意的事情是,clip只會在絕對定位的元素上生效。所有,你必須這樣做:

          .example {
          position: absolute;
          clip: rect(110px, 160px, 170px, 60px);}

          在下面的演示中,你可以看到當元素在絕對定位/相對定位的切換中表現(xiàn)出來的效果:

          但是,你也可以將元素的position設置成position: fixed,因為,根據(jù)css官方規(guī)范,fixed的元素也屬于‘a(chǎn)bsolutely positioned’元素。

          5.元素豎向的百分比設定是相對于容器的寬度,而不是高度

          這是一個很讓人困惑的CSS特征,我之前也談到過它。我們大家都知道,當按百分比設定一個元素的寬度時,它是相對于父容器的寬度計算的,但是,對于一些表示豎向距離的屬性,例如padding-top,padding-bottom,margin-top,margin-bottom等,當按百分比設定它們時,依據(jù)的也是父容器的寬度,而不是高度。

          下面是一個實例演示,你可以調(diào)整容器的寬度,但你會發(fā)現(xiàn),黃塊塊的padding-bottom的距離也會隨之寬度而變大或變小。

          HTML代碼

          <div class="wrapper" id="w">
          <div class="box" id="b"></div></div><input type="range" min="120" max="400" value="400" class="range" id="r"><output>寬度是: <span id="op">400px</span></output><output>黃塊塊的Padding bottom是:<br><span id="op2">10%</span></output>

          CSS代碼

          body {
          font-family: Arial, sans-serif;
          padding-top: 30px;
          text-align: center;}.wrapper {
          width: 400px;
          margin: 0 auto;
          border: solid 1px black;}.box {
          width: 100px;
          height: 100px;
          background: gold;
          margin-left: auto;
          margin-right: auto;
          padding-top: 10%;
          padding-bottom: 10%;
          margin-bottom: 5%;}.range {
          display: block;
          margin: 20px auto;}output {
          text-align: center;
          display: block;
          font-weight: bold;
          padding-bottom: 20px;}output span {
          font-weight: normal;}

          實例演示

          上面的代碼中,我們對內(nèi)部子元素聲明了3個豎向的距離,都是百分比形式。當移動滑塊時,我們的js代碼只需修改了容器的寬度。但是,這個這三個屬性高度都跟隨著變化,可以看出,它們的百分比計算是基于容器的寬度,而不是高度的。

          6.border屬性比你想象的要復雜

          我們很多人都用過這樣的寫法:

          .example {
          border: solid 1px black;}

          這里的border屬性的用法實際上是一種簡寫的形式,它分別設置了border-style, border-width, 和border-color — 用一句代碼表示它們?nèi)齻€。

          但不要忘記,border-style, border-width, 和border-color也都有自己的簡寫形式。所以,border-width可以寫成這樣:

          .example {
          border-width: 2px 5px 1px 0;}

          這樣,四個邊的寬度被一次設定。border-colorborder-style 屬性也可以這樣做。下面的這個實例演示就是用的這種寫法:

          HTML代碼

          <div class="box">

          CSS代碼

          body {
          font-family: Arial, sans-serif;}.box {
          width: 150px;
          height: 150px;
          margin: 20px auto;
          border-color: peachpuff chartreuse thistle firebrick;
          border-style: solid dashed dotted double;
          border-width: 10px 3px 1px 8px;}p {
          text-align: center;}

          演示

          其實,這些每個屬性還可以繼續(xù)細化,被拆分成border-left-style, border-top-width, border-bottom-color….

          但是,你無法用border的簡寫分別對四個邊設置不同的值,只能分開來設置。所以,border是一個簡寫里還有簡寫的屬性。

          7.text-decoration屬性變成了屬性簡寫

          我相信有些小知識會讓你大吃一驚。

          跟著最新的CSS規(guī)范,text-decoration現(xiàn)在的寫法是這樣的:

          a {
          text-decoration: overline aqua wavy;}

          text-decoration屬性現(xiàn)在需要用三種屬性值來表示了:text-decoration-line, text-decoration-color, and text-decoration-style.

          但不幸的是,目前只有火狐瀏覽器實現(xiàn)了對這些新屬性的支持。

          你可以用火狐瀏覽器試一試下面的演示:

          HTML代碼

          <a href="#" id="a">IT'S LIKE WATER, PEOPLE

          (You should see a wavy line on top. Currently works only in Firefox)

          CSS代碼

          body {
          padding: 30px;
          text-align: center;
          font-family: Arial, sans-serif;}a, a:visited {
          color: blue;
          background: aqua;
          -moz-text-decoration-color: aqua;
          -moz-text-decoration-line: overline;
          -moz-text-decoration-style: wavy;
          text-decoration-color: aqua;
          text-decoration-line: overline;
          text-decoration-style: wavy;}

          演示

          在這演示中,我們沒有使用簡寫形式,而是分開描述每個屬性。這是可以更好的保證瀏覽器的向后兼容,使那些目前不支持這種寫法的瀏覽器也不受影響。

          8.border-width屬性可以使用預定義常量值

          也許對與你來說這并不是一個什么新鮮信息。除了可以使用標準寬度值(例如5px或1em)外,border-width屬性可以接受預定義的常量值:medium, thin, 和 thick

          事實上,如果你不給border-width屬性賦值,那它的缺省值是“medium”。下面的演示就是用了預定義常量值:

          HTML代碼

          <div class="example">

          CSS代碼

          body {
          font-family: Arial, sans-serif;
          text-align: center;}.example {
          width: 100px;
          height: 100px;
          margin: 20px auto;
          background: aqua;
          border: solid thick red;}

          演示

          在瀏覽器使用這些預定義常量值時,CSS規(guī)范里并沒有規(guī)定都應該是什么寬度,但從我的觀察看,它們的值分別是 1px, 3px, 和 5px.

          9.為什么沒有人使用border-image

          之前我曾經(jīng)寫過一篇關于CSS的border-image屬性的文章。現(xiàn)在幾乎所有的現(xiàn)代瀏覽器都支持這個屬性——除了IE10及以下IE版本。

          看起來這是一個非常漂亮的CSS功能,它可以讓你用圖片修飾元素的邊框。下面是一個實例演示,你可以拖拽調(diào)整里面的方塊的大小,看看有什么邊框圖案的變化。

          HTML代碼

          <div class="bi"><p><上面的方塊使用了圖片描邊。在這個方塊的右下角,有一個可以調(diào)整這個方塊大小的小三角,點住它,拖動它調(diào)整方塊大小,看看有什么效果。.</strong></p><p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p></div>

          CSS代碼

          body {
          font-family: Arial, sans-serif;
          text-align: center;}.bi {
          border: 45px solid transparent;
          -webkit-border-image: url(http://www.webhek.com/wordpress/wp-content/uploads/2014/07/bg-pawprints-all.jpg) 45 round;
          -moz-border-image: url(http://www.webhek.com/wordpress/wp-content/uploads/2014/07/bg-pawprints-all.jpg) 45 round;
          border-image: url(http://www.webhek.com/wordpress/wp-content/uploads/2014/07/bg-pawprints-all.jpg) 45 round;
          font-family: Arial, Helvetica, sans-serif;
          color: #222;
          width: 500px;
          margin: 30px auto 30px auto;
          overflow: hidden;
          resize: both;}

          演示

          但不幸的是,這么好的一個功能,卻沒有看到多少人使用它,也許是我的眼界太窄。如果你在哪看到過有人使用border-image屬性,或你在真正項目中使用了它,請留言告訴我。

          10.你知道table里的empty-cells屬性嗎?

          css里的empty-cells屬性是所有瀏覽器都支持的,甚至包括IE8,它的用法是下面這個樣子:

          table {
          empty-cells: hide;}

          估計你從語義上已經(jīng)猜出它的作用了。它是為HTML table服務的。它會告訴瀏覽器,當一個table單元格里沒有東西時,就隱藏它。下面的演示里,你可以點擊里面按鈕,它會切換empty-cells的屬性值,看看table的顯示有什么變化。

          HTML代碼

          <table cellspacing="0" id="table">
          <tr>
          <th>Fruits</th>
          <th>Vegetables</th>
          <th>Rocks</th>
          </tr>
          <tr>
          <td></td>
          <td>Celery</td>
          <td>Granite</td>
          </tr>
          <tr>
          <td>Orange</td>
          <td></td>
          <td>Flint</td>
          </tr></table>
          <button id="b" data-ec="hide">切換EMPTY-CELLS</button>

          CSS代碼

          body {
          text-align: center;
          padding-top: 20px;
          font-family: Arial, sans-serif;}table {
          border: solid 1px black;
          border-collapse: separate;
          border-spacing: 5px;
          width: 500px;
          margin: 0 auto;
          empty-cells: hide;
          background: lightblue;}th, td {
          text-align: center;
          border: solid 1px black;
          padding: 10px;}button {
          margin-top: 20px;}

          js代碼

          var b=document.getElementById('b'),
          t=document.getElementById('table');b.onclick=function () {
          if (this.getAttribute('data-ec')==='hide') {
          t.style.emptyCells='show';
          this.setAttribute('data-ec', 'show');
          } else {
          t.style.emptyCells='hide';
          this.setAttribute('data-ec', 'hide');
          }};

          演示

          在上面的演示中,我為能讓單元格的邊框顯示出來,在單元格的邊框間添加了空隙。有時候這個屬性不會有任何視覺效果,因為你必須讓你里面有可見的東西。

          11.font-style的oblique屬性值

          對與css的font-style屬性,我估計大家每次見到的都是使用“normal”或 “italic”兩個屬性值。但事實上,你還可以讓它賦值為“oblique”。請看下面的演示:

          HTML代碼

          <h1>Oblique Text</h1><h1>Italic Text</h1>

          CSS代碼

          h1 {
          font-weight: normal;
          font-family: Georgia, serif;
          font-style: oblique;
          text-align: center;
          font-size: 50px;}h1:nth-child(2) {
          font-style: italic;}p {
          font-family: Arial, sans-serif;
          text-align: center;}

          演示

          這是什么意思?為什么“oblique”和斜體”italic”的效果是一樣的?

          CSS規(guī)范中是這樣描述“oblique”的:

          “…讓一種字體標識為斜體(oblique),如果沒有這種格式,就使用italic字體。”

          這里描述所用的“oblique”和“italic”都是傾斜的意思。“oblique”在維基百科里的解釋就是一種排版術語,就是一種傾斜的文字,但不是斜體。

          因為“oblique”對于font-style來說是一種合法的屬性值,它可和italic進行互換,除非真有一種字體只提供了oblique體而沒有提供斜體。

          但我似乎從來沒有聽說過哪種字形提供過oblique字體,也許我錯了。研究發(fā)現(xiàn),一種字庫好像不能同時提供斜體和oblique兩種字體,因為oblique基本上是一種模仿的斜體,而不是真正的斜體。

          所以,如果我沒有猜錯的話,如果一種字庫里沒有提供斜體字,那當使用CSS的font-style: italic時,瀏覽器實際上是按font-style: oblique顯示的。

          12.word-wrap和overflow-wrap是等效的

          word-wrap并不是一個很常用的CSS屬性,但在特定的環(huán)境中確實非常有用的。我們經(jīng)常使用的一個例子是讓頁面中顯示一個長url時換行,而不是撐破頁面,下面是一個例子。

          HTML代碼

          <p class="p" id="p">supercalifragilisticexpialidocious</p><button id="b" data-ww="break-word">TOGGLE word-wrap</button>

          CSS代碼

          body {
          font-family: Arial, sans-serif;
          text-align: center;}.p {
          font-size: 24px;
          text-align: center;
          width: 200px;
          margin: 20px auto;
          border: solid 1px black;
          min-height: 60px;
          word-wrap: break-word;}button {
          display: block;
          margin: 0 auto;}

          JS代碼

          var p=document.getElementById('p'),
          b=document.getElementById('b');b.onclick=function () {
          if (this.getAttribute('data-ww')==='break-word') {
          p.style.wordWrap='normal';
          this.setAttribute('data-ww', 'normal');
          } else {
          p.style.wordWrap='break-word';
          this.setAttribute('data-ww', 'break-word');
          }};

          演示

          因為這個屬性最初是由微軟發(fā)明的,所以,所有的瀏覽器都支持這個屬性。

          盡管有所有的瀏覽器都支持,但W3C決定要用overflow-wrap替換word-wrap,我想可能是他們認為word-wrap用詞不當。overflow-wrapword-wrap具有相同的屬性值,但現(xiàn)在,word-wrap被當作overflow-wrap的備選寫法。

          雖然已經(jīng)有不少的瀏覽器支持overflow-wrap這種寫法,但看起來沒必要使用overflow-wrap來讓老的瀏覽器不支持。所有的瀏覽器都會繼續(xù)支持word-wrap這種寫法。

          這其中有多少是以前不知道的?

          文簡介

          帶尬猴!

          你是否在使用 Fabric.js 時希望能在選中元素后自定義元素樣式或選框(控制角和輔助線)的樣式?

          如果是的話,可以放心往下讀。

          本文將手把腳和你一起過一遍 Fabric.js 在對象元素選中后常用的樣式設置。

          我將對象元素選中后的設置分成3類進行講解:

          • 控制角
          • 輔助邊
          • 其他樣式
          • 狀態(tài)



          準備工作

          創(chuàng)建一個畫布和一個圓形。為什么是圓形而不是矩形?等下你就知道了。

          <canvas id="c" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const canvas=new fabric.Canvas('c', {
              width: 400,
              height: 400,
            })
          
            let circle=new fabric.Circle({
              top: 80,
              left: 80,
              radius: 50,
              fill: '#ffde7d' // 淡黃色
            })
          
            canvas.add(circle)
          </script>
          

          一個蛋黃出現(xiàn)了。上面這段代碼是 Fabric.js 的基礎。如果不太了解或者忘記語法了,可以查看 《Fabric.js 從入門到膨脹》。

          我最近也在整理 Fabric.js 的常用方法,有興趣的可以看看 《Fabric.js中文教程》



          約定

          本文所說的控制角和輔助邊請看下圖。翻譯能力有限,將就理解下吧~


          控制角

          控制角就是選中元素后周邊出現(xiàn)的幾個方形。


          實心控制角

          默認情況下,控制角是空心的。也就是只有邊框,沒有填充色。

          如果想要做成實心的控制角,只需將元素的 transparentCorners 屬性設置為 true 即可。

          // 省略部分代碼
          let circle=new fabric.Circle({
            transparentCorners: false,
            // 其他配置...
          })
          


          控制角顏色

          元素的 cornerColor 屬性可以控制控制角的顏色。

          // 省略部分代碼
          let circle=new fabric.Circle({
            transparentCorners: false,
            cornerColor: 'pink',
            // 其他配置...
          })
          

          此時控制角的邊框顏色和填充顏色都變成了粉紅色。


          控制角邊框顏色

          如果你想單獨設置控制角的邊框顏色也行!要設置的屬性叫 cornerStrokeColor。

          // 省略部分代碼
          let circle=new fabric.Circle({
            transparentCorners: false,
            cornerColor: 'pink',
            cornerStrokeColor: 'blue',
            // 其他配置...
          })
          


          控制角大小

          想修改控制角的大小,可以修改 cornerSize 的值。

          // 省略部分代碼
          let circle=new fabric.Circle({
            cornerSize: 30,
            // 其他配置...
          })
          

          和前面的例子對比,將 cornerSize 設置成 30 之后,控制角明顯大了很多。


          控制角邊框虛線規(guī)則

          控制角那幾個小把手的邊框是可以設置成虛線的。要調(diào)整的參數(shù)是 cornerDashArray ,該參數(shù)的值是一個數(shù)值型數(shù)組。

          虛線的規(guī)則主要分以下幾種情況:

          • 數(shù)組只有1個元素:虛線和實現(xiàn)的長度相等。
          • 數(shù)組有2個元素:第一個元素是實線長度,第二個元素是虛線長度。
          • 數(shù)組有3個或3個以上的元素:實線、虛線、實線、虛線…… 一直輪回下去。

          為了方便演示,我先將控制角的尺寸設置得大一點。

          情況1:數(shù)組只有1個元素

          // 省略部分代碼
          let circle=new fabric.Circle({
            cornerSize: 30,
            cornerDashArray: [4],
            // 其他配置...
          })
          

          情況2:數(shù)組有2個元素

          // 省略部分代碼
          let circle=new fabric.Circle({
            cornerSize: 30,
            cornerDashArray: [4, 10],
            // 其他配置...
          })
          

          情況3:數(shù)組有3個或3個以上的元素

          // 省略部分代碼
          let circle=new fabric.Circle({
            cornerSize: 30,
            cornerDashArray: [4, 10, 20],
            // 其他配置...
          })
          


          控制角形狀

          控制角除了是正方形外,還可以將它設置成圓形。只需將 cornerStyle 設置為 circle 即可。

          // 省略部分代碼
          let circle=new fabric.Circle({
            cornerStyle: 'circle',
            // 其他配置...
          })
          


          輔助邊

          前面說完控制角,接下來講講輔助邊


          輔助邊顏色

          我們可以通過 selectionBackgroundColor 屬性設置輔助邊的顏色。

          // 省略部分代碼
          let circle=new fabric.Circle({
            borderColor: 'red',
            // 其他配置...
          })
          


          輔助邊粗細

          設置輔助邊粗細的屬性名叫 borderScaleFactor。

          // 省略部分代碼
          let circle=new fabric.Circle({
            borderScaleFactor: 4,
            // 其他配置...
          })
          


          輔助邊虛線規(guī)則

          設置輔助邊虛線規(guī)則使用的屬性是 borderDashArray。使用規(guī)則和 cornerDashArray 是一樣的。

          // 省略部分代碼
          let circle=new fabric.Circle({
            borderDashArray: [10, 20, 30],
            // 其他配置...
          })
          


          其他樣式

          內(nèi)邊距

          設置內(nèi)邊距的屬性是 padding,這名字和 css 的內(nèi)邊距是一樣的。

          在 Fabric.js 中,給元素設置了內(nèi)邊距,會影響控制角和輔助邊到元素邊緣的距離。

          padding 接受一個數(shù)值,不需要傳入單位。

          // 省略部分代碼
          let circle=new fabric.Circle({
            padding: 20,
            // 其他配置...
          })
          

          和前面的例子對比一下,將 padding 設置為 20 后,輔助邊和元素之間的距離明顯增大了。


          背景色

          這里所說的背景色和 css 里面的背景色不是同一回事。

          本文要介紹 Fabric.js 的背景色有2種。一種是元素自身的背景色,另一種是選中后的背景色。

          在 Fabric.js 里,背景色和填充色是兩回事。

          • 填充色:fill
          • 背景色:backgroundColor
          • 選中后的背景色:selectionBackgroundColor

          填充色是基礎,忘了的話可以查看 《Fabric.js 從入門到膨脹》 ,本文不再講解。

          Fabric.js 是以矩形的方式去計算元素占位面積的,這也很好理解,比較方便嘛。所以使用 backgroundColor 設置背景顏色就能看到元素占據(jù)多大面積了。

          // 省略部分代碼
          let circle=new fabric.Circle({
            fill: '#ffde7d',
            backgroundColor: '#f6416c',
            // 其他配置...
          })
          


          而 selectionBackgroundColor 屬性是設置元素選中后的背景色。

          但需要注意,如果你同時設置了 backgroundColor 和 selectionBackgroundColor,重疊的部分 backgroundColor 的優(yōu)先級更高。

          那什么地方才是不重疊的地方呢?那就是設置了 padding 的地方。

          // 省略部分代碼
          let circle=new fabric.Circle({
            fill: '#ffde7d',
            backgroundColor: '#f6416c',
            padding: 20,
            selectionBackgroundColor: '#00b8a9',
            // 其他配置...
          })
          


          移動元素時的透明度

          元素移動時會先進入選中狀態(tài)。此時會產(chǎn)生控制角和輔助線。

          你可以使用 borderOpacityWhenMoving 設置控制角和輔助線的透明度。這個屬性接受 0 ~ 1 的值。

          0 表示完全透明,1 表示完全不透明。

          注意,borderOpacityWhenMoving 設置的是『移動時』控制角和輔助邊的透明度。 重點詞是 『移動時』

          // 省略部分代碼
          let circle=new fabric.Circle({
            borderOpacityWhenMoving: 0.1,
            // 其他配置...
          })
          

          本例將 borderOpacityWhenMoving 設置為 0.1 ,所以移動時就只能隱隱約約看到控制角和輔助邊了。


          狀態(tài)

          我把能否選中、局部控制操作等內(nèi)容放在“狀態(tài)”章節(jié)里。


          禁止選中

          如果你不希望元素被選中,可以將元素的 selectable 屬性設置為 false。

          // 省略部分代碼
          let circle=new fabric.Circle({
            borderOpacityWhenMoving: 0.1,
            // 其他配置...
          })
          


          無法通過空白區(qū)域操作元素

          如果圖形不是矩形,在選中元素后,輔助邊和圖形之間會有一個空白區(qū)。也就是前面用 backgroundColor 填充的那部分。

          箭頭所指的4個地方都是空白區(qū)域。

          默認情況下,你可以點擊空白區(qū)選中或者拖拽圖形。

          但如果你希望只能點擊圖形區(qū)域才能選中圖形的話,可以將圖形的 perPixelTargetFind 屬性設置為 true。

          // 省略部分代碼
          let circle=new fabric.Circle({
            perPixelTargetFind: true,
            // 其他配置...
          })
          


          隱藏控制角

          可以通過 hasControls 屬性設置控制角的顯示和隱藏。

          如果將 hasControls 設置為 false ,就會將控制角隱藏起來,你也就無法通過控制角去縮放和旋轉(zhuǎn)元素了。

          // 省略部分代碼
          let circle=new fabric.Circle({
            hasControls: false,
            // 其他配置...
          })
          


          隱藏輔助邊

          同樣你也可以將輔助邊隱藏起來,只需將 hasBorders 屬性設置為 false 即可。

          // 省略部分代碼
          let circle=new fabric.Circle({
            hasBorders: false,
            // 其他配置...
          })
          


          設置控制角的可見性

          前面將 hasControls 屬性設置為 false 后就可以隱藏所有控制角。

          其實 Fabric.js 還提供了2個方法可以單獨設置指定控制角的可見性:

          • setControlsVisibility(optionsopt):批量設置控制角可見性
          • setControlVisible(controlKey, visible):單獨設置控制角可見性

          這兩個方法的作用是一樣的,只是使用方式上有點不同。

          需要注意的是,一旦把控制角隱藏起來,就意味著不能通過被隱藏的控制角去縮放和旋轉(zhuǎn)元素了


          在使用者兩個方法之前,你需要了解一堆屬性:tl, tr, br, bl, ml, mt, mr, mb, mtr,它們分別對應9個控制點,如下圖所示。


          setControlsVisibility(optionsopt)

          setControlsVisibility() 方法接收一個對象參數(shù),在這對象中可以描述要顯示或者隱藏哪些控制角。

          比如我想把左上角和右下角隱藏。

          // 省略部分代碼
          let circle=new fabric.Circle({
            // 其他配置...
          })
          
          circle.setControlsVisibility({
            tl: false,
            br: false
          })
          


          setControlVisible(controlKey, visible)

          setControlVisible() 方法一次只能設置1個控制角的可見性,它接收2個參數(shù)。第一個參數(shù)是要操作的控制角,第二個參數(shù)是控制角的顯示狀態(tài)。

          比如我想將左下角的控制角隱藏起來。

          // 省略部分代碼
          let circle=new fabric.Circle({
            // 其他配置...
          })
          
          circle.setControlsVisibility('bl', false)
          


          返回控制角的可見性

          可以使用 isControlVisible(controlKey) 方法獲取控制角當前的可見性。

          // 省略部分代碼
          let circle=new fabric.Circle({
            // 其他配置...
          })
          
          circle.setControlsVisibility('bl', false)
          
          console.log(circle.isControlVisible('bl')) // 返回 false
          console.log(circle.isControlVisible('br')) // 返回 true
          


          獲取當前被選中的對象

          Fabric.js 還提供了2個方法可以捕捉到當前被選中的對象。這2個方法分別叫 getActiveObject() 和 getActiveObjects() 。需要在 canvas 對象中調(diào)用的。


          getActiveObject() 和 getActiveObjects() 從名字來看就已經(jīng)知道,末尾沒加 s 的就是返回當前選中的元素;末尾加了 s 的就是返回當前選中的所有元素(比如通過框選操作選擇了一堆元素)。

          選中元素時,getActiveObject() 會返回的當前元素對象,而 getActiveObjects() 則返回一個數(shù)組集合。

          沒選中元素時,getActiveObject() 會返回 null,而 getActiveObjects() 會返回一個空數(shù)組。


          可以通過這兩個方法獲取當前選中的對象再做其他操作(比如修改填充顏色、描邊顏色、描邊粗細等)。


          代碼倉庫

          ? Fabric.js 元素選中狀態(tài)的事件與樣式



          推薦閱讀

          我最近在整理 Fabric.js 常用方法,有興趣的可以看看 《Fabric.js中文教程》


          《Fabric.js 拖放元素進畫布》

          《Fabric.js 限制邊框?qū)挾瓤s放》

          《Fabric.js 監(jiān)聽元素相交(重疊)》

          《Fabric.js 橡皮擦的用法(包含恢復功能)》

          《Fabric.js 噴霧筆刷 從入門到放肆》

          《Fabric.js 設置容器類名要注意這幾點》


          點贊 + 關注 + 收藏=學會了

          者|廖偉華(大貘)

          出品|阿里巴巴新零售淘系技術部

          導讀:給網(wǎng)站添加暗黑模式是隨著macOS中的暗黑模式(Dark Mode)出現(xiàn)之后的一個熱門話題。社區(qū)中有關于這方面的討論也很多,都在圍繞著怎么給網(wǎng)站添加暗黑模式。今天在這篇文章再次和大家一起聊聊這個已久的話題,不同的是,這篇文章將和大家從不同的角度來聊怎么給網(wǎng)站添加暗黑模式。感興趣的同學,請繼續(xù)往下閱讀。


          暗黑模式是系統(tǒng)級別的



          所謂的暗黑模式并不是現(xiàn)在才有的,這個事實已經(jīng)存在很久了。如果你很早就接觸過電腦的話,你可能會發(fā)現(xiàn)你使用過的電腦屏幕經(jīng)歷過好幾個過程,看起來會像下面這樣:



          是不是覺得既熟悉又陌生。既然如此,為什么今年會成為設計或者說Web端的一個熱點呢?

          其實這一切都應該歸功于Apple公司,在macOS系統(tǒng)中提出了dark和light兩種視覺模式,即暗色(dark)高亮(light)兩種皮膚,而且這兩種皮膚是系統(tǒng)級別的,我們可以通過系統(tǒng)上的切換,讓整個電腦上只要支持dark/light模式的應用都可以輕易切換。


          那么為什么要從系統(tǒng)級別去做這個事情呢?這是有原因的。系統(tǒng)面對的用戶群體中朋部分人士在身體上存有一定的缺陷,比如說色盲的用戶群體。也就是說,這種暗黑模式或者高亮模式對于有色盲的用戶群體是非常友好的。既然如此,為了讓自己的Web網(wǎng)站或者Web應用能向系統(tǒng)級別靠齊,就有了網(wǎng)站級別的暗黑模式。

          你可能在很多網(wǎng)站的右上角看到了一個提供暗黑和高亮模式的切換按鈕。


          暗黑模式實現(xiàn)原理



          給Web網(wǎng)站或者Web應用添加暗黑模式的基本原理我想大家應該很清楚,事實上也非常的簡單。

          正如上圖所示,給同一個Web網(wǎng)站或Web應用提供多套皮膚,用戶根據(jù)自己的喜歡進行選擇。那么給網(wǎng)站添加暗黑模式是同一個原理,就是給網(wǎng)站同時提供兩套皮膚,即theme1.css和theme2.css。

          早期我們可能會借助于JavaScript腳本,根據(jù)用戶的選擇在一個<link />標簽上進行兩個主題文件(即.css文件)切換來實現(xiàn):


          <!-- HTML -->
          <link type="text/css" rel="stylesheet" media="all" href="../theme1.css" id="theme_css" />
          
          // Script
          document.getElementById('buttonID').addEventListener('click', function(){                    document.getElementById('theme_css').href='../theme2.css'; 
          })


          這可能是一種比較古老的實現(xiàn)方案。也是大家最為熟悉的方案。


          CSS實現(xiàn)暗黑模式切換


          時至今日,給Web網(wǎng)站或Web應用程序?qū)崿F(xiàn)暗黑模式已有多種模式。可以是純CSS的方式,也可以是CSS和JavaScript結(jié)合的模式。那么接下來,我們來看看具體的實現(xiàn)方式。

          ? 媒體查詢prefers-color-scheme

          CSS有一個特別強大的特性,那就是媒體查詢@media,CSS的@media規(guī)則可以用于有條件地將樣式應用于文檔以及其他各種上下文和語言,如HTML和JavaScript。在W3C的Media Queries Level 5【1】引入了“用戶首選媒體特性”,即Web網(wǎng)站或應用程序檢測用戶顯示內(nèi)容的首先方式的方法。(https://drafts.csswg.org/mediaqueries-5/)

          比如prefers-reduced-motion這個媒體查詢就可以檢測頁面上的動畫,假設設備開啟了“Reduce motion”選項,就可以通過該媒體查詢選項讓頁面上的元素是否具有動效:

          如果用戶開啟減少動效的喜好,那么就不要在元素上使用動效:


          @media (prefers-reduced-motion: no-preference) {    button {        animation: vibrate 0.3s linear infinite both;    }}

          如果用戶沒有在系統(tǒng)級別設置該選項的話,可以像下面這樣讓按鈕有動效:

          @media (prefers-reduced-motion: no-preference) {
              button {
                  animation: vibrate 0.3s linear infinite both;
              }
          }


          Web上的其他具有動效的元素都可以像上面之樣使用, 上面只是用button為例。

          如果Web網(wǎng)站有很多元素具有動效的話,還可以將所有與動效相關的CSS放在一個獨立的文件中,然后通過link的media屬性來加載:

          <link rel="stylesheet" href="animations.css" media="(prefers-reduced-motion: no-preference)" />

          為了說明JavaScript如何控制preferences-reduced-motion。這里假設你在項目中使用了 Web Animation API【2】。當用戶開啟了偏好設置,CSS規(guī)則會被瀏覽器動態(tài)觸發(fā),這樣一來我五一需要自己監(jiān)聽變化,然后手動停止與動畫相關的東西:(https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API)

          const mediaQuery=window.matchMedia('(prefers-reduced-motion: reduce)');
          mediaQuery.addEventListener('change', ()=> {
              console.log(mediaQuery.media, mediaQuery.matches);
              // ...
          });


          如果你有強迫癥,強迫減少網(wǎng)站上所有有動效停下來,還可以像下面這樣的簡單粗暴的操作:

          @media (prefers-reduced-motion: reduce) {
              *,
              *::before,
              *::after {
                  animation-duration: 0.001s !important;
                  transition-duration: 0.001s !important;
              }
          }


          有關于prefers-reduced-motion更詳細的介紹可以閱讀@Thomas Steiner的博文《 Move Ya! Or maybe, don't, if the user prefers-reduced-motion!》【3】。(https://developers.google.com/web/updates/2019/03/prefers-reduced-motion)

          似乎上面的內(nèi)容偏離了我們今天要聊的主題,大家不用著急。只不過是拿prefers-reduced-motion這個媒體查詢來拋磚引玉而以。在CSS中通過媒體查詢的prefers-color-scheme特性和prefers-reduced-motion類似,不同是,該特性是用于檢測用戶是否要求頁面使用light還是dark主題。該媒體查詢常見的值有:

          • no-preference:表示用戶未指定操作系統(tǒng)主題。其作為 布爾值 時以false輸出
          • light:表示用戶的操作系統(tǒng)是淺色主題(light)
          • dark:表示用戶的操作系統(tǒng)是深色主題(dark)

          也就是說,通過prefers-color-scheme媒體查詢要讓暗黑模式(dark)開啟深色系主題,可以像下面這樣使用:

          @media (prefers-color-scheme: dark) {
              :root {
                  --background-color: #111416
                  --text-color: #ccc;
                  --link-color: #f96;
              }
          }


          當然在非dark模式下,你的樣式可能像下面這樣:

          :root {
              --background-color: #fff;
              --text-color: #333;
              --link-color: #b52;
          }
          
          body {
              background-color: var(--background-color);
              color: var(--text-color);
          }
          
          a {
              color: var(--link-color);
          }


          注意上面提供的示例代碼僅僅是最基本的顏色配置方案,但也可以說完成了近90%的工作。但細節(jié)決定成敗。如果要讓你的Web網(wǎng)站或應用程序在light和dark模式切換下能有較好的效果,還需要注意其他的一些細節(jié),比如說img、svg等元素的細節(jié)處理。有關于細節(jié)方面的,稍后我們會再討論,暫且不表。

          正如上面的示例所示,我們是通過CSS的媒體查詢特性來檢測dark模式,即通過檢查媒體查詢是否首選。那么顏色方案是否匹配還需要檢查當前瀏覽器是否支持dark模式。

          我們可以像下面這樣來檢測瀏覽器是否支持dark模式:

          if (window.matchMedia('(prefers-color-scheme)').media !=='not all') {
              console.log('瀏覽器支持dark模式!(^_^)');
          }


          至于哪些瀏覽已支持prefers-color-scheme特性,我們可以通過Caniuse來查詢【4】:(https://caniuse.com/prefers-color-scheme/embed)

          前面的示例簡單的向大家演示了如何給Web網(wǎng)站或應用程序設置暗黑模式。但有很多細節(jié)我們需要去注意。

          在一個應用中只dark(暗色系)和light(亮色系)只能是二選一,永遠不可能兩者共存。為什么要提這個呢?我們從加載策略來做衡量。如果我們不管三七二十一,直接將所有樣式(普通樣式、亮色系樣式和暗色系樣式)都用一個.css文件加載的話會強迫用戶在關鍵的渲染路徑中下載CSS(包括你不想要的模式代碼也加載進來了)。為此,為了優(yōu)化加載速度和給用戶提供更好的體驗,我們可以將CSS分成三個部分,以延遲非關鍵的CSS:

          • style.css:網(wǎng)站上普通樣式(通用樣式)
          • dark.css:暗色系所需樣式規(guī)則
          • light.css:亮色系所需樣式規(guī)則

          其中dark.css和light.css可以通過<link media="" />有條件的加載。加上并不是所有瀏覽器都已支持prefers-color-scheme特性,所以我們在加載通用樣式style.css規(guī)則的基礎上動態(tài)默認加載light.css。即,不支持該特性的瀏覽器會按下面的順序加載CSS:style.css ? light.css ? dark.css;如果支持該特性的瀏覽器則會按下面的順序加載CSS:style.css ? dark.css ? light.css。具體的代碼如下:

          <!-- Script --><script>    if (window.matchMedia('(prefers-color-scheme: dark)').media==='not all') {        document.documentElement.style.display='none';        document.head.insertAdjacentHTML(            'beforeend',            '<link rel="stylesheet" href="/light.css" onload="document.documentElement.style.display=\'\'">'        );    }</script><!-- HTML --><link rel="stylesheet" href="/style.css"><link rel="stylesheet" href="/dark.css" media="(prefers-color-scheme: dark)"><link rel="stylesheet" href="/light.css" media="(prefers-color-scheme: no-preference), (prefers-color-scheme: light)">


          按照該規(guī)則,前面的CSS示例代碼,我們就可以按下面這樣的文件來劃分:

          // dark.css
          :root {
              --background-color: #111416
              --text-color: #ccc;
              --link-color: #f96;
          }
          
          // light.css
          :root {
              --background-color: #fff;
              --text-color: #333;
              --link-color: #b52;
          }
          
          // style.css
          body {
              background-color: var(--background-color);
              color: var(--text-color);
          }
          
          a {
              color: var(--link-color);
          }

          這里使用了CSS自定義屬性,該示例再次向大家演示了CSS自定義屬性的強大之處。

          ? CSS的新特性color-scheme

          CSS Color Adjustment Module Level 1【5】提供了另一個新屬性color-scheme。該特性會告訴瀏覽器該應用的顏色主題和允許用戶代理的特殊變體樣式表,而且它還可以讓Web中的部分區(qū)域的渲染在dark和light之間切換,比如讓瀏覽器渲染渲染的表單域是個黑色背景和高亮文本。(https://drafts.csswg.org/css-color-adjust-1/)

          來看一個簡單的示例代碼:

          /* dark.css */
          :root {
              --color: rgb(250, 250, 250);
              --background-color: rgb(5, 5, 5);
              --link-color: rgb(0, 188, 212);
              --main-headline-color: rgb(233, 30, 99);
              --accent-background-color: rgb(0, 188, 212);
              --accent-color: rgb(5, 5, 5);
          }
          
          /* light.css */
          :root {
              --color: rgb(5, 5, 5);
              --background-color: rgb(250, 250, 250);
              --link-color: rgb(0, 0, 238);
              --main-headline-color: rgb(0, 0, 192);
              --accent-background-color: rgb(0, 0, 238);
              --accent-color: rgb(250, 250, 250);
          }
          
          /* style.css */
          :root {
              color-scheme: light dark;
          }
          
          body {
              color: var(--color);
              background-color: var(--background-color);
          }


          同樣的,還可以HTML的meta標簽來設置:

          <meta name="supported-color-schemes" content="light dark">

          到目前為止,支持 color-scheme 的瀏覽器還較少【6】:(https://caniuse.com/#feat=mdn-html_elements_meta_name_color-scheme)

          俗話說,百聞不如一見,這里向大家展示一個由@Thomas Steiner提供的案例【7】:(https://twitter.com/tomayac)

          上面這個案例和以往提供的案例有所不同。該案例按前面所講的分成三個獨立的樣式文件:style.css、dark.css和light.css。嘗試切換暗黑模式并重新加載頁面,你會發(fā)現(xiàn)不匹配的樣式文件仍然會被加載,只是優(yōu)先級有所差異,這樣做它們就不會與站點當前所需的資源競爭。

          當網(wǎng)站是在light模式下,樣式文件加載優(yōu)先級是style.css ? light.css ? dark.css,即 dark.css 權重最低(Lowest):

          當網(wǎng)站在dark模式下,樣式文件加載優(yōu)先級是style.css ? dark.css ? light.css,即 light.css權重最低(Lowest):

          當瀏覽器不支持prefers-color-scheme而且設置light為默認模式,那么樣式加載優(yōu)先級會和高亮模式一樣:

          特別聲明,上面三圖截圖來自于《Hello darkness, my old friend》【8】一文。(https://web.dev/prefers-color-scheme/)

          上面示例還做了另一個細節(jié)上的優(yōu)化。和其他媒體查詢更改一樣,可以通過JavaScript的訂閱來更改暗黑模式。比如可以動態(tài)更改頁面的favicon或更改<meta name="theme-color">來決定Chrome中URL欄的顏色。代碼并不復雜:

          const darkModeMediaQuery=window.matchMedia('(prefers-color-scheme: dark)');darkModeMediaQuery.addListener((e)=> {    const darkModeOn=e.matches;    console.log(`Dark mode is ${darkModeOn ? 'on' : 'off'}.`);});

          ? CSS混合模式來助攻

          上面我們看到的都是原生CSS處理暗黑模式的技術方案。事實上我們還可以通過CSS Hack來實現(xiàn),采用CSS的filter和CSS的混合模式mix-blend-mode。

          下面這個示例就是CSSfilter實現(xiàn)的暗黑模式:

          Switch from light to dark mode using the toggle [CSS filter]@airenCodePen【9】(https://codepen.io/airen/pen/qzBzXB)

          關鍵代碼很少:

          .theme-dark {     filter: invert(100) hue-rotate(180deg); } .theme-dark img {     filter: invert(100) hue-rotate(180deg); }

          另外還可以使用CSS的mix-blend-mode來實現(xiàn):

          .dark-mode-screen {
              width: 100vw; 
              height: 100vh; 
              position: fixed; 
              top: 0; 
              left: 0; 
              background: white; 
              mix-blend-mode: difference; 
          }


          如果你想讓頁面中部分元素忽略mix-blend-mode:difference帶來的影響,可以使用isolation: isolate:


          .twitter-logo,
          .emoji {
              isolation: isolate; 
          }

          效果會類似下圖這樣:

          有關于這方面的詳細介紹可以閱讀@thoughtspile的《How to create a dark theme without breaking things: learning with the Yandex Mail team》【10】和的@wgao19《Night Mode with Mix Blend Mode: Difference》【11】。(https://habr.com/en/company/yandex/blog/450032/)(https://dev.wgao19.cc/sun-moon-blending-mode/)

          ? 其他細節(jié)

          根據(jù)前面的內(nèi)容去操作,不管是使用CSS的媒體查詢prefers-color-scheme、新特性color-scheme還是借助CSS的濾鏡filter或混合模式mix-blend-mode都可以輕易的給Web網(wǎng)站或應用程序添加暗黑模式。

          注意,很多同學有一個小誤區(qū),認為filter和mix-blend-mode只能用于圖片,事實上并非如此,他可以運用于Web的各種元素上。

          那么掌握了實現(xiàn)暗黑模式的技術方案就能做出好的效果嗎?并非如此,其中還是有很多細節(jié)需要我們注意。比如顏色的配置、Web媒體(圖片、Icon等)和可訪問性等方面的處理都值得我們?nèi)ネ魄谩?/p>

          顏色的配置

          在給Web網(wǎng)站或Web應用設計暗黑模式的時候,你千萬不要鉆到死胡同里。暗黒模式并不僅僅是黑(black)白(white)之間的切換。你想像一下,在一個深夜密不透光的地方,用你的肉眼注視著一塊高亮的屏幕,時間久了,你會有什么樣的一個感覺:

          正確的做法是應該為你的品牌色系提供一個暗色系版本,如果不奏效的話,可以根據(jù)需要在黑色和灰色之間選擇一個平均顏色。比如說,Web的背景顏色是black(#000)(或者接近#000)的話,建議你前景色(比如文本顏色)取值為rgb(250,250,250)(或者靠近這個顏色值)。這樣才能讓你的整體效果不至于亮瞎用戶的眼睛。比如下面這樣的一個效果:

          如果你實在拿不準配色是否合理(Web安全顏色),你可以借助在線工具,比如 Contrast Checker 【12】:(https://contrastchecker.com/)

          該工具是根據(jù) WCAG 2.0 guidelines for contrast accessibility【13】 標準來做的。比如下面圖所展示的效果就是一個較好的效果:(https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html)

          除了借助工具來檢測之外,瀏覽器的插件也是把利器,可以借助瀏覽器有關于Accessibility相關的插件來做檢測,就比如小站,檢測出來的結(jié)果令人汗顏:

          事實上,很多網(wǎng)站都存在這樣的缺陷:

          圖片處理

          在暗黑模式下,圖片的處理也是非常重要的。它們可能會直接影響用戶的體驗,太亮的圖像可能會讓用戶感到困惑和不舒服。而且有人做過這方面相應的調(diào)查,大多數(shù)被調(diào)查的人在暗黑模式下更喜歡亮度低的圖像。比如下面這張圖:

          左側(cè)是暗黑模式下效果,右側(cè)是在高亮模式下效果。

          為了能更用戶更好的體驗,這里提倡在不同模式下給用戶展示不同效果的圖像,但并非說在不同的模式下引入不同的圖片。就目前CSS的技術,我們在同一圖像源下可以很好的對圖像做處理。比如,粗暴一點的使用CSS的opacity,溫柔一點的使用CSS的混合模式mix-blend-mode(如果是背景的話則用background-blend-mode)或 filter。


          // 粗暴模式
          @media (prefers-color-scheme: dark) {
              img {
                  opacity: 0.65;
              }
          
              img:hover {
                  opacity: 1;
              }
          }
          
          // 溫柔模式
          @media (prefers-color-scheme: dark) {
              img {
                  filter: brightness(.8) contrast(1.2);
              }
          }


          不過這里有一個細節(jié)需要注意,我們引入的圖像源有可能是.svg的矢量圖,如果希望給矢量圖(更多是Icon)一個不同于位圖(更多是圖像,照片)的重新著色處理。那么我們可以通過屬性選擇器和偽類選擇器將.svg過濾掉:

          @media (prefers-color-scheme: dark) {
              img:not([src*=".svg"]) {
                  filter: brightness(.8) contrast(1.2);
              }
          }

          如果你希望給用戶更多的選擇的話,我們可以將CSS自定義屬性和JavaScript結(jié)合起來,可以讓用戶根據(jù)自己的喜好去做調(diào)節(jié)。這里還是拿圖片的處理為例吧:

          // dark.css
          :root {
              --brightness: brightness(.8);
              --contrast: contrast(1.2);
              --image-filter: var(--brightness) var(--contrast);
          }
          
          // JS
          document.documentElement.style.setProperty('--image-filter', value);


          也可以參考下面這個Demo【14】,使用filter修改圖片效果:

          (https://codepen.io/nitnelav/full/jgwRNJ)

          CSS Filters@nitnelavCodePen【15】(https://codepen.io/nitnelav)

          當然,如果你是位追求極致的同學,希望在暗黑模下給用戶提供最好的圖像,而不是隨便修改圖片的亮度或飽和度;但又不希望因加載圖片資源過多而影響整體的性能(甚至不希望因為自己的原因過渡浪費流量)。如果真的是這樣的話,你可以由設計師為暗黑模式下提供特定的圖片,然后與<picture>元素一起使用。可以在<picture>的<source>根據(jù)媒體屬性的設置加載所需要的圖片資源:

          // dark.css
          :root {
              --brightness: brightness(.8);
              --contrast: contrast(1.2);
              --image-filter: var(--brightness) var(--contrast);
          }
          
          // JS
          document.documentElement.style.setProperty('--image-filter', value);


          暗黑模式下會加載dark.webp圖片,在高亮模式或者不支持prefers-color-scheme的瀏覽器中會加載light.webp圖片,不支持<picture>的瀏覽器會加載light.png圖片。你將看到的效果可能如下:

          圖標的處理


          剛才提到過,很有可能你Web網(wǎng)站或Web應用程序中有很多Icon圖標用的是SVG圖標。在暗黑模式下,同樣要對Icon圖標做相應的處理。這里來看兩種情景。

          先來看第一種,那就是.svg文件和其他格式的圖像一相通過<img>標簽引入。由于該Icon很有可能是純色的,因此在暗黑模式下,我們可以通過filter來做dark/light之間的切換:

          /* dark.css */
          :root {
              --icon-filter: invert(100%);
              --icon-filter_hover: invert(40%);
          }
          
          img[src*=".svg"] {
              filter: var(--icon-filter);
          }
          
          /* light.css */
          :root {
              --icon-filter_hover: invert(60%);
          }
          
          /* style.css */
          img[src*=".svg"]:hover {
              filter: var(--icon-filter_hover);
          }


          如果你還想調(diào)整成其他的顏色,還可以像下面這個 Demo 【16】來操作,增加filter的屬性值選項:(https://codepen.io/airen/full/eaRBXq)

          Change Icon Color with CSS Filter (Forked @ Cassie Evans)@airenCodePen【17】(https://codepen.io/airen/pen/eaRBXq)

          該方法和處理圖像的方法是類似的。接下來我們再來看第二種方式。使用的Icon圖標很有可能是內(nèi)聯(lián)的SVG,針對這樣的場景,我們可以使用CSS的currentColor屬性。currentColor最大的特性就是可以根據(jù)color的值來決定元素的顏色,而對于SVG繪制的Icon圖標,主要由path、circle、rect這樣的元素構(gòu)成,這些元素可以通過fill、stroke來決定填充色和描邊色。換句話說,我們在使用內(nèi)聯(lián)SVG時,將SVG中用到fill和stroke的屬性值都強制設置成currentColor,就像下面這樣:

          <svg xmlns="http://www.w3.org/2000/svg"   
              viewbox="0 0 24 24" fill="none"
              stroke="currentColor" stroke-width="2"
              stroke-linecap="round" stroke-linejoin="round"
          > 
              <circle cx="12" cy="12" r="10"/>
              <circle cx="12" cy="12" r="4"/>
              <line x1="21.17" y1="8" x2="12" y2="8"/>
              <line x1="3.95" y1="6.06" x2="8.54" y2="14"/>
              <line x1="10.88" y1="21.94" x2="15.46" y2="14"/>
          </svg>

          另外在媒體查詢中設置:

          @media (prefers-color-scheme: dark) {    :root {        --background-color: #111416        --text-color: #ccc;        --link-color: #f96;    }    svg {        color: var(--text-color)    }}


          如果你分成多個文件的話,可能會像下面這樣的:

          @media (prefers-color-scheme: dark) {
              :root {
                  --background-color: #111416
                  --text-color: #ccc;
                  --link-color: #f96;
              }
          
              svg {
                  color: var(--text-color)
              }
          }


          讓切換有一個過渡效果

          熟悉CSS的同學都應該記得,CSS的transition可以讓元素在兩個狀態(tài)的切換過程中有一個平滑過渡的效果,以至于不會那么生硬:

          而我們聊的dark/light兩模式之間的切換剛好穩(wěn)合transition。加上dark/light兩模式之間的切換就是color和background-color屬性值的切換。為了讓整個切換過程有一個過渡效果,我們可以把transition加上來。比如:

          /* dark.css */
          :root {
              --color: rgb(250, 250, 250);
              --background-color: rgb(5, 5, 5);
              --link-color: rgb(0, 188, 212);
              --main-headline-color: rgb(233, 30, 99);
              --accent-background-color: rgb(0, 188, 212);
              --accent-color: rgb(5, 5, 5);
          }
          
          /* light.css */
          :root {
              --color: rgb(5, 5, 5);
              --background-color: rgb(250, 250, 250);
              --link-color: rgb(0, 0, 238);
              --main-headline-color: rgb(0, 0, 192);
              --accent-background-color: rgb(0, 0, 238);
              --accent-color: rgb(250, 250, 250);
          }
          
          /* style.css */
          :root {
              color-scheme: light dark;
          }
          
          body {
              color: var(--color);
              background-color: var(--background-color);
          }
          
          svg {
              color: var(--color);
          }


          JavaScript實現(xiàn)dark/light模式切換



          如果你不依任CSS,或者說希望讓自己的Web網(wǎng)站或Web應用程序都具備dark/light模式的切換,那么可以通過JavaScript來實現(xiàn)。因為dark/light模式的切換說到底就是兩套主題的切換。當然,你可以讓該JS的能力更為強大一些,不僅僅是對.css文件的切換,粗暴簡單的實現(xiàn)網(wǎng)站換膚這樣的一個功能。或許你可以這樣做:

          • 在網(wǎng)站上提供相應的切換按鈕(比如一個tab選項卡,也可以是一個radio按鈕),方便用戶自行選擇
          • 該JS可以對系統(tǒng)級別做監(jiān)聽,如果用戶從系統(tǒng)級別開啟了暗黑模式,那么就把樣式文件切換到dark.css下
          • 還可以根據(jù)時間來做一個dark/light模式的切換,比如說白天采用light模式,晚上使用dark模式
          • 和CSS實現(xiàn)dark/light模式切換一樣,還可以在JS中加上transition效果,讓模式在切換的過程有一個過渡效果

          為了節(jié)約篇幅,這里就不把JavaScript代碼貼出來了,感興趣的話可以看看@Koos Looijesteijn的《 A guide to implementing dark modes on websites》【18】一文。文章中詳細的根據(jù)上面幾個過程,向大家展示了對應的JavaScript代碼。如果你不愿閱讀文章的話,可以點擊鏈接直接閱讀源代碼【19】。(https://www.kooslooijesteijn.net/blog/add-dark-mode-to-website)(https://gist.github.com/kslstn/20f654fd27eb29619040c74fa6526919)

          不過就我個人而言,我不太推薦使用JavaScript方案,這可能和我自己的信條有關系:

          在Web端能用CSS實現(xiàn)的絕不借助JavaScript。


          瀏覽器配置



          下面有一個簡單的示例:

          Switch light / dark mode with prefers-color-scheme: dark@airenCodePen【20】(https://codepen.io/)

          在該示例的頁面上沒有提供任何切換按鈕給用戶做選擇。主要目的是希望頁面能根據(jù)系統(tǒng)級別的設置來決定采用什么主題。假設你的系統(tǒng)默認就開啟了暗黑模式。但你在瀏覽器看到的效果也不一定是dark模式下的效果。這主要是因為瀏覽器對prefers-color-scheme支持有一定的差異。不過我們可以對瀏覽器做一些設置,讓頁面能正常的跟著系統(tǒng)設置做出正確的渲染。

          如果你使用Firefox,可以在地址欄中輸入about:config,然后鼠標右鍵點擊選擇“新建(New)” → “整數(shù)(Integer)”,新建整數(shù)ui.systemUsesDarkTheme,并且將其值設置為1:

          如果你使用的是Safari瀏覽器,可以使用它自帶的工具來查看效果:

          最終在支持的瀏覽器下看到的效果如下:

          除此之外,還可以給瀏覽器安裝插件。比如@CHRIS HOFFMAN在他的《 How to Enable Dark Mode for Google Chrome》【21】文章中就詳細的介紹了怎么在Chrome瀏覽器安裝Dark Reader【22】插件,讓Web頁面具有暗黑模式瀏覽效果:(https://www.howtogeek.com/360650/how-to-enable-dark-mode-for-google-chrome/)(https://chrome.google.com/webstore/detail/dark-reader/eimadpbcbfnmbkopoojfekhnkhdbieeh)


          小結(jié)


          上面我們通過不同的方式向大家闡述和演示了如何實現(xiàn)黑暗模式和高亮模式切換的解決方案。有粗暴簡單的方式,原始的切換樣式表的方式,還有采用一些新的CSS特性,比如CSS自定義屬性,新的媒體查詢特性,還有神奇的濾鏡和混合模式。而且這些解決方案中既有CSS和JavaScript的混合解決方案,也有純CSS的解決方案,甚至還有原生系統(tǒng)和瀏覽器通信的解決方案。還是那句老話,不管哪種解決方案或者技術手段,都有自己的利弊,沒有最好,只有最適合的使用場景。在實際使用的時候,應該具體問題具體分析。


          擴展閱讀



          如果你想更深入了解這方面的知識,建議你花一些時間閱讀下面相關的教程:

          • Hello darkness, my old friend

          https://web.dev/prefers-color-scheme/#vector-graphics-and-icons

          • Implementing Dark Mode For My Website

          https://ishadeed.com/article/dark-mode

          • Dark mode

          https://adactio.com/journal/15941

          • A guide to implementing dark modes on websites

          https://www.kooslooijesteijn.net/blog/add-dark-mode-to-website

          • How to Enable Dark Mode for Google Chrome

          https://www.howtogeek.com/360650/how-to-enable-dark-mode-for-google-chrome/

          • Dark Mode in CSS

          https://css-tricks.com/dark-modes-with-css/

          • Night Mode with Mix Blend Mode: Difference

          https://dev.wgao19.cc/2019-05-04__sun-moon-blending-mode/

          • CSS-only dark mode

          https://kleinfreund.de/css-only-dark-mode/

          • Designing for Dark Mode

          https://www.kirupa.com/tricks/dealing_with_dark_mode.htm

          • Supporting macOS Mojave’s Dark Mode on the web

          https://kevinchen.co/blog/support-macos-mojave-dark-mode-on-websites/

          • Create A Dark/Light Mode Switch with CSS Variables

          https://dev.to/ananyaneogi/create-a-dark-light-mode-switch-with-css-variables-34l8

          • Firefox 67: Dark Mode CSS, WebRender, and more

          https://hacks.mozilla.org/2019/05/firefox-67-dark-mode-css-webrender/

          • How to create a dark theme without breaking things: learning with the Yandex Mail team

          https://habr.com/en/company/yandex/blog/450032/



          更多技術干貨,關注「淘系技術」微信公眾號


          主站蜘蛛池模板: 亚洲Aⅴ无码一区二区二三区软件| 无码人妻精品一区二区三区99不卡| 精品一区二区三区免费毛片| 久久亚洲色一区二区三区| 日韩免费无码视频一区二区三区| 久久一区二区三区精华液使用方法| 国产精品女同一区二区| 视频一区视频二区日韩专区| 99无码人妻一区二区三区免费| 2014AV天堂无码一区| 黄桃AV无码免费一区二区三区| 午夜一区二区免费视频| 精品亚洲福利一区二区| 中文字幕一区二区三区人妻少妇| 无码人妻久久一区二区三区 | 精品亚洲一区二区| 中文字幕一区二区三区在线播放 | 成人精品视频一区二区| 精品福利视频一区二区三区 | 国产精品高清一区二区三区不卡| 一区二区三区亚洲| 日韩免费无码一区二区三区| 无码人妻精品一区二区三区在线| 国产视频一区二区在线播放 | 欧美日本精品一区二区三区| 国产乱码精品一区二区三区麻豆 | 夜夜爽一区二区三区精品| 久久久不卡国产精品一区二区| 午夜视频久久久久一区 | 国产主播在线一区| 国产在线不卡一区| 内射少妇一区27P| 国产亚洲综合一区柠檬导航| 久久久久人妻一区二区三区vr| 精品亚洲AV无码一区二区三区| 亚洲无码一区二区三区| 一区 二区 三区 中文字幕| 亚洲国产精品一区二区久久| 精品少妇人妻AV一区二区三区 | 亚洲一区二区女搞男| 精品日韩一区二区三区视频|