CSS Masks
<defs>
<mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse">
遮罩圖片
</mask>
</defs>
<foreignObject width="400px" height="300px" style="mask: url(#mask);">被遮對象</foreignObject>
</svg>
3、chroma過濾器css屬性filter;這個我沒有測試成功,希望有成功的可以留言告訴我方法。
圖像是由rgb三個通道以及在每個像素上定義的顏色組成的。但是在他們之上還有第四個通道,alpha通道,通過亮度定義每個像素上的透明度。白色意味着不透明,黑色意味着透明,介於黑白之間的灰色表示半透明。你可以看到下面的圖片
給一個html元素使用css遮罩,就會這樣處理。不用給圖片應用一個alpha通道,只需要給一個圖片運用一個-webkit-mask-image的css屬性。例如:-webkit-mask-image: url(mouse.png);他從圖片遮罩里讀出圖片的透明信息,然后應用到html元素上,就像下面顯示的圖片
遮罩可以讓頭像按照特定形狀顯示。
這么做有什么好處呢?遮罩可以使得圖片按照任意的形狀顯示。或者你可能有很長的文本需要滾動顯示,那么可以使用遮罩讓他從不透明到透明的漸變顯示。
你也可以用background-image屬性,或是css的漸變屬性,代替一個實際的位圖,代碼示例如下:
-webkit-mask-image: -webkit-linear-gradient(top, rgba(0,0,0,1), rgba(0,0,0,0));
注意:這種舊的語法很快被新語法linear-gradient(to bottom, rgba(0,0,0,1), rgba(0,0,0,0))取代(目標關鍵字改變成to bottom)。LennartSchoors有一篇關於這個問題的短文。
當蘋果把css遮罩帶給webkit時,未能將他的實現細節和文件與w3c達成一致。所以意味着,如果其他供應商想要實現遮罩效果,他們就不得不首先反向編譯,找出所有的實現細節。這種工作沒有人願意做。所以直到幾天前,2012年11月15號,遮罩第一次出現在w3c公布的草案中。但是跟蘋果公司的是不同的版本。
好消息是:其他瀏覽器有類似功能,用不同的實現方式實現webkit屬性中的css遮罩。
模擬一個簡單-webkit-mask-image的跨瀏覽器遮罩效果
我們可以讓html元素如下圖顯示成米老鼠頭像的樣子:
我們讓html使用webkit專有的css遮罩效果:
<div class="element"> <p>Lorem ipsum dolor sit … amet.</p> </div>
定義如下樣式:
.element { width: 400px; height: 300px; overflow: hidden; color: #fff; background: url(background.png); -webkit-mask-image: url(mouse.png); }
現代瀏覽器
我們看一下現代瀏覽器,支持html技術的瀏覽器,可以在html內部解析svg,像這樣:
<!DOCTYPE html>
<html> <body> <svg width="300px" height="300px"> <circle cx="125" cy="150" r="50" fill="pink" stroke="green" stroke-width="5" /> </svg> </body> </html>
最重要的是webkit也跟firefox和opera一樣,提供一個相反的操作:就是把xthml嵌入到svg里,多虧svg1.1的擴展特性和<foreignObject>元素
<?xml version="1.0" standalone="yes"?>
<svg width="400px" height="300px" version="1.1" xmlns="http://www.w3.org/2000/svg"> <foreignObject width="400px" height="300px"> <!-- HTML begin --> <div class="element"> <p>Lorem ipsum dolor sit … amet.</p> </div> <!-- HTML end --> </foreignObject> </svg>
Ie9和ie10是唯一現代瀏覽器不支持<foreignObject>元素的,我們將在后面討論ie的問題。
內聯的svg和<foreignObject>元素可以在svg包裝器里面附上頁面的一部分html代碼,這樣就可以讓html塊呈現成我們想要的遮罩樣子
<!DOCTYPE html>
<html> <head> <style> .element { width: 400px; height: 300px; overflow: hidden; color: #fff; background: url(background.png); -webkit-mask-image: url(mouse.png); } </style> </head> <body> <!-- SVG wrapper begins --> <svg> <foreignObject width="400px" height="300px"> <!-- inner HTML begins --> <div class="element"> <p>Lorem ipsum dolor sit … amet.</p> </div> <!-- inner HTML ends --> </foreignObject> </svg> <!-- SVG wrapper ends --> </body> </html>
下一步是在svg里面定義svg遮罩,我們可以定義遮罩圖片,然后通過style="mask:[mask id]"應用到內嵌的html或是foreignObject上
<!DOCTYPE html>
<html> <body> <!-- SVG begins --> <svg> <!-- Definition of a mask begins --> <defs> <mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse"> <image width="400px" height="300px" xlink:href="mouse.png"></image> </mask> </defs> <!-- Definition of a mask ends --> <foreignObject width="400px" height="300px" style="mask: url(#mask);"> <!-- HTML begins --> <div class="element"> <p>Lorem ipsum dolor sit … amet.</p> </div> <!-- HTML ends --> </foreignObject> </svg> <!-- SVG ends --> </body> </html>
最后,我們需要一個合適的遮罩圖片。我們不能簡單的使用webkit中屬性css遮罩圖片,因為svg遮罩認得亮度值而不認得透明值。所以我們需要把所有的不透明圖片轉換成不同深淺的白色。
在ps里操作很簡單:
- 打開你想要作為遮罩的透明png24的圖片
- 選擇圖層菜單,然后圖層樣式最后是顏色疊加
- 在顏色疊加對話框里面改變顏色值為白色
- 點擊ok關閉對話框
- 選擇文件菜單,保存為web,替換舊的圖片
遮罩html的內容在webkit,firefox和opera都效果不錯,很棒!
IE瀏覽器
IE8以及其以下的瀏覽器不支持svg標簽。他們將會標記為未知元素。把他們當做是普通html代碼來渲染頁面。
<!DOCTYPE html>
<html> <body> <svg></svg> <defs></defs> <mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse"></mask> <image width="400px" height="300px" xlink:href="mouse.png"/></image> </mask><//mask> </defs><//defs> <foreignObject width="400px" height="300px" style="mask: url(#mask);"></foreignObject> <div class="element"> <p>Lorem ipsum dolor sit … amet.</p> </div> </foreignObject><//foreignObject> </svg><//svg> </body> </html>
這個很cool,因為它實際是一個自動優雅降級。
Ie9和ie10有一個問題。他們都識別svg,但是都不知道<foreignObject>元素。他們渲染svg,但是把它作為<foreignObject>的一部分,而<foreignObject>是無效svg標簽。所以這部分就跟svg一起失效啦。意思是:我們的內容是迷惑我們的讀者,所以整個去掉。這樣不好。
我們考慮可以用條件注釋在ie里面隱藏svg部分,但是微軟決定在ie10里去掉條件注釋。所以目前還沒有解決辦法。
唯一的解決辦法是
- 用支持svg擴展和<foreignObject>元素的客戶端測試;
- 用js渲染svg片段支持svg擴展。
這段js是我們需要的,把它加到頁面的頭部
function head () {
if (window.SVGForeignObjectElement) {
document.write('\
<svg width="400px" height="300px">\ <defs>\ <mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse">\ <image width="400px" height="300px" xlink:href="mouse.png"/>\ </mask>\ </defs>\ <foreignObject width="100%" height="100%" style="mask: url(#mask);">\ '); } } function foot () { if (window.SVGForeignObjectElement) { document.write('\ </foreignObject>\ </svg>\ '); } }
在我們的html結構中需要調用這些js函數替換原來的svg部分
<body> <script>head();</script> <div class="element"> <p>Lorem ipsum dolor sit … amet.</p> </div> <script>foot();</script> </body>
現在內容在所有的ie瀏覽器將保持一致。IE11應該支持<foreignObject>,我們拭目以待吧。
注1:你看到在每行最后字符串內部的反斜杠,容許多行字符串。他們得到每個瀏覽器和官方ecmascript5標准的支持。
注2:document.write是最好的js實踐嗎?那是個瘋子,那為什么還使用他?凡事沒有絕對的對錯,完全依賴於使用的環境。如果你在外部js文件利用document.write,是個很糟糕的事情。document.write迫使在html中預加載的地方嵌入外部腳步文件,同時阻止他們嘗試任何異步加載。這意味着如果這些外部腳步加載失敗,你的頁面就會戛然而止。但是我們在這里不處理外部文件,你應該把它放到一邊。沒有阻塞。另外,由於javascript擁有輸出額外標簽到屏幕,當html解析器運行中,你不會成為短暫的CSS樣式失效的目擊者
什么是FOUC?
flash of unstyled content (FOUC) 它指的是在某些情況下,IE在加載網頁時會出現短暫的CSS樣式失效。
什么是FOUC(文檔樣式短暫失效)?
如果使用import方法對CSS進行導入,會導致某些頁面在Windows 下的Internet Explorer出現一些奇怪的現象:以無樣式顯示頁面內容的瞬間閃爍,這種現象稱之為文檔樣式短暫失效(Flash of Unstyled Content),簡稱為FOUC.
——譯者:D姐
我們到這里很高興也可以就此打住了。但是如何讓ie也支持css遮罩呢?那么,我們走。。。
Ie4-9有一個叫做Chroma的過濾器。它類似與電影拍攝中用的視頻混合技術:就是透過一定顏色然后讓元素同色的部分從屏幕上消失。這種顏色因此叫做顏色遮罩
下面的css代碼會讓元素上的所有青色部分消失
filter: progid:DXImageTransform.Microsoft.Chroma(color='cyan'); zoom: 1; /* Needed in IE < 8 */
為什么是青色?這里僅僅是個建議。你可以使用任何顏色,作為你想要的遮罩顏色,而不是必須是青色。但是這個顏色必須是一個單獨的,沒有用到其他地方的顏色。所以跟內容混合的顏色不應該作為遮罩顏色。
現在,有個更有意思的事情,chroma過濾器事實上不僅僅會過濾元素本身的顏色,還會過濾他孩子元素的顏色。因為應用下面的樣式會創建一個10px寬的框。
.parent { width: 120px; background-color: #eee; filter: progid:DXImageTransform.Microsoft.Chroma(color='cyan'); zoom: 1; } .child { height: 100px; margin: 10px; background-color: cyan; }
對應的標記:
<div class="parent"> <div class="child"></div> </div>
青色區域的子元素會過濾父元素,我們將會透過青色區域它看父元素。
還是回到我們的米老鼠頭像的例子,我們需要做的是創建一個米老鼠頭像形狀的圖片,這個圖片需要外部是青色的,里面的形狀是透明的,如圖所示。
在photoshop中需要做下面的事情:
- 打開現有的svg遮罩的png圖片
- 按住ctrl鍵或是cmd (mac中),點擊圖層面板中的圖層0
- 按下Backspace或del鍵移除白色部分
- 從選擇菜單中選擇反相
- 點擊前景色,把他顏色值改為#00FFFF (RGB: 0,255,255)
- 從編輯菜單中選擇填充,把前景色填充
- 選擇文件菜單里面的保存成web
- 在保存為web對話框里選擇png-8格式,帶有2個顏色值和透明度
- 保存為一個單獨的文件,如mouse-cyan.png
我們只保存兩個顏色,是為了消除形狀邊界的鋸齒。這么做的目的是因為chroma過濾器只能過濾單一顏色。
現在我們需要把圖片放到想要產生遮罩效果的元素上,就像下圖一樣
我們面臨的一個難題是:我們需要完成的這個效果,不能使用css中的定位屬性。為什么?因為ie的過濾器遇到定位元素就不起作用了。所以最好的解決方式是使用負邊距,讓青色遮罩移動到元素上。例如:
<div class="element"> <p>Lorem ipsum dolor sit … amet.</p> </div> <img src="mouse-ie.png" style="display: block; margin-top: -300px;">
現在你可以過濾了
<div style="width: 400px; height: 300px; filter: progid:DXImageTransform.Microsoft.Chroma(color='#00FFFF'); zoom: 1;"> <div class="element"> <p>Lorem ipsum dolor sit … amet.</p> </div> <img src="mouse-ie.png" style="display: block; margin-top: -300px;"> </div>
這項技術的一個遺憾事情是,微軟決定從ie10里移除所有的專有過濾器,除了條件注釋。他們也移除了所有的遺留模式。所以這個解決方案也僅限於IE4-9。
為了讓ie都有效果,我們需要擴展我們的javascript
function head () {
if(window.SVGForeignObjectElement) {
document.write('\
<svg width="400px" height="300px">\ <defs>\ <mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse">\ <image width="400px" height="300px" xlink:href="mouse.png"/>\ </mask>\ </defs>\ <foreignObject width="100%" height="100%" style="mask: url(#mask);">\ '); } else { document.write('\ <div style="width: 400px; height: 300px; filter: progid:DXImageTransform.Microsoft.Chroma(color=\'#00FFFF\'); zoom: 1;">\ '); } } function foot () { if(window.SVGForeignObjectElement) { document.write('\ </foreignObject>\ </svg>\ '); } else { document.write('\ <!--[if lte IE 9]>\ <img src="mouse-ie.png" style="display: block; margin-top: -300px;">\ <![endif]-->\ </div>\ '); } }
所以如果<foreignObject>在svg里包裹的元素支持,如果不支持我們可以轉成IE瀏覽器的過濾器實現。最后所有瀏覽器都實現了css遮罩效果,除了IE10瀏覽器。還是相當不錯的,是不是?這是最終效果
注意,這時當你需要硬性按照圖片形狀裁剪的最好方法。你可能對軟性遮罩裁剪也感興趣,只不過沒有ie支持,因為chroma過濾器沒有過濾軟邊的能力。
在任何情況下,都不要忘了檢查沒有應用遮罩的輸出效果是否優雅降級。因為有ie10不支持遮罩,而且javascript也可能被禁用。
我確實說過“除了一個瀏覽器其他瀏覽器都支持嗎?”我撒謊了。對於桌面瀏覽器是真的。大多數的移動webkit瀏覽器仍然落后於前沿技術。不僅是Android系統,蘋果系統的safari對於svg支持的也不是很好。所以對於他們需要使用-webkit-mask-image.做加倍的svg遮罩。我們可以在樣式表中這樣做
.element { width: 400px; height: 300px; overflow: hidden; background: #36f url(background.png); color: #fff; -webkit-mask-image: url(mouse.png); }
最后我們做到了。
線漸變遮罩
記得一開始我說過,你也可以使用漸變做遮罩。這也可能在上述瀏覽器都適用,那我們之前的步驟需要做一些調整。首先我們需要用一個漸變圖片或是用一個純的svg路徑,然后定義一個svg矩形,用svg漸變填充,來代替svg遮罩內容
<mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse"> <linearGradient id="g" gradientUnits="objectBoundingBox" x2="0" y2="1"> <stop stop-color="white" stop-opacity="1" offset="0"/> <stop stop-color="white" stop-opacity="0" offset="1"/> </linearGradient> <rect width="400px" height="300px" fill="url(#g)"/> </mask>
這個代表漸變從上到下的方向(從(0,0)點到(0,1)點),第一個點的位置是完全不透明的白色,第二個點是完全透明的白色
對於ie我們不再需要青色圖片,因為我們這次不使用chroma過濾器,而是使用alpha過濾器。過去我們使用alpha過濾器,是為了彌補老的ie瀏覽器沒有opacity屬性。但是他的能力遠遠不至於此。你可以把他運用到漸變模式上,定義開始和結束點,也可以定義開始和結束的透明度。這是一個簡單的例子:
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100,FinishOpacity=0,Style=1,StartX=0,FinishX=0,StartY=0,FinishY=300);
這個漸變樣式alpha過濾器開始於點(0,0)擴展到(0,300).開始透明度是100%,結束透明度是0%。
移動webkit我們通常很容易這樣實現
-webkit-mask-image: -webkit-linear-gradient(top, rgba(0,0,0,1), rgba(0,0,0,0));
事實證明Android 2.0不支持漸變作為遮罩圖片。我們別無選擇只能使用一個漸變的png,頂部是不透明的逐漸漸變到底部是透明的。因為-webkit-mask的行為類似於小背景圖片平鋪蓋在區域上。所以使用一個1px X 300px的圖片足以。最后把嵌入的圖片借助於duri.me,把圖片進行64編碼做為數據url,這樣節省http的請求。這是我們可以放到外部樣式里
-webkit-mask-image: url(data:image/png;base64,iVBORw…[shortedned a bit]…FTkSuQmCC);
下面是javasript的修改
function head () {
if (window.SVGForeignObjectElement) {
document.write('\
<svg width="400px" height="300px">\ <defs>\ <mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse">\ <linearGradient id="g" gradientUnits="objectBoundingBox" x2="0" y2="1">\ <stop stop-color="white" stop-opacity="1" offset="0"/>\ <stop stop-color="white" stop-opacity="0" offset="1"/>\ </linearGradient>\ <rect width="400px" height="300px" fill="url(#g)"/>\ </mask>\ </defs>\ <foreignObject width="100%" height="100%" style="mask: url(#mask);">\ '); } else { document.write('\ <div style="width: 400px; height: 300px; filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100,FinishOpacity=0,Style=1,StartX=0,FinishX=0,StartY=0,FinishY=300); zoom:1;">\ '); } } function foot () { if (window.SVGForeignObjectElement){ document.write('\ </foreignObject>\ </svg>\ '); } else { document.write('\ </div>\ '); } }
如果如下:
徑向漸變遮罩
徑向漸變也是可以的。我們來做一個400px X 400px的圖片遮罩
<body> <script>head();</script> <img src="photo.jpg" width="400" height="400" alt="Dude"> <script>foot();</script> </body>
然后我們需要這樣改變我們的svg遮罩:
<mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse"> <linearGradient id="g" gradientUnits="objectBoundingBox" x2="0" y2="1"> <stop stop-color="white" stop-opacity="1" offset="0"/> <stop stop-color="white" stop-opacity="0" offset="1"/> </linearGradient> <rect width="400px" height="400px" fill="url(#g)"/> </mask>
這里alpha過濾器的style=2中的2代表徑向形狀
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100,FinishOpacity=0,Style=2);
腳本轉譯成:
function head () {
if (window.SVGForeignObjectElement) {
document.write('\
<svg width="400px" height="400px">\ <defs>\ <mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse">\ <radialGradient id="g" gradientUnits="objectBoundingBox" cx="0.5" cy="0.5" r="0.5" fx="0.5" fy="0.5">\ <stop stop-color="white" stop-opacity="1" offset="0"/>\ <stop stop-color="white" stop-opacity="0" offset="1"/>\ </radialGradient>\ <rect width="400px" height="400px" fill="url(#g)"/>\ </mask>\ </defs>\ <foreignObject width="100%" height="100%" style="mask: url(#mask);">\ '); } else { document.write('\ <div style="width: 400px; height: 400px; filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100,FinishOpacity=0,Style=2); zoom: 1;">\ '); } } function foot () { if (window.SVGForeignObjectElement) { document.write('\ </foreignObject>\ </svg>\ '); } else { document.write('\ </div>\ '); } }
對於移動webkit我們再次創建一個徑向漸變的位圖。使用一個50px X 50px圖片足夠了。然后把它拉伸蓋在400px×400px的元素上,我們需要使用-webkit-mask-size: cover.
img { -webkit-mask-size: cover; -webkit-mask-image: url(data:image/png;base64,iVBORw0…[shortened a bit]…lFTkSuQmCC); }
最終效果:
著作權歸作者所有。
商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
原文: https://www.w3cplus.com/css3/css-masking.html © w3cplus.com