本文由大漠根据David Walsh的《REM to PX Browser Function with Sass》所译,整个译文带有我们自己的理解与思想,如果译得不好或不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://davidwalsh.name/rem-px-browser-function-sass,以及作者相关信息
——作者:David Walsh
——译者:大漠
性能对于Web前端开发人员是必备的一项技能。CSS3和HTML5的新特性帮助我们改善了应用程序,但有时这些特性并没有得到很好的支持。这就是优雅降级。你想在新的浏览器中使用这些特性,但不能忽视对传统浏览器的支持。我最近开始在做一个新的项目,他必须要支持IE8。由于级联问题的嵌套,使用EM单位时不好把控,所以我决定在这个项目中开始使用有用的rem单位,这样更容易理解和维护。这种方法的主要问题是IE8不支持rem单位。最后,我们需要针对于这种情景创建一个后备方案:使用px
单位做降级处理。
性能和编码速度
你会发现,在网络上关于rem px mixin
有很多有用的话题和讨论,本文以这些文章做了一定的参考研究。大部分他们都是依赖于相同的技术,使用Sass mixin产生两次CSS属性,如:
SCSS
.header {
@include rempx(margin, 1rem 2rem);
}
编译出来的CSS:
CSS
.header {
margin:16px 32px; /* Fallback */
margin:1rem 2rem;
}
主要的问题是每使用这个mixin什么重复写CSS样式,这样整个CSS样式体重就会增长。这种技术有两个属性,而不是一个。第一个是用在不支持Rem单位的浏览器上。代码不怎么干净,但它是灵活的和易于维护。因为我们知道rem
单位在IE8中不被支持,但是,我们要是有两不同的样式表呢?
第二个问题是,使用上面的方法存在输入速度问题。每次你想添加一个新的CSS属性都得输入一次@include rempx(property,values)
,这不是最优秀的方法。
提供不同的样式表
我们的第一个目标是有两个分开的样式表:
main.css
文件用于标准浏览器,使用rem
单位main-ie.css
文件用于IE8浏览器,使用px
单位
这两个文件将会有完全相同的CSS内容,只是单位不同。
Nicolas Gallagher向我们展示了如何在标准浏览器和IE浏览器中加载不同的CSS文件,如下所示:
<!--[if (gt IE 8) | (IEMobile)]><!-->
<link rel="stylesheet" href="/css/main.css">
<!--<![endif]-->
<!--[if (lt IE 9) & (!IEMobile)]>
<link rel="stylesheet" href="/css/main-ie.css">
<![endif]-->
标准浏览器将下载main.css
文件,而IE浏览器下将下载main-ie.css
文件。这将确保客户端没有下载这两个CSS文件。
我们的第二个目标是使用@mixin
技术,所以我们只需要维护一个文件。
Sass解决文案
现在我们知道如何调用不同的样式表,我们现在需要生成两个CSS文件。这个时候我们需要把Sass引进来。为了使用这个示例尽量的简单,我不会给Sass使用一个特殊的文件结构,只是一群.scss
文件。这是我们示例中使用的结构:
- 一个空的
css
文件夹 - 一个
sass
文件夹,里面有四个文件:main.scss
、main-ie.scss
、_function.scss
和_module-example.scss
main.scss
// 配置
$px-only:false;
// 导入Sass的函数文件
@import "functions";
// 导入网站的模块文件
@import "module-example.scss";
main-ie.scss
// 配置
$px-only:true;
// 导入Sass的函数文件
@import "functions";
// 导入网站模块文件
@import "module-example.scss";
_function.scss
$pixelBase : 16; /* 1 */
@function parseInt($n) {
@return $n / ($n * 0 + 1); /* 2 */
}
@function u($values){ /* 3 */
$list: (); /* 4 */
@each $value in $values { /* 5 */
$unit : unit($value); /* 6 */
$val : parseInt($value); /* 2 */
@if ($px-only) and ($unit == 'rem') { /* 7 */
$list: append($list, ($val * $pixelBase) + px); /* 7 */
}
@else if($unit == 'px') or ($unit == 'rem'){ /* 8 */
$list: append($list, $value); /* 8 */
}
@else {
@warn 'There is no unit conversion for #{$unit}'; /* 9 */
}
}
@return $list(); /* 10 */
}
它是如何工作的?
变量$px-only
不仅仅是属于main.scss
或main-ie.scss
文件内。所有导入的文件都将影响$px-only
的值。当u()
函数加载时,main.scss
或者main-ie.scss
都指定了变量$px-only
的值。为了其他模块能正常工作,必须先导入这个Sass函数。
函数的解释
- 这个变量是指默认浏览器的字体大小和
1rem = 16px
。为了更好的维护,我们将此值存储在一个变量中,以便重用和容易修改。 - 这个函数返回一个数字的这符串,此函数由Hugo提供。
- 我们称为函数
u
,因为它更容易输入。u
也代表单位。这个函数接受一个参数,一个rem或者px值的数组。 - 我们定义一个新的列表,将保存新值。
$valuse
参数里的每个$value
值,通过测试当前的$value
值并将其存储在$list
数组内。- 这个Sass函数返回一个带单位的数字。在我们的例子中,是px或者rem。
- 首要条件:如果当前模式是像素模式和单位的值为rem,那么rem值将转换为px并把它们放到
$list
数组中。 - 第二个条件:如果单位是px或rem,我们只是将值入到列表中。
- 如果第一个和第二个条件失败,我们在Sass控制台上输入一个警告信息。
- 最后,我们返回整个简洁的CSS值列表。
使用
_module-example.scss
.main-header {
margin:u(1rem 2rem 20px 3rem);
padding-bottom:u(0.25rem);
font-size:u(0.875rem);
}
转译出来的CSS
main.css
.main-header {
margin: 1rem 2rem 20px 3rem;
padding-bottom: 0.25rem;
font-size: 0.875rem;
}
main-ie.csss
.main-header {
margin: 16px 32px 20px 48px;
padding-bottom: 4px;
font-size: 14px;
}
优点和缺点
优点
- 易于维护:一旦编辑代码,将生成两个不同的样式表
- 容易阅读:你最后的CSS是干净的,没有未使用的属性
- 降低文件大小:你最好的CSS是轻量级的
- 快速开发:快速输入
u()
来生成最终需要的单位
缺点
- 需要在
<head>
内使用条件样式引入正确的样式表
我希望得到您的反馈和分享你的任何想法,哪些地方可以改进!
扩展阅读
- Mixins for Rem Font Sizing
- The Ultimate PX/REM Mixin
- "Mobile First" CSS and Getting Sass to Help with Legacy IE
- Sass基础——Rem与Px的转换
- CSS3的REM设置字体大小
- 浏览器兼容之旅的第一站:如何创建条件样式
译者手语:整个翻译依照原文线路进行,并在翻译过程略加了个人对技术的理解。如果翻译有不对之处,还烦请同行朋友指点。谢谢!
如需转载,烦请注明出处:
英文原文:http://davidwalsh.name/rem-px-browser-function-sass
中文译文:http://www.w3cplus.com/preprocessor/rem-px-browser-function-sass.html