前言
一般而言,我們用CSS設置字體大小和元素長寬是這樣的:
.name {
? ? font-size: 16px;
? ? width: 100px;
}
(由于字體大小和元素長寬的原理一樣,下面統一討論字體。)
本來一切好好的,但到了不同的屏幕上效果差別就很大了。假設你的設計稿是按照iphone6的尺寸來標注,那在iphone6 plus上,由于你的字體還是一樣大,所以在iphone6 plus上看起來會小一點。如果屏幕尺寸再大,則會再小,效果和UI設計的看起來就不太一樣了。特別是某些固定尺寸的元素,看起來就會很奇怪。
原始的做法
更好的設計是,在iphone6 plus上把iphone6的設計放大。
比如6的屏幕寬度是375,字體大小為16,而6p的寬度為414,那字體就應該是414/375*16=17.6px。也就是根據兩者之間的比例來放大字體。然而,屏幕并不只有6和6p,也許還要適配其他不同尺寸的屏幕。而且如果每種適配都需要重新修改字體樣式的話,工作量就太大了。
當然,最簡單的做法就是在head里面設置initial-scale,根據不同屏幕來決定縮放的值。但是,這種做法有個不好的地方,就是它本身是一個放大功能,字體和圖片被放大之后會變模糊,對于追求比較高的前端頁面來說可能難以接受。
還有另一個方面,IE并不能縮放px字體的大小。如果在IE上進行了縮放,那字體還是那么大。
三種不同的單位
接下來介紹三種不同的長度單位(CSS Units)。
px
px,就是pixels。翻譯為像素并不十分精確,可能翻譯為點更好,但是已經有另一個單位pt(points),所以,也只能繼續翻譯為像素了。這里的px不同于一般的像素,它的特性就是在不同的設備上代表的大小不同。在低清屏上,1px就代表1像素,而在高清屏上,比如iphone 6上則代表2個像素,而在iphone6 plus上則代表3個像素,因為6p是3倍的高清屏。所以,當設計稿給出iphone 6的尺寸時,你必須把它除以2,寫成px,才能在移動設備上正確地顯示尺寸。
em
Relative to the font-size of the element (2em means 2 times the size of the current font)
意思就是,某個元素的字體大小與它的父元素的相對單位。
這個很好理解,比如父元素A,擁有子元素B。假設A字體設置為1em,B設置為2em,而1em=16px,那最后A的字體是16px,B的字體是32px。而B又擁有子元素C,C設置為0.5em,則C的字體為32px*0.5=16px。這里的32px是B元素的字體大小。
rem
Relative to font-size of the root element
和em類似,不同的是,rem相對的是根元素的字體大小。
假設html的字體為16px,擁有A元素,字體為2rem,那A的字體就是32px。假設A擁有B,而B為2rem,那B的字體也為32px,因為它相對的是html,而不是A。假設B的字體為2em,那B就是64px了。
再來看看rem的兼容性,也是相當不錯的。
利弊
使用px的話,基本上頁面元素的字體大小都是固定的,甚至修改起來也很麻煩。而用em就能解決適配的問題,但壞處是每個大小都是相對父元素的,一旦某個節點有所變動,很容易造成其他節點也要變動,而且本身不是特別直觀,單看某個節點是1em并不能得到它的具體大小。而rem基本是最優方案了,既可以很好地適配,也可以直觀地修改。
下面會介紹將rem方案應用到項目里的方法。
REM方案
用px寫CSS,構建時替換為rem
并不提倡直接在代碼里寫rem,因為你并不知道你當前的1rem代表多少。所以最好的方式是代碼里直接用px描述字體和大小,并在后期將其轉化為rem。
適配不同屏幕的方案
針對6和6p這些不同的屏幕,我們可以使用media query來定義root element的字體大小,這樣就能輕松做到根據不同屏幕展現同樣的視覺效果。
構建方案
構建方案很簡單,分為兩步,一個針對.css文件,另一個針對html,包括html中的style標簽以及html中的inline-style。
處理普通的css文件
目前比較好用的處理css文件的插件是gulp-postcss和postcss-pxtorem配合使用,比如像這樣:
var postcss = require('gulp-postcss');
var pxtorem = require('postcss-pxtorem');
? ? var options = {
? ? rootValue: 10,
? ? propWhiteList: [],
? ? minPixelValue: 1};
gulp.src('www/*.css').pipe(postcss([pxtorem(options)])).pipe(gulp.dest('build/'));
postcss-pxtorem提供了不同的參數設置來轉化css中的px。比如rootValue用來定義轉化時根元素的值,mediaQuery決定是否轉換media query中的大小,minPixelValue用來定義最小的不需轉化的px值(比如可以不轉化1px的大?。H绻胍刂颇承┰氐拇笮〔槐晦D化,可以通過8PX這樣的大寫方式來解決,因為pxtorem不會轉化這部分css,而瀏覽器卻能夠識別。此外還有白名單、黑名單、小數點位數、是否替換原來的px等參數可供設置。
處理html中的css
這部分比較有意思。微信提供了posthtml-px2rem的方案來解決inline-style的問題,但不處理html中的style標簽,因為他們已經把css獨立出去解決。但是,不少框架還會在文件中使用style標簽,如果只需要處理inline-style的話也可以用這個方案。
更通用一點的處理方式是gulp-posthtml、posthtml-postcss、postcss-pxtorem,流程基本就是處理html中的css中的px,這里會統一把inline-style一起解決,所以是個不錯的選擇。
var posthtml = require('gulp-posthtml');
var posthtmlcss = require('posthtml-postcss');
var pxtorem = require('postcss-pxtorem');
var options = {};
gulp.src('www/*.html').pipe(posthtml([posthtmlcss([pxtorem(options)])])).pipe(gulp.dest('build/'));
這里使用了和上面同樣的postcss-pxtorem,參數option也是一樣的。
完結
我們在代碼中使用px并以統一的規范來實現界面,根據不同的屏幕定制不同的基礎字體大小,并在構建時將px轉為rem讓其適配不同的屏幕。
其實一般我們都需要額外定制html標簽的字體大小,不讓其轉換,這樣會更顯得直觀一點。