前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CSS3着重符及其fallback

CSS3着重符及其fallback

作者头像
mmzhou
发布2018-08-06 18:07:21
1.7K0
发布2018-08-06 18:07:21
举报
文章被收录于专栏:前端小作坊前端小作坊

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:

代码语言:javascript
复制
// 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的缓存复用。

代码语言:javascript
复制
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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • CSS3着重符及其fallback
    • 标准
      • FALLBACK
        • jQuery.emphasis.js
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档