色域媒體查詢(color-gamut media query)標準與使用
什麼是色域媒體查詢?
色域媒體查詢(color-gamut media query)是 CSS Media Queries Level 4 中新增的媒體屬性。媒體查詢允許我們根據不同的輸出設備進行內容定製,而無需修改內容本身。色域媒體查詢允許我們根據輸出設備的支持色域分類應用不同的樣式。
用法介紹
下面演示如何根據媒體色域給首頁的題圖提供不同的背景圖片
@media (color-gamut: srgb) { .hero { background-image: url(http://example.com/foobar.png); }}@media (color-gamut: p3) { .hero { background-image: url(http://example.com/foobar-p3.png); }}
在上面的例子中,大部分設備都支持 sRGB 色域將會把 .hero 選擇出來的結點的 background-image屬性設置成 foobar.png; 對於支持 DCI P3 色域的設備,後面的樣式會對之前設置的 background-image 屬性覆蓋成foobar-p3.png.
上面的例子是一個典型的色域媒體查詢的應用場景。需要注意的是,對於給定的色域,color-gamut僅僅查詢設備能否顯示該色域大部分顏色。由於色域間可能存在的包含關係,如 DCI P3 色域包含 sRGB 色域,因此一個能顯示 DCI P3 色域的設備也能夠顯示 sRGB 色域,從而表達式color-gamut: srgb在支持 DCI P3 色域的設備上將會返回真值。所以我們通常將媒體色域查詢按照色域遞增的順序排列,使的寬色域的樣式能夠覆蓋上一條窄色域的樣式。
由於色域呈現的視覺效果對大部分人而言差別並不大,這裡的 jsfiddle 的例子對色域查詢顯示以文字形式展示查詢結果。
瀏覽器支持
截至發稿時,只有 Chrome 58 和 Safari 10 支持色域查詢。
從 Canon RAW 到 DCI P3
上面介紹了如何對 DCI P3 色域的設備進行圖片內容定製。內容有消費首先需要生產者,下面介紹如何在 macOS 下如何將 Canon Raw 格式轉化成使用 DCI P3 色域的文件,可以分別使用圖形化界面的 Photos 或者命令行 GraphicsMagick 來轉化。
Photos
將 RAW 文件導入到 Photos 中,選擇文件,導出該圖片。在導出對話框中的色彩配置中選擇 Display P3. 可以參考 Apple 幫助網站的說明。
GraphicsMagick
安裝前置工具
brew install graphicsmagick dcraw
轉化 CR2 為 DCI P3 色域的 jpg 文件。假設待轉換文件為~/Desktop/test.CR2
gm convert -profile /System/Library/ColorSync/Profiles/Display P3.icc ~/Desktop/test.CR2 ~/Desktop/test-p3.jpg
作為對比,還可以生成 sRGB 色域的 jpg 文件:
gm convert ~/Desktop/test.CR2 ~/Desktop/test-srgb.jpg
通過這兩個文件可以對比出,DCI P3 色域確實比 sRGB 色域飽和度更高、色彩更加鮮艷。
隱私考慮
媒體查詢一方面帶來定製呈現形式的便利,另一方面也帶來了用戶隱私泄漏的風險。在媒體查詢的 Level 4 草案中提到
At minimum, the same information should be inferrable via scripting by examining the User Agent string.
一個 MacOS Chrome 58 的用戶代理信息為
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.33 Safari/537.36
顯然,我們無法通過用戶代理信息去判斷一個設備是否支持 DCI P3 色域。截至發稿時,在消費領域支持 DCI P3 色域的桌面和移動設備有
- Apple iMac (Late 2015)
- Apple iPad Pro 9.7 英寸
- Samsung Galaxy Note 7
- iPhone 7
- Surface Studio (2016)
- Macbook Pro (Late 2016)
因此,對於用戶信息追蹤器而言,使用以下 CSS 樣式可以追蹤到使用這些設備的用戶,後台可以統計此背景圖的訪問量來對用戶進行區分。
@media screen and (color-gamut: p3) { div.track-p3-device { position: absolute; width: 1px; height: 1px; top: 0; left: 0; background-image: url(http://example.com/transparent-track-dci-p3.png); }}
在 JavaScript 中,使用
if (window.matchMedia("(color-gamut: p3)").matches) { //do something}
也可以檢測 DCI P3 色域的設備。因此,色域媒體查詢可以讓內容方根據設備色域來區分用戶。
TL;DR: Chromium/Safari 是如何實現色域查詢的?
簡單地說,Chromium 自己定義了一個色域寬廣度指標,對每個屏幕判斷色域寬廣度;Safari 使用硬體上報的擴展色域是否支持的信息。
下面介紹 Chromium(Chrome) 和 Safari 的色域查詢首次實現方案。瀏覽器總會有不斷的重構,標準也有可能會有更新與修復,因此實現部分只針對首次實現的方案進行介紹。CSS 關鍵字的處理這裡略過不提,重點介紹瀏覽器如何判斷設備的色域。
首先介紹 Safari 的最初實現。 判斷設備色域代碼如下
static bool color_gamutMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData&, Frame*, MediaFeaturePrefix){ if (!value) return true; switch (downcast<CSSPrimitiveValue>(*value).getValueID()) { case CSSValueSrgb: return true; case CSSValueP3: // FIXME: For the moment well just assume an "extended // color" display is at least as good as P3. return screenSupportsExtendedColor(); case CSSValueRec2020: // FIXME: At some point we should start detecting displays that // support more colors. return false; default: ASSERT_NOT_REACHED(); return true; }}
系統調用了screenSupportsExtendedColor方法,並將支持擴展顏色都當作支持到了 DCI P3 色域。此方法最終轉到了 MobileGestaltSPI.h 去獲取硬體信息HasExtendedColorDisplay, 因此 Safari 是通過設備上報的屬性來決定這裡是否支持 DCI P3 色域。對於 Rec2020 色域,目前 Safari 還不會判斷是否支持 Rec2020. 截至發稿時 Safari 的實現與最初實現沒有本質區別。
下面介紹 Chromium 的最初實現。Chrome 會在每個屏幕獲取屏幕上報的色彩空間,通過這個色彩空間來判斷色域,色域判斷代碼如下
ColorSpaceGamut getColorSpaceGamut(SkColorSpace* colorSpace) { sk_sp<SkColorSpace> scRGB(SkColorSpace::MakeSRGBLinear()); std::unique_ptr<SkColorSpaceXform> transform( SkColorSpaceXform::New(colorSpace, scRGB.get())); if (!transform) return ColorSpaceGamut::Unknown; unsigned char in[3][4]; float out[3][4]; memset(in, 0, sizeof(in)); in[0][0] = 255; in[1][1] = 255; in[2][2] = 255; in[0][3] = 255; in[1][3] = 255; in[2][3] = 255; transform->apply(SkColorSpaceXform::kRGBA_F32_ColorFormat, out, SkColorSpaceXform::kRGBA_8888_ColorFormat, in, 3, kOpaque_SkAlphaType); float score = out[0][0] * out[1][1] * out[2][2]; if (score < 0.9) return ColorSpaceGamut::LessThanNTSC; if (score < 0.95) return ColorSpaceGamut::NTSC; // actual score 0.912839 if (score < 1.1) return ColorSpaceGamut::SRGB; // actual score 1.0 if (score < 1.3) return ColorSpaceGamut::AlmostP3; if (score < 1.425) return ColorSpaceGamut::P3; // actual score 1.401899 if (score < 1.5) return ColorSpaceGamut::AdobeRGB; // actual score 1.458385 if (score < 2.0) return ColorSpaceGamut::Wide; if (score < 2.2) return ColorSpaceGamut::BT2020; // actual score 2.104520 if (score < 2.7) return ColorSpaceGamut::ProPhoto; // actual score 2.913247 return ColorSpaceGamut::UltraWide;}
在上面的代碼中,對於給定的色彩空間,生成從這個色彩空間到 sRGB 色彩空間的變換。然後構造了指定色彩空間中的#ff0000, #00ff00, #0000ff三個像素,對這三個像素施加色彩空間變換產生從0到1以 32bit 浮點數表示的三個向量。
對於正常的覆蓋 RGB 三原色的色彩空間,sRGB中的三個基礎顏色向量通過變換產生的三個新向量一定集中在對角線上,即上面的主對角線以外的元素應該都不大。因而如果一個色彩空間色域越寬,那麼對角線的乘積一定越大。 因此可以使用對角線乘積作為色域寬廣度的一個指標。Chromium 團隊對常見色彩空間做了指標計算,從而給定一個色彩空間,通過這個評分可以近似區分許多色彩空間。然而因為標準的草案只有 srgb, p3, rec2020 三個取值, Chromium 在後面的判斷中將這個函數降級以符合標準草案的行為。可以預期如果標準草案增加其他色域作為關鍵字,Chromium 可以進行方便的拓展。
由於標準中並沒有給出計算色域寬廣度的量化指標,因此 Chromium 使用了一個簡單的指標來定量區分。正如開發者所言
While I agree that this is a hacky method, I do think it is good enough to work, but not good enough to be standardized.
上面的方法實際上假定了色彩空間一定主要覆蓋對角線上的色彩(也就是上文提到的#ff0000等三個變數),然而,如果自定義的色彩空間因為特殊用途(如為紅綠色盲用戶定製屏幕)而偏離對角線,那麼使用轉換後對角線乘積的計算方式有可能會出現問題,即該色彩空間可能更多覆蓋對角線外的顏色,而在基準對角線顏色上覆蓋不足,會被認為是窄色域。這也是後面對色域寬廣度計算進行標準化時需要考慮的問題。
參考資料
[1] 色域媒體查詢標準:Media Queries Level 4
[2] 維基百科對 DCI P3 色域的介紹:DCI-P3 - Wikipedia[3] Safari 對色域媒體查詢的最初實現:Changeset 199024 - WebKit[4] Chromium 對色域媒體查詢的最初實現:Issue 2652313004: Implement color-gamut media query本文全文轉載自色域媒體查詢(color-gamut media query)標準與使用,已取得原作者——也就是我許可。
推薦閱讀:
※近期在嘗試用bootstrap做移動端開發,發現了一些問題,這裡寫下自己的一些想法與疑問?
※如果原先沒有 HTML 和 CSS 的基礎,可以直接學 HTML5 和 CSS3 嗎?
TAG:CSS | CSS3MediaQuery |