編碼的世界 / 優質文選 / 生涯

如何使用 PostCSS 在樣式表中處理圖片


2022年7月16日
-   

原文鏈接: https://css-tricks.com/images-in-postcss
本文摘自guestAleks HudochenkovAleks 在這裏給我們展示了PostCSS在前端開發中,所擅長的領域。 也就是,越少的去寫無用的CSS。你即將看到各種與處理圖像相關的PostCSS插件。最後,我打賭會提升在你心目中PostCSSCSS中的重要性。
我們平時也一直在用CSS處理圖片。但我們甚至可能沒有意識到,如果我們能替代手工操作,那很多事情就會容易很多 。我將為你展示很多POSTCSS的插件,尤其是在處理圖片上。
本文所介紹的每個插件在任何可以解析PostCSS語法- CSSSCSSLess ,以及使用PostCSS語法創建的插件中都可以使用。我不會介紹如何使用PostCSS本身,因為已經有一個很好的文章德魯Minns。
現在我們開始看案例吧。
圖片助手
postcss-assets插件幾乎是用於處理圖像的必備插件。它有很多功能。
內聯圖像
有時候,我們的樣式表內將圖像做成數據的URL方式是很有用的。減少了一個HTTP請求!
/* input.css */
div {
background: inline("images/logos/postcss.png");
}
/* output.css */
div {
background: url("data:image/png;base64,iVBORw0KGgoAAAAggg==");
}

計算尺寸
有時你需要元素的大小或根據你所使用的圖像的尺寸大小來決定背景尺寸。根據需要,這個插件可以使將尺寸測量並輸出。
/* input.css */
body {
width: width("images/foobar.png");
height: height("images/foobar.png");
background-size: size("images/foobar.png");
}
/* output.css */
body {
width: 320px;
height: 240px;
background-size: 320px 240px;
}

如果我們處理的是二倍圖,我們可以通過傳遞第二個參數輸出:
/* input.css */
body {
width: width("images/foobar.png", 2);
height: height("images/foobar.png", 2);
background-size: size("images/foobar.png", 2);
}
/* output.css */
body {
width: 160px;
height: 120px;
background-size: 160px 120px;
}

URL解析
該插件可以自動補全文件路徑。我們並不需要知道完整路徑圖像。只要知道文件名就可以了。
例如,我們有這樣的文件夾結構:
images/
logos/
postcss.png
input.css

我們傳這樣的一個參數。** 表示當前路徑下所有文件夾和文件進行搜索。
postcss([
require('postcss-assets')({
loadPaths: ['**']
})
])

/* input.css */
div {
background: resolve("postcss.png");
background: resolve("logos/postcss.png");
}
/* output.css */
div {
background: url("/images/logos/postcss.png");
background: url("/images/logos/postcss.png");
}

緩存無效
這個插件可以使圖片緩存失效。
postcss([
require('postcss-assets')({
cachebuster: true
})
])

/* input.css */
div {
background: url("images/logos/postcss.png");
}
/* output.css */
div {
background: url("images/logos/postcss.png?153bd5d59c8");
}

內聯和修改SVGs
幾乎每一個圖形我最近處理的都是SVG。這是處理任何像素密度圖像的一種格式。更妙的是,它的語法是文本,這意味著我們可以對其進行編輯,而不再需要用沉重的工具,如圖形編輯程序。
這裏有內聯SVG插件:postcss-inline-svg.。你可能會問,為什麼我們需要它,postcss-assets插件已經可以做到這一點了。原因是postcss-inline-svg有一個殺手鐧:它可以修改SVG
比如說在一個網站裏,我們在十個不同的地方使用了不同顏色的星形圖標。有很多方法可以做到這一點。我們可以使用一個inline SVG system<symbol></symbol> 或者 <use>。又或者,我們可以使用CSS背景屬性!
CSS中使用圖像有兩種方式。1)url(/path/to/image.jpg) 傳文件路徑 2)url(data:)數據URL。後者有時也被稱為“內聯”圖像,完成的圖像精靈的主要優勢之一:結合HTTP請求。有了postcss-inline-svg,我們可以這樣做(讓我們的CSS精靈圖像),單獨調整顏色:
/* input.css */
.starred {
background-image: svg-load("img/star.svg", fill=#f00);
}
.stargreen {
background-image: svg-load("img/star.svg", fill=#0f0, stroke=#abc);
}
/* output.css */
.starred {
background: url("data:image/svg+xml;charset=utf-8,%3Csvg fill='%23f00'%3E%3C/svg%3E");
}
.stargreen {
background: url("data:image/svg+xml;charset=utf-8,%3Csvg fill='%230f0' stroke='%23abc'%3E%3C/svg%3E");
}

你覺著,這樣輸出的CSS文件是太大了?輸出CSS將更大,是因為代碼重複,但它並沒有用Gzip壓縮的事!為了證明,我做了一個測試。我一個CSS文件寫了100個不同的選擇器,並在每規則集與隨機顏色的添加圖標內嵌填。像這樣:
.wibcsidpuaeqgbxvcjqq {
background: svg-load("images/star.svg", fill: #8c0);
}

我創建了一個副本,刪除了​​所有內嵌圖片的背景。以下是文件大小的對比結果:
| | Original size | Gzipped | With 100 images | 48500 bytes | 2560 bytes | With 1 image | 3158 bytes | 1817 bytes |
區別:2560 – 1817 = 743 bytes
差別不是很大!
這種方法的唯一區別是:沒有辦法為圖片添加動畫。例如,如果懸停的時候,顏色有過渡動畫,就實現不了。因為transition不能被應用到background-image屬性上。
這些插件相輔相成
實際案例:我們需要一個按鈕是一個圖標。按鈕內的圖像需要一個特定的圖像大小,也需要改變懸停顏色。只有一個源SVG文件。
描述:
<button type="button" class="delete">Delete</button>

在沒有任何幫助的情況下,我們可能會這樣做:
.delete {
box-sizing: content-box;
padding: 15px;
/* Values based on this particular image */
width: 26px;
height: 32px;
border: 1px solid #ef5350;
border-radius: 3px;
background: #fff url("images/trash.svg") 50% 50% no-repeat;
text-indent: -9999px;
}
.delete:hover {
border-color: #c62828;
/* Manually duplicate file and change things */
background-image: url("images/trash-hover.svg");
}

postcss-assets自動化後,我們可以這樣做:
postcss([ require('postcss-inline-svg')(), require('postcss-assets')()]);

.delete {
box-sizing: content-box;
padding: 15px;
width: width("images/trash.svg");
height: height("images/trash.svg");
border: 1px solid #ef5350;
border-radius: 3px;
background: #fff svg-load("images/trash.svg", fill=#ef5350) 50% 50% no-repeat;
text-indent: -9999px;
}
.delete:hover {
border-color: #c62828;
background-image: svg-load("images/trash.svg", fill=#c62828);
}

輸出:
.delete {
box-sizing: content-box;
padding: 15px;
width: 26px;
height: 32px;
border: 1px solid #ef5350;
border-radius: 3px;
background: #fff url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='26' height='32' viewBox='12 8 26 32' fill='%23ef5350'%3E%3Cpath d='M20 18h2v16h-2z'/%3E%3Cpath d='M24 18h2v16h-2z'/%3E%3Cpath d='M28 18h2v16h-2z'/%3E%3Cpath d='M12 12h26v2H12z'/%3E%3Cpath d='M30 12h-2v-1c0-.6-.4-1-1-1h-4c-.6 0-1 .4-1 1v1h-2v-1c0-1.7 1.3-3 3-3h4c1.7 0 3 1.3 3 3v1z'/%3E%3Cpath d='M31 40H19c-1.6 0-3-1.3-3.2-2.9l-1.8-24 2-.2 1.8 24c0 .6.6 1.1 1.2 1.1h12c.6 0 1.1-.5 1.2-1.1l1.8-24 2 .2-1.8 24C34 38.7 32.6 40 31 40z'/%3E%3C/svg%3E") 50% 50% no-repeat;
text-indent: -9999px;
}
.delete:hover {
border-color: #c62828;
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='26' height='32' viewBox='12 8 26 32' fill='%23c62828'%3E%3Cpath d='M20 18h2v16h-2z'/%3E%3Cpath d='M24 18h2v16h-2z'/%3E%3Cpath d='M28 18h2v16h-2z'/%3E%3Cpath d='M12 12h26v2H12z'/%3E%3Cpath d='M30 12h-2v-1c0-.6-.4-1-1-1h-4c-.6 0-1 .4-1 1v1h-2v-1c0-1.7 1.3-3 3-3h4c1.7 0 3 1.3 3 3v1z'/%3E%3Cpath d='M31 40H19c-1.6 0-3-1.3-3.2-2.9l-1.8-24 2-.2 1.8 24c0 .6.6 1.1 1.2 1.1h12c.6 0 1.1-.5 1.2-1.1l1.8-24 2 .2-1.8 24C34 38.7 32.6 40 31 40z'/%3E%3C/svg%3E");
}

如果圖像變化,你不需要做任何事情!postcss-assets會自動更新大小。需要更改顏色?如果您使用另一個插件或預處理器,你甚至可以定義成變量。
<iframe id="cp_embed_NNvGJP" src="//codepen.io/hudochenkov/embed/NNvGJP?height=300&amp;theme-id=1&amp;slug-hash=NNvGJP&amp;default-tab=css%2Cresult&amp;user=hudochenkov&amp;embed-version=2" scrolling="no" frameborder="0" height="300" allowtransparency="true" allowfullscreen="true" name="CodePen Embed" title="CodePen Embed" class="cp_embed_iframe " style="width: 100%; overflow: hidden;"></iframe>

精靈
目前你可能想用那種圖片精靈,所有的圖片組合在一起成一個較大的圖像。首先,眾所周知,手機解碼內嵌圖像比普通圖像稍微慢一些。
有很多的工具,可以生成圖片精靈。例如:grunt-spritesmith。 這些工具都是很強大的,不是特別容易或方便安裝。就像grunt-spritesmith這個,你需要了解它的模板引擎是如何工作的。
但postcss-sprites就方便的多。這是它的工作原理:
/* input.css */
.comment {
background-image: url("images/sprite/ico-comment.png");
}
.bubble {
background-image: url("images/sprite/ico-bubble.png");
}
/* output.css */
.comment {
background-image: url("images/sprite.png");
background-position: 0 0;
}
.bubble {
background-image: url("images/sprite.png");
background-position: 0 -50px;
}

它查找在CSS中每個圖像(可能是過濾),創建一個Sprite,並輸出正確的背景位置到那裏。
為高清屏處理圖像精靈
盡管postcss-sprites支持高清屏圖片,它並不完全給你處理過程。例如,它不給你媒體查詢在高清屏實際使用的那些圖像。這個問題可以用另一個PostCSS插件來解決。這是PostCSS生態之美 - 有許多插件,每個只做一項工作,你可以結合他們去解決更複雜的問題。
有一個postcss-at2x插件,它增加了高清屏幕的媒體查詢。讓我們結合這些插件生成普通屏和高清屏精靈。
postcss([
require('postcss-at2x')(),
require('postcss-sprites').default({
retina: true
})
]);

/* input.css */
.circle {
background-image: url("images/circle.png") at-2x;
}
.square {
background-image: url("images/square.png") at-2x;
}
/* output.css */
.circle {
background-image: url("sprite.png");
background-position: 0px 0px;
}
.square {
background-image: url("sprite.png");
background-position: -25px 0px;
}
@media (minmoz-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3/2), (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5), (min-resolution: 144dpi), (min-resolution: 1.5dppx) {
.circle {
background-image: url("sprite.@2x.png");
background-position: 0px 0px;
background-size: 50px 25px;
}
}
@media (minmoz-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3/2), (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5), (min-resolution: 144dpi), (min-resolution: 1.5dppx) {
.square {
background-image: url("sprite.@2x.png");
background-position: -25px 0px;
background-size: 50px 25px;
}
}

創建動態圖片
有時候我們需要非常簡單的圖像(如幾何形狀),但仍然發現自己打開一個圖形編輯器,創建圖像,導入它,把它在正確的地方,對其進行優化,並在CSS中使用它。那我們能不能在CSS裏創建簡單的圖片?我敢打賭,你一定會說:我們可以!
postcss-write-svg可以讓你在CSS裏創建簡單的SVG圖像。剛剛描述SVG元素,它會被內聯作為background-image
/* input.css */
@svg square {
@rect {
fill: var(color, black);
width: 100%;
height: 100%;
}
@polygon {
fill: green;
points: 50,100 0,0 0,100;
}
}
#example {
background: white svg(square param(color #00b1ff));
}
/* output.css */
#example {
background: white url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%2300b1ff' width='100%25' height='100%25'/%3E%3Cpolygon fill='green' points='50%2C100 0%2C0 0%2C100'/%3E%3C/svg%3E");
}

還有其他的插件,只用CSS屬性,實現圓和三角形。你也可以用CSS直接實現三角形,但它的不全面,當你想要做不同類型的三角形變得更難了。postcss-triangle允許您輕松地創建等腰三角形,等腰和等邊三角形。
/* input.css */
.isosceles-triangle {
triangle: pointing-right;
width: 150px;
height: 115px;
background-color: red;
}
.right-isosceles-triangle {
triangle: right-iso pointing-down;
width: 250px;
background-color: red;
}
.equilateral-triangle {
triangle: equilateral pointing-up;
height: 100px;
background-color: red;
}
/* output.css */
.isosceles-triangle {
width: 0;
height: 0;
border-style: solid;
border-color: transparent;
border-width: 57.5px 0 57.5px 150px;
border-left-color: red;
}
.right-isosceles-triangle {
width: 0;
height: 0;
border-style: solid;
border-color: transparent;
border-width: 125px 125px 0;
border-top-color: red;
}
.equilateral-triangle {
width: 0;
height: 0;
border-style: solid;
border-color: transparent;
border-width: 0 57.73503px 100px;
border-bottom-color: red;
}

圈更容易,postcss-circle可以節省你的幾行代碼,並增強可讀性。
/* input.css */
.circle {
circle: 100px red;
}
/* output.css */
.circle {
border-radius: 50%;
width: 100px;
height: 100px;
background-color: red;
}

緩存無效
假設你需要更新樣式表裏的圖像鏈接。我們可能會遇到一個問題,如果我們使用的緩存日期還要很久才到期,用戶的瀏覽器該圖像是掛在緩存中的。解決辦法是,強迫用戶的瀏覽器去下載的新版本(緩存無效)。有兩種方法可以做到這一點:改變文件名或更改URL。更改文件名有很多要求,但改變URL參數是容易的。
以下是postcss-urlrev如何改變URL
/* input.css */
.foo {
background: url("images/test.png") 0 0 no-repeat;
}
/* output.css */
.foo {
background: url("images/test.png?v=e19ac7dee6") 0 0 no-repeat;
}

這個任務還可以用 postcss-cachebuster and postcss-assets
實用工具
PostCSS插件可以幫助優化樣式表。例如postcss-svgo可以用 SVGO優化內聯SVG,最好的SVG優化工具。
如果您仍然需要支持不支持SVG的瀏覽器,postcss-svg-fallback可以幫助你。這個插件在你的CSSSVG回退PNG(包括內聯,和外聯鏈接URL() ),為舊瀏覽器增加額外的規則。
內聯圖像可能使CSS臃腫,但有一個解決方案:postcss-data-packer可以提取 Data URL到一個單獨的文件。然後,您就可以異步加載該文件,以減少網頁加載時間。
結論
在沒有PostCSS之前,我們做了很多繁瑣的手工工作,複制和粘貼的事情,或者手工計算。現在,我們可以使用一些PostCSS插件,使我們的電腦為我們做這些事情。它加快了我們的工作,使我們成為更快樂的人。

熱門文章