成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

CSS > 關(guān)于雪碧圖預(yù)處理和后處理方案的討論

hyuan / 908人閱讀

摘要:預(yù)處理方案代表和預(yù)處理方案是預(yù)先指定需要生成的雪碧圖切片元素,由工具合成后,得到相應(yīng)的雪碧圖和數(shù)據(jù)文件,開發(fā)中將二者投入使用。預(yù)處理方案一般以頁(yè)面為單元組織雪碧圖。結(jié)語(yǔ)關(guān)于雪碧圖的處理方案的討論就到此結(jié)束了。

廣告:SF 里弄了個(gè) CSS 小圈子,歡迎一起來(lái)討論問(wèn)題

前端小圖標(biāo)處理方案眾多,本文主要介紹基于雪碧圖的處理方案,分析雪碧圖的預(yù)處理和后處理模式的得與失,以及在項(xiàng)目中通常會(huì)遇到的問(wèn)題以及解決方案。其他小圖標(biāo)處理方案未在此文探討之列。

此外,本文更多的是理論性分析,具體技術(shù)實(shí)現(xiàn)不作深入解釋。如有疑問(wèn),歡迎到上述小圈子一起討論!

討論的起點(diǎn)是工程工具 Gulp/Webpack 上的集成方案(手動(dòng)拼合雪碧圖的做法已經(jīng)作古了)。

1. 預(yù)處理方案

代表:gulp.spritesmith 和 webpack-spritesmith

預(yù)處理方案是預(yù)先指定需要生成的雪碧圖切片元素,由工具合成后,得到相應(yīng)的雪碧圖和數(shù)據(jù) (S)CSS 文件,開發(fā)中將二者投入使用。

數(shù)據(jù)文件內(nèi)容通常是可定義的,我們可以自定義模板或者內(nèi)容生成函數(shù)(怎么寫這里就不探討了)。借助 SCSS 等 CSS 預(yù)編譯語(yǔ)言的威力,如何使用雪碧圖數(shù)據(jù)就極具便利性。

注意,下面的 SCSS 代碼都是寫的模板函數(shù)生成的內(nèi)容,模板函數(shù)具體怎么寫不在本文探討范圍內(nèi)。

最簡(jiǎn)單的,我們可以直接生成類(如),如:

.icon-home {
    width: 12px;
    height: 12px;
    background: url(sprite.png) -56px -48px no-repeat;
}

這樣在 HTML 結(jié)構(gòu)中可以直接使用。但如果切片元素眾多,每一條規(guī)則都要有多帶帶的 background 屬性的話,未免太冗長(zhǎng),稍微改進(jìn)下,把公共的 background-image 屬性提取出來(lái)(高清模式下還有 background-size,以下從簡(jiǎn)討論),可以生成這樣的內(nèi)容:

.icon-home {
    width: 12px;
    height: 12px;
    background-position:-56px -48px;
}
.icon-back {
    width: 18px;
    height: 20px;
    background-position: -10px 0;
}
.icon-home,
.icon-back {
    background-image: url(sprite.png);
}

但是,如果有的類沒(méi)用到,白白生成一個(gè)類豈不是很沒(méi)必要?或者我們不想使用 .icon-home 這樣子的類名,那我們用 SCSS 占位符可以解決這個(gè)問(wèn)題:

%-icon-home {
    width: 12px;
    height: 12px;
    background-position:-56px -48px;
}

%-icon-home,
%-icon-back {
    background-image: url(sprite.png);
    background-repeat: no-repeat;
}

然后需要用到的時(shí)候,再繼承這個(gè)占位符:

.head-home {
    @extend %-icon-home;
}

這樣,我們就能用上自定義的類名,并節(jié)省 CSS。

但如果遇到狀態(tài)性變化怎么辦?比如 :hover 時(shí)小圖標(biāo)變紅,這時(shí)候其實(shí)除了 background-position 改變外,其他數(shù)據(jù)是沒(méi)有變化的。

按上述方案,我們的寫法會(huì)是:

.head-home {
    @extend %-icon-home;
    
    &:hover {
        @extend %-icon-home_hover;
    }
}

生成的最終 CSS 是:

.head-home {
    width: 12px;
    height: 12px;
    background-position:-56px -48px;
}
.head-home:hover {
    width: 12px;
    height: 12px;
    background-position: 0 0;
}
.head-home,
.head-home:hover {
    background-image: url(sprite.png);
}

思索發(fā)現(xiàn),本質(zhì)上占位符只是包含了圖片信息,那我們換一種更加高端點(diǎn)的寫法:

// 把雪碧圖數(shù)據(jù)保存為一個(gè) SCSS Map 數(shù)據(jù)
$__sprite__: (
    "home": (
        "width": 12,
        "height": 12,
        "x": 56,
        "y": 48,
        "url": "sprite.png"
    ),
    "home_hover": (
        "width": 12,
        "height": 12,
        "x": 0,
        "y": 0,
        "url": "sprite.png"
    )
);

// 公共部分依然占位符
%-sprite-common {
    background-image: url(sprite.png);
}

// 輸出 background-position
@mixin sprite-position($name) {
    $data: map-get($__sprite__, $name);
    $x: map-get($data, "x");
    $y: map-get($data, "y");
    background-position: -#{$x}px -#{$y}px;
}

// 輸出其他切片元素私有數(shù)據(jù)
@mixin sprite-item($name) {
    // 繼承公共樣式
    @extend %-sprite-common;
    // 設(shè)置獨(dú)有樣式
    @include sprite-position($name);

    $data: map-get($__sprite__, $name);
    $width: map-get($data, "width");
    width: unquote($width + "px");
    height: unquote(map-get($data, "height") + "px");
}

生成出以上 SCSS 模板后,我們就可以這樣使用雪碧圖了:

.head-home {
    @include sprite-item("home");
    
    &:hover {
        @include sprite-position("home_hover");
    }
}

生成出來(lái)的效果類似于:

.head-home {
  background-image: url(sprite.png);
}
.head-home {
  background-position: -56px -48px;
  width: 12px;
  height: 12px;
}
.head-home:hover {
  background-position: -0px -0px;
}

這樣,在 :hover 態(tài)下生成的 CSS 規(guī)則只會(huì)包含必要的變動(dòng)。

總結(jié)起來(lái),預(yù)處理模式的優(yōu)點(diǎn)在于,通過(guò)自定義 CSS 數(shù)據(jù)文件,可以隨心所欲地使用已經(jīng)生成出來(lái)的雪碧圖信息。

然而,在預(yù)處理模式下,開發(fā)的頁(yè)面依賴的是生成后的雪碧圖,而不是合并前的雪碧圖切片元素,隨之帶來(lái)的問(wèn)題是:沒(méi)辦法實(shí)現(xiàn)雪碧圖的按需合并。

預(yù)處理方案一般以頁(yè)面為單元組織雪碧圖。思考這樣的問(wèn)題:如果一張雪碧圖對(duì)應(yīng)一個(gè)頁(yè)面,那各頁(yè)面的公共組件使用的雪碧圖,是每個(gè)頁(yè)面各一份副本,還是只保存一次切片元素,把通用的抽成一張公共雪碧圖呢?

如果各存一份,公共組件的切片元素就得保存到多個(gè)文件夾,每次更新、刪除、添加的時(shí)候得同步多處。如果管理不當(dāng),就會(huì)導(dǎo)致頁(yè)面元素不同、廢棄的切片仍被合并以及遺漏等問(wèn)題。(以 CSS 文件為單元組織雪碧也會(huì)遇到類似的情況。)

如果抽成一張公共雪碧圖,假設(shè)一個(gè)最簡(jiǎn)單場(chǎng)景:有 ABC 三個(gè)頁(yè)面,其中 AB 頁(yè)面有一個(gè)共同的切片元素 ab.png ,BC 頁(yè)面也有一個(gè)共同的切片元素 bc.png。這兩張切片元素都放進(jìn)了 spr_common.png 中。由于靜態(tài)資源管理需要,我們?cè)诖虬臅r(shí)候統(tǒng)一給資源加上簽名,也就成了 spr_common.de353d.png?,F(xiàn)在,需要更新 ab.png 這張切片,進(jìn)而變成了 spr_common.5ef25d.png。而 C 頁(yè)面的樣式里包含了這張雪碧圖,盡管自身沒(méi)有任何變動(dòng),但由于公共雪碧圖變了,C 頁(yè)面的 CSS 也必須跟著變化。即,公共雪碧圖會(huì)帶來(lái)耦合問(wèn)題,局部頁(yè)面更新會(huì)造成其他頁(yè)面不必要的跟隨變化。

后處理方案則解決了這些問(wèn)題。

2. 后處理方案

典型:postcss-sprites

后處理方案通過(guò)對(duì)已經(jīng)生成的 CSS 文件進(jìn)行分析,將其中包含切片元素的 backgroundbackground-image 作為依賴收集,合并成雪碧圖后再將相關(guān)參數(shù)替換。

如上述典型工具,生成前是:

.comment {
    background: url(images/sprite/ico-comment.png) no-repeat 0 0;
}
.bubble {
    background: url(images/sprite/ico-bubble.png) no-repeat 0 0;
}

生成后是:

.comment {
    background-image: url(images/sprite.png);
    background-position: 0 0;
}
.bubble {
    background-image: url(images/sprite.png);
    background-position: 0 -50px;
}

如此一來(lái),CSS 中有哪些切片元素就合并哪些,不會(huì)把沒(méi)有用到的切片也合并進(jìn)去。即一張 CSS 樣式表有一張專門的雪碧圖。

不過(guò),正如上面所看到的,后處理模式解決了按需合并的問(wèn)題,也不會(huì)造成頁(yè)面/組件間雪碧圖的耦合,但卻喪失了預(yù)處理方案中直接利用數(shù)據(jù)的便捷性。在預(yù)處理方案中,我們不用人工地去衡量切片元素的寬高,而是讓 SCSS 自動(dòng)輸出,后處理方案卻做不到這一點(diǎn)。

3. 預(yù)處理和后處理相結(jié)合

既要能像預(yù)處理那樣不用人工的地去量切片,又要像后處理那樣實(shí)現(xiàn)按需的合并,這就是我理想的開發(fā)模式。

基于以上探索,我寫了個(gè)工具:postcss-sprite-property 來(lái)實(shí)現(xiàn)二者的平衡。做法是:

區(qū)分開發(fā)環(huán)境和生產(chǎn)環(huán)境。在開發(fā)環(huán)境中,不合并雪碧圖,直接使用切片元素預(yù)覽;生產(chǎn)環(huán)境中,為每一張樣式表內(nèi)的切片合并雪碧圖

利用 node-sass 所支持的自定義函數(shù)功能,為 SCSS 注入 image-widthimage-height 兩個(gè)自定義函數(shù),用來(lái)查詢圖片寬高數(shù)據(jù)

使用 @sprite-item@sprite-position 兩個(gè)混合,優(yōu)雅地定義一張雪碧圖元素

盡量為公共屬性生成一個(gè)公共的規(guī)則

Webpack 中,開發(fā)時(shí)不拼合雪碧圖,讓切片本身作為組件依賴;打包時(shí)合并雪碧圖并剔除切片元素

來(lái)看一個(gè)實(shí)例:

我們把如下樣式放進(jìn)我們的公共樣式庫(kù)中:

// 使用雪碧圖
// 以圖片名作為參數(shù)
@mixin sprite-item($name) {
    // 統(tǒng)一一個(gè)路徑存放切片元素
    // 這樣就能得到圖片的實(shí)際地址了
    $url: "../asset/sprite/#{$name}.png";
    // 注入的 `image-width` 函數(shù)可以幫我們查詢圖片寬度
    $width: image-width($url);
    @if (null == $width) {
        @warn "Sprite element `#{$name}` not found!";
    } @else {
        // 獲取圖片高度
        $height: image-height($url);
        // 自動(dòng)書寫 `width` 和 `height`
        width: $width;
        height: $height;
        // 定義背景
        // 開發(fā)模式下直接按輸出預(yù)覽
        // 生產(chǎn)環(huán)境下將其替換為雪碧圖的數(shù)據(jù)
        background: url($url) 0 0 / #{$width} #{$height} no-repeat;
    }
}
// 改變雪碧圖 `background-position`
// 和上面的 `sprite-item` 區(qū)別僅在于
// 這個(gè)混合不輸出 `width` 和 `height`
@mixin sprite-position($name) {
    $url: "../asset/sprite/#{$name}.png";
    $width: image-width($url);
    @if (null == $width) {
        @warn "Sprite element `#{$name}` not found!";
    } @else {
        $height: image-height($url);
        background: url($url) 0 0 / #{$width} #{$height} no-repeat;
    }
}

現(xiàn)在,具體項(xiàng)目里就能這樣使用了:

.home-head {
    @include sprite-item("pageA/home");
    
    &:hover {
        @include sprite-position("pageA/home_hover");
    }
}

.home-back {
    @include sprite-item("pageB/back");
}

開發(fā)階段,沒(méi)有合成雪碧圖,直接使用切片預(yù)覽,所以效果是這樣的:

.home-head {
  width: 12px;
  height: 12px;
  background: url("../asset/sprite/pageA/home.png") 0 0 / 12px 12px no-repeat;
}
.home-head:hover {
  background: url("../asset/sprite/pageA/home_hover.png") 0 0 / 12px 12px no-repeat;
}

.home-back {
  width: 18px;
  height: 20px;
  background: url("../asset/sprite/pageB/back.png") 0 0 / 18px 20px no-repeat;
}

最后發(fā)布生成的樣式則是這樣的:

.home-head {
    width: 12px;
    height: 12px;
    background-position: -56px -48px;
}
.home-head:hover {
    background-position: 0 0;
}
.home-back {
    width: 18px;
    height: 20px;
    background-position: -10px 0;
}
.home-head,
.home-head:hover,
.home-back {
    background-image: url(sprite.png);
}

當(dāng)然,如上所示,.home-head.home-head:hover 都在最后的公共規(guī)則中。最理想的當(dāng)然是沒(méi)有更好,但作為一個(gè)平衡方案,這仍是可接受的。

更具體的用法和更多的功能請(qǐng)參看 Github:https://github.com/HaoyCn/pos...

4. REM 布局中雪碧圖的錯(cuò)位問(wèn)題

這個(gè)算是雪碧圖的硬傷。其他小圖標(biāo)方案不會(huì)有這個(gè)問(wèn)題。REM 布局里雪碧圖錯(cuò)位幾乎是不可避免的,在安卓下錯(cuò)位甚至可以達(dá)到 2px 左右。我也總結(jié)出一個(gè) CSS 兜錯(cuò)方案:

background-position 使用百分比單位

給雪碧圖增加透明內(nèi)邊距,如 spritesmith 工具設(shè)置 padding: 8

增加 1-2px 的容錯(cuò)區(qū)域,概要代碼如下:

%-sprite {
    // 錯(cuò)位時(shí)的容錯(cuò)區(qū)域
    padding: 1px;
    // 從內(nèi)容區(qū)開始繪制背景
    background-origin: content-box;
    // 在內(nèi)邊距盒外裁切背景
    background-clip: padding-box;
}

利用以上三個(gè)屬性的組合來(lái)騰出容錯(cuò)的空間。

4. 結(jié)語(yǔ)

關(guān)于雪碧圖的處理方案的討論就到此結(jié)束了。待 HTTP2 普及之后,也就沒(méi)有雪碧圖什么事了,而現(xiàn)在仍有其存在的必要性。

處理小圖標(biāo)還有其他的方案,如 Iconfont 和 Svg-Sprite??傊疀](méi)有最好的,只有最適合的。

感謝閱讀。歡迎來(lái)文章頂部的小圈子一起討論!

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/116621.html

相關(guān)文章

  • 2017-09-28 前端日?qǐng)?bào)

    摘要:前端日?qǐng)?bào)精選等新方法簡(jiǎn)介寫作建議和性能優(yōu)化小結(jié)前端面試之篇第期關(guān)于雪碧圖預(yù)處理和后處理方案的討論你的網(wǎng)站可以一鍵變色嗎中文譯內(nèi)存管理碰撞課程掘金阿里前端面試點(diǎn)目標(biāo),想成為一名好的前端工程師那些事函數(shù)能干啥如何在日常搬磚中使用最全, 2017-09-28 前端日?qǐng)?bào) 精選 before(),after(),prepend(),append()等新DOM方法簡(jiǎn)介css寫作建議和性能優(yōu)化小結(jié)前...

    xuhong 評(píng)論0 收藏0
  • 淺談 CSS Sprites 雪碧應(yīng)用

    摘要:編寫配置文件,以下是關(guān)鍵配置代碼雪碧圖合并輸出到文件參數(shù)執(zhí)行目錄參數(shù)生成的和圖片的文件名之所以推薦,是因?yàn)榉浅5撵`活,看懂模塊的可以根據(jù)你的項(xiàng)目情況編寫對(duì)應(yīng)的配置文件。 showImg(https://segmentfault.com/img/bVGpAw?w=518&h=156); 前言 網(wǎng)站開發(fā)90%會(huì)用到小圖標(biāo), 多小圖標(biāo)調(diào)用顯示是前端開發(fā)常見(jiàn)的問(wèn)題;目前小圖標(biāo)顯示常見(jiàn)有兩種方式...

    MkkHou 評(píng)論0 收藏0
  • Css Sprite(雪碧、精靈)<像拼合技術(shù)&gt;

    摘要:一精靈圖使用場(chǎng)景二優(yōu)點(diǎn)減少圖片的字節(jié)。減少網(wǎng)頁(yè)的請(qǐng)求,從而大大的提高頁(yè)面的性能。解決了網(wǎng)頁(yè)設(shè)計(jì)師在圖片命名上的困擾,只需對(duì)一張集合的圖片上命名就可以了,不需要對(duì)每一個(gè)小元素進(jìn)行命名,從而提高了網(wǎng)頁(yè)的制作效率。 一、精靈圖使用場(chǎng)景: showImg(https://segmentfault.com/img/bVbd4Ex?w=927&h=389); 二、Css Sprite(優(yōu)點(diǎn)) 減...

    Youngs 評(píng)論0 收藏0
  • Css Sprite(雪碧、精靈)<像拼合技術(shù)&gt;

    摘要:一精靈圖使用場(chǎng)景二優(yōu)點(diǎn)減少圖片的字節(jié)。減少網(wǎng)頁(yè)的請(qǐng)求,從而大大的提高頁(yè)面的性能。解決了網(wǎng)頁(yè)設(shè)計(jì)師在圖片命名上的困擾,只需對(duì)一張集合的圖片上命名就可以了,不需要對(duì)每一個(gè)小元素進(jìn)行命名,從而提高了網(wǎng)頁(yè)的制作效率。 一、精靈圖使用場(chǎng)景: showImg(https://segmentfault.com/img/bVbd4Ex?w=927&h=389); 二、Css Sprite(優(yōu)點(diǎn)) 減...

    n7then 評(píng)論0 收藏0
  • Css Sprite(雪碧、精靈)<像拼合技術(shù)&gt;

    摘要:一精靈圖使用場(chǎng)景二優(yōu)點(diǎn)減少圖片的字節(jié)。減少網(wǎng)頁(yè)的請(qǐng)求,從而大大的提高頁(yè)面的性能。解決了網(wǎng)頁(yè)設(shè)計(jì)師在圖片命名上的困擾,只需對(duì)一張集合的圖片上命名就可以了,不需要對(duì)每一個(gè)小元素進(jìn)行命名,從而提高了網(wǎng)頁(yè)的制作效率。一、精靈圖使用場(chǎng)景: 二、Css Sprite(優(yōu)點(diǎn)) 減少圖片的字節(jié)。 減少網(wǎng)頁(yè)的http請(qǐng)求,從而大大的提高頁(yè)面的性能。 解決了網(wǎng)頁(yè)設(shè)計(jì)師在圖片命名上的困擾,只需對(duì)一張集合的圖片...

    zhigoo 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<