CSS3着重符及其fallback

CSS3着重符及其fallback

在东亚国家,人们会在文章中重要文字旁加上小符号以突出其重要性。如下:

标准

在中文里面,我们一般会在文字下方加上圆形符号。在日语中会在文字上方加上小顿号。在CSS3中如下属性可以控制着重符号:

  1. text-emphasis
  2. text-emphasis-style
  3. text-emphasis-color
  4. text-emphasis-position

text-emphasistext-emphasis-styletext-emphasis-color的快捷方式,注意它并不包含text-emphasis-position

text-emphasis-style属性用于控制着重符号的样式。基本的符号形状有dot | circle | double-circle | triangle | sesame这几种,它们又分别有“空心(open)”、“填充(filled)”两种展现形式。当你只填了filledopen是,符号形状的默认值和文字是竖排还是横排(writing-modes)有关,比如横排时默认是filled circle,竖排时是filled sesame。如果你之前填了符号形状,则默认的展现形式是filled。当然你还可以自定义符号,但是只能显示一个字符。

另一个重要的属性是text-emphasis-color,它控制了着重符号的颜色,默认使用当前文字的颜色。

最后一个属性是text-emphasis-position,它有这几种可选值[ over | under ] && [ right | left ]。它的默认值计算方式更为复杂些,与横竖排版和所处语言环境都有关系。横排情况下,中文环境默认值为under,日文环境默认值为over。竖排情况下,中文和日文环境下默认值都为right

在CSS中,一般着重符号的字体大小是其对应文字的一半。且当行高有足够空间来绘制着重符时,它不会影响到对应文字的行高。

在2013年8月1日,这个标准成为“候选推荐标准”,这对喜爱文字排版的人来说是个好消息。遗憾地是目前只有webkit内核的浏览器是支持它的,并且需要使用webkit前缀。所以在使用时需要做fallback。

FALLBACK

在做fallback时,有这么几点是需要考虑的:

  1. 如何应对letter-spacing样式和文字宽度不一致的情况
  2. 如何处理浏览器的最小字体配置
  3. 如何空间是否足够绘制着重符(计算行高)
  4. 如何减少对现有html的影响
  5. 如何获得所处语言环境

对于第一点的解决方案是:对每个字符用span包裹,方法类似于letter.js。然后在每个span内部插入另一个包含着重符的span,它的宽度为百分百,且绝对定位。如下面样例所示:

对于有letter-spacing的情况,可以设置span的letter-spacing为0,然后使用margin-right来替代它。

如果你是用chrome,你可能已经注意到了“最小字体”导致的问题:着重符号太大了。在chrome下着重符号是12px,而不是8px(16/2)。为了解决问题2,我们需要想想其他方法。我首先考虑到的是zoom属性,它支持chrome(所有版本)、safari和IE。可惜的是在chrome下zoom:0.5也不能使字体变小。然后考虑到的是transform:scale(0.5),幸运地是它能使文字比最小字体还要小。不过支持的浏览器不够多,参考这里。所以必须要考虑在不支持transform的时候使用fallback。我的处理方法是使用绝对大小(px)。虽然不能使着重符号字体变小,但是至少可以保证着重符位置正确。

在绘制着重符时,如果行高内有足够的高度,则着重符不会扩大行高。如果高度不够,则扩大行高。第二种情况需要设置display:inline-block; 及padding-bottom,来模拟行高高度的扩大。为了做高度是否充足的判断,我们就需要计算字体大小和行高。当你设置字体大小为1em时,对于IE这样的浏览器,获得地长度其实并不是以px为单位。这时需要一些hack:

// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
var PIXEL = /^\d+(px)?$/i;
function getPixelValue(element, value) {
    if (PIXEL.test(value)) {
        return parseInt(value);
    }
    var style = element.style.left;
    var runtimeStyle = element.runtimeStyle.left;
    element.runtimeStyle.left = element.currentStyle.left;
    element.style.left = value || 0;
    value = element.style.pixelLeft;
    element.style.left = style;
    element.runtimeStyle.left = runtimeStyle;
    return value;
};

幸运地是,jQuery已经处理了这种情况。这样我们就可以得到正确的字体大小和行高(需要特殊处理行高为缩放因子和normal的情况)。不过受到了“文字可能比设置地字体大小更大”、“同行有更高行高的元素(例如图片)”等等特殊情况的限制,导致了计算结果并不一定正确。幸运地是对最终结果的影响并不是很大。

第四个问题指的是innerText/$('em').text()的返回值在做了fallback之后就不再正确了,同时受到影响的还有innerHTML。对于后者我没有想到好的方案。对于前者,我们可以把着重符放在span标签的before伪元素上。这样得到的innerText值还是正确的。不过也引入了另一个问题:如何用js修改before伪元素的样式。我采用的方法是插入css rule,下面有简单的代码。在实际情况下,因为不能删掉css rule,所以需要做好css rule的缓存复用。

var styleSheet;
function addCSSRule(selector, rules) {
    if (!styleSheet) {
        var style = document.createElement('style');
        style.type = 'text/css';
        $('head').eq(0).prepend(style);
        styleSheet = document.styleSheets[0];
    }

    if (styleSheet.insertRule) {
        styleSheet.insertRule(
            selector + '{' + rules + '}',
            styleSheet.cssRules.length
        );
    } else {
        // IE
        styleSheet.addRule(selector, rules, -1);
    }
}

最后一个问题的解决方案则比较简单粗暴。获取navigator.language || navigator.browserLanguage的值判断其所处的语言环境。

jQuery.emphasis.js

解决了这些问题之后,终于得到了一个可用的fallback。再根据标准来修改优化代码,就得到了jQuery.emphasis.js。这里有些它的demo。不过它没有解决所有的问题,目前已知的缺陷如下:

  1. 不支持竖排(即不支持positionright/left
  2. 不支持特殊情况下的inline-block元素(比如默认元素有padding-bottom
  3. 如果浏览器不支持transform,则会有最小字体导致的着重符过大问题

如果你还发现了其他问题,欢迎feedback

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏全沾开发(huā)

使用JavaScript实现一个俄罗斯方块

使用JavaScript实现一个俄罗斯方块 清明假期期间,闲的无聊,就做了一个小游戏玩玩,目前游戏逻辑上暂未发现bug,只不过样子稍...

39960
来自专栏林德熙的博客

win10 uwp win2d 使用 Path 绘制界面

在 win2d ,可以使用 DrawGeometry 的方式画出几何。而路径 Path 就是一种 Geometry 。传入的 CanvasGeometry 参数...

14010
来自专栏deepcc

.clearfix:after的用法,清除浮动

28160
来自专栏深度学习之tensorflow实战篇

绘制动态心形图案::R语言绘制心形图

原始方程源于此贴一楼:直通车 整理修改后: 被窝修改成这样: x<-seq(-1.1,1.1,length = 3000) rep<-30 y<-matri...

50670
来自专栏游戏开发那些事

【python游戏编程之旅】第一篇---初识pygame

本系列博客介绍以python+pygame库进行小游戏的开发。有写的不对之处还望各位海涵。

15020
来自专栏吾爱乐享

php学习之html的标签属性(二)

16020
来自专栏lonelydawn的前端猿区

一款不可多得的火柴时钟

? 火柴时钟 一款有意思的时钟玩具,原生代码编写,使用 CSS 渲染过渡动效,引入 base64 格式 data url 图片。 引用 <link rel=...

31270
来自专栏哲学驱动设计

OEA 中 WPF 树型表格虚拟化设计方案

    最近用 OEA 做的仓库管理系统中,许多界面的都需要使用表格控件来显示数据。一是这些表格的列非常多,有的甚至达到了 200 列,而且一个模块的界面中可能...

21670
来自专栏码神联盟

碎片化 | 第四阶段-41-struts2字节流生成验证码-视频

如清晰度低,可转PC网页观看高清版本: http://v.qq.com/x/page/r056700jckx.html 验证码实现 需求: 在登录的页面,增...

30090
来自专栏mathor

概率论与数理统计(一)

12640

扫码关注云+社区

领取腾讯云代金券