以下是 Roman Rudenko 的客座文章,他是 Mobify 的疯狂科学家,他负责理解浏览器为何出现错误行为以及如何让它们正常运行。Roman 不编码的时候,会学习骑摩托车,避免撞到太多固体物体。
许多网页设计师和开发者都熟悉 CSS rem
长度 单位。但是,您可能不知道它还有几个方便的备用用途。在这篇文章中,我将介绍如何使用 CSS rem
单位来缩放特定的页面元素,而不会影响其他元素。我还将讨论如何使用它来替代支持不足的 vw
(视窗宽度)单位。
对于不熟悉 rem
单位(代表“root em”)的读者来说,它提供了一种方法,可以将长度指定为根元素字体大小的几分之几。实际上,这几乎总是意味着 <html>
元素的字体大小。rem
最明显的用途是替换 em
,以防止内部元素字体大小因外部元素而改变,从而避免经典的嵌套 em
缩放问题。但 rem
有效地充当自定义可调单位,因此它对于其他用途也很有用。
首先,让我们看看 rem
的工作原理以及它与 em
单位的不同之处。em
值是根据当前元素的 font-size
计算的,因此使用它来设置大小的框将随着元素或其祖先的字体大小调整而相应缩放。同时,rem
定义为根元素的 font-size
。因此,所有对 rem
的引用都将返回相同的值,而不管祖先字体大小如何。实际上,rem
是一个文档范围的 CSS 变量。如今,浏览器对 rem
的支持相当不错。它在桌面上的支持有限,因为 IE8 不支持它,但常见的移动设备和平板电脑浏览器对其支持要好得多。
Rem 可以用于其典型的字体大小职责。当标记以复杂的方式嵌套时,使用 em
值的 font-size
声明可能会意外地累加,而 rem
是解决这些问题的不错选择。但是,rem
还有一些其他有趣的用途。
缩放文档元素
您可以使用 rem
来缩放文档中的某些元素,而保持其他元素不变。在这个例子中,辅助页面内容(幻灯片控件、插图名称、帖子元数据)的 font-size
是通过 rem
控制的,但主要内容保持以像素为单位的大小。
Check out this Pen!
当点击红色大小调整链接之一时,一小段 JavaScript 会调整 <html>
font-size
,重新调整辅助元素的大小,而不会改变主要元素的大小。
这种大小调整方式对于用户驱动的定制很有用,或者可以适应需要辅助元素更容易触摸(平板电脑)或可见(电视)的情况。如果没有 rem
,则需要单独调整每个可调整元素的大小。
/* States */
html.secondary-12px { font-size: 12px; }
html.secondary-14px { font-size: 14px; }
html.secondary-16px { font-size: 16px; }
/* Primary content stays fixed */
body { font-size: 18px; }
/* Secondary content scales */
.post-inner .meta { font-size: 1rem; }
.figure .title { font-size: 1rem; }
.slideshow .controls { font-size: 1.25rem; }
.slideshow .controls a { padding: 0 0.5rem; }
替代 vw
CSS vw 单位 定义为视窗宽度的 1/100。此单位对于避免宽度计算中的累加很有用,就像 rem
避免 font-size
乘数累加一样。它也可以用于非宽度属性,例如 font-size
(将文本的固定片段拟合到百分比大小的框中)或高度(保留元素的纵横比)。对 vw 的支持 仍然参差不齐。因此,我们可以改用 rem,并动态重新计算 <html>
的字体大小以匹配 vw
单位的大小。
让我们来看看此解决方法的示例实现(调整浏览器大小以查看调整)。
Check out this Pen!
body { font-size: 12px; margin: 0; padding: 0;}
.one, .two {
border: solid #666;
border-width: 10px; border-width: 0.01rem; /* 1vw */
border-radius: 30px; border-radius: 0.03rem; /* 3vw */
font-size: 20px; font-size: 0.02rem; /* 2vw */
padding: 20px; padding: 0.02rem; /* 2vw */
}
在这里,<body>
元素的 font-size
规则使内容免受 <html>
font-size
更改的影响。不支持 rem
的浏览器将获得基于像素的回退;支持 rem
的浏览器将从 <html>
字体大小获取正确的大小。
此示例的早期版本允许识别 vw 属性的浏览器直接使用它,但在 Chrome 25 无法应用使用 vw 指定的边框宽度后,该版本就被删除了。基于 rem 的替代方案没有此类问题。
在 rem
单位可用之前,可以使用 JavaScript 直接计算和分配属性。但是,rem
使事情变得更加容易。使用 rem
,只需要为整个文档进行一次分配,并且脚本不需要记住哪些属性应该以什么确切的方式进行缩放。
(function (doc, win) {
var docEl = doc.documentElement,
recalc = function () {
var clientWidth = docEl.clientWidth;
if (!clientWidth) return;
docEl.style.fontSize = clientWidth + 'px';
docEl.style.display = "none";
docEl.clientWidth; // Force relayout - important to new Android devices
docEl.style.display = "";
};
// Abort if browser does not support addEventListener
if (!doc.addEventListener) return;
// Test rem support
var div = doc.createElement('div');
div.setAttribute('style', 'font-size: 1rem');
// Abort if browser does not recognize rem
if (div.style.fontSize != "1rem") return;
win.addEventListener('resize', recalc, false);
doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window);
上面 JavaScript 代码中有一些需要注意的地方。首先,如果浏览器已过时并且不支持 addEventListener
API 或 rem
单位本身,则该脚本将提前终止。其次,它不是将 <html>
字体大小设置为实际的 vw
单位,而是将其设置为视窗宽度(以像素为单位)。这意味着 CSS 需要将 vw
值按 100 的比例缩放,以便与 rem
一起使用,但可以避免由于 Webkit 中有限的 font-size
精度而产生的舍入错误。
其他视窗单位几乎可以用相同的方式支持。这种方法有一些缺点。例如,您不能将 rem
用于其他用途。而且,您一次只能使用一个视窗单位(vw
),因此不能使用其他单位,例如 vh
、vmin
或 vmax
。
虽然现在几乎没有生产环境中的浏览器支持真正的 CSS 变量,但相当一部分浏览器允许您使用 rem
单位来做一点欺骗。如果您不需要将 rem
用于正常的字体大小,则可以使用它来运行时缩放几乎所有东西。如果您必须将 rem
用于字体大小,则可以选择使用 CSS 预处理器(Sass 或 Less)来计算正确的字体尺寸,从而使 rem 单位可用于运行时欺骗。
我已经使用这种技术大约 3 年了,它非常方便。不过,唯一对它表现出兴趣的人是 Josh Brewer。
如果您只支持好的浏览器,代码会变得非常精简(毫不意外):https://gist.github.com/brianblakely/3106678
不错的、简单的示例应用程序:http://m.kraftcheese.com/
干杯!
很棒的文章!我一直想谈谈 REM!——不久前,我将 Bootstrap 2.3 转换为使用所有 REM 值而不是 PX,并使用媒体查询来调整字体大小。我为整个盒子模型做了这件事。它让网站变得有趣地可以缩放。然后,我做的网站投入生产了,我就注释掉了它,哈哈。Chris,您怎么看?整个网站应该使用 REM 吗?
我不是 Chris,但我认为,是的,可以,只要您 a) 确保不支持 rem 的浏览器有回退,或者 b) 没有使用不支持 rem 的浏览器的访问者(查看您的分析数据!=)。
我在我的网站中使用了
rem
的左右:ricardozea.net使用
rem
构建网站后的经验告诉我,它太棒了!无需担心字体大小是否会因父元素的em
单位而改变。实际上,几乎所有有尺寸的元素,我都用rem
设置了。当然,需要适当的 IE7/8 样式表,对于这些用户来说,还需要另一个 HTTP 请求。但对于我们其他人来说,就是快乐的露营者。
这就是 LESS 和 SASS 片段派上用场的地方。我将这些用作所有内容(如宽度、高度、填充、边距等)的入门。
15% 的用户仍然使用 IE 6/7/8,他们只拥有所有 CSS3 功能的 50%。
但是.. 我们有 11 个字体单位。太棒了 :))
我的方法:在主样式表中使用 rem 单位,然后创建一个 ie 样式表,计算/更改所有使用 rem 的属性,将它们改为像素,然后使用正确的 html 条件语句,在需要时使用 ie 样式表。
我已经使用了几年的 REM 单位来衡量所有尺寸,没有遇到任何问题。我喜欢它提供的控制权。
但是,不幸的是,IE9 和 IE10 存在问题。它们会使用 REM 单位来衡量元素,但不会用于字体大小(无论使用哪种语法)!事实上,如果您以 REM 单位设置字体大小,整个字体将被忽略,它们会回退到用户代理的衬线或非衬线字体…甚至不会使用您堆栈中的字体。
我报告了一个错误,经过一段时间和大量工作后才得到认可,但他们现在正在努力解决。
如果您感兴趣,请参阅 IE 错误 772679 。同时,我添加了 px 字体大小作为 IE 的解决方法。
所以问题就在这里?!几周前,我在发布网站后遇到了这个问题,IE9 和 IE10 显示了 sans-serif 字体,而不是我使用的网络字体。
只有在为 IE 设置像素回退后,网站字体才开始工作。
谢谢你的信息。
很棒的小贴士,这个技巧非常有用,我以后肯定会用它,或者至少尝试一下,哈哈。
谢谢,一如既往,你的内容非常有见地。我注意到 foundation.css(Foundation 5 CSS 框架)使用 rem 62.5 - 似乎这是完整宽度的 62.5%(对吗?)
.row {
margin: 0 auto;
max-width: 62.5rem;
width: 100%;
}
PS:这个评论预览器很棒 - 我可以问一下你用的是什么插件/主题吗?
Gvanto,我自己还没有查看,但我相当确定 Chris(Coyier)记录了他对整个网站的重新设计,正如现在的网站外观/工作方式一样,在“The Lodge”中,你可以在网站的主导航栏中找到它。也许他在那里提到了或深入讨论了评论功能。希望这能有所帮助。
你把“Viewport”拼成了“Viewporth”。第一段的倒数第三个词。
很棒的文章!
谢谢!已修复并掩埋,因为不再相关。