解决文字和text-decoration:underline下划线重叠问题

lgpf352s 8年前
   <h3><strong>一、text-decoration:underline下划线的问题</strong></h3>    <p>CSS text-decoration:underline 可以给内联文本增加下划线,但是,如果对细节要求较高,就会发现,下划线经常会和中文文字的下边缘搞在一起,英文的话甚至直接穿越,看起来就比较香菇蓝瘦。</p>    <p><img src="https://simg.open-open.com/show/1b722c7300ad71ec7a8b3027746dee57.png"></p>    <p>上图几个中文下边缘正好都是横线,结果,可以看到,基本上合在一起分不清谁是谁了,换成微软雅黑字体(见下图),似乎变本加厉了:</p>    <p><img src="https://simg.open-open.com/show/e9ae1f121e0915b908b606742fdcf8ff.png"></p>    <p>有没有什么办法让下划线不要靠得这么近,或者文字可以完整清晰地显示呢?</p>    <p>有,方法还不少,下面逐一介绍,大家可以根据自己的实际项目需求,选择合适的技术选型。</p>    <h3>方法一:text-decoration-skip指定覆盖关系</h3>    <p>理论上,使用下面的CSS:</p>    <pre>  <code class="language-css">a { text-decoration-skip: ink; }</code></pre>    <p>机会有类似下图的效果:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/e21da3f84a3ee2a175ff406cb4968d18.png"></p>    <p>text-decoration-skip 是 text-decoration 相关的CSS3新的属性,还有很多其他新的CSS3 text-decoration 属性,可以指定下划线类型等。</p>    <p>看上去效果很不错,但是遗憾的是,即使现在快到2017年了,此属性的浏览器支持情况还是很不乐观,包括大头Chrome浏览器目前尚未支持。</p>    <p>Safari 8+ supports -webkit-text-decoration-skip with values none and skip (other values behave like none or skip)</p>    <p>目前也就是Safari 8+浏览器支持带 -webkit- 私有前缀的 text-decoration-skip 属性,且仅仅支持 skip (默认值)和 none 两个值,换句话说,Safari 8+浏览器默认下划线就是和文字非穿越而是避让效果。这进一步导致CSS代码中没有 text-decoration-skip 属性出现的必要了。所以,此方法虽然最原生,但时机还不够。</p>    <h3><strong>方法二:使用border-bottom属性模拟</strong></h3>    <p>内联元素虽然不支持垂直方向的 margin 属性,但是支持垂直方向的 padding 属性和 border 属性,并且,对原来的布局定位等没有任何影响。因此,配合 padding ,我们就可以很有效地调节下边框和文字下边缘的距离,实现我们最想要的的效果,类似下面的CSS代码:</p>    <pre>  <code class="language-css">a {      text-decoration: none;      border-bottom: 1px solid;  }</code></pre>    <p>效果类似下图:</p>    <p><img src="https://simg.open-open.com/show/d3a44ae6f91b17561d97f04279b447f4.png"></p>    <p>如果觉得 border-bottom 模拟的下划线还是和文字走得太近,我们可以使用 padding-bottom 再撑开点距离,例如:</p>    <pre>  <code class="language-css">a {      text-decoration: none;      border-bottom: 1px solid;      padding-bottom: 5px;  }</code></pre>    <p>则效果类似下面截图:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/7c8617e7ec3437fc2d6d28f0e977c898.png"></p>    <p>注意,使用 border-bottom 模拟下划线的时候, border-color 最好缺省,这样就会使用文字的 color 颜色作为边框色,这样,鼠标 hover 的时候,下划线会自动和文字一起变色,类似下图效果:</p>    <p><img src="https://simg.open-open.com/show/e488bc047352c83c4313bd66cc0dc06a.png"></p>    <p>使用 border-bottom 模拟的另外一个好处就是我们还可以使用虚线下划线:</p>    <pre>  <code class="language-css">a {      text-decoration: none;      border-bottom: 1px dashed;  }</code></pre>    <p>类似下面实际项目需求的截图就可以使用这种策略:</p>    <p><img src="https://simg.open-open.com/show/ecb744f97e86976973ad00f277e2584a.png"></p>    <h3><strong>方法三:使用box-shadow属性模拟</strong></h3>    <p>我们也可以使用CSS3 box-shadow 属性模拟下划线,代码如下:</p>    <pre>  <code class="language-css">a {      text-decoration: none;      box-shadow: 0 1px;  }</code></pre>    <p>同样,建议颜色值缺省,使用 color 属性的颜色值。</p>    <p>效果基本上和 border-bottom 如出一辙,如下截图:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/49e153fd6f27fa01115d40bf21492ae1.png"></p>    <p>相比 border-bottom 属性, box-shadow 的优势在于,即使我们把内联元素设置成 display:inline-block ,生成的下划线也不会对垂直对齐或者布局产生影响,但,如果是 border-bottom ,会增加元素的尺寸,可能就会影响元素的排列。</p>    <p>但是, box-shadow 也有不足,一是兼容性,IE9+才支持,二是只能实线,不能虚线。</p>    <h3><strong>方法四:使用background-image属性模拟</strong></h3>    <p>就是使用CSS3渐变绘制实线或虚线背景图。</p>    <p>效果截图如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/4a0e0ab00f6cf63ed82d3a294c71a550.png"></p>    <p>相关CSS代码如下:</p>    <pre>  <code class="language-css">.solid {      padding-bottom: 2px;      background-image: linear-gradient(to top, currentColor, currentColor 1px, transparent 1px);  }  .dashed {      padding-bottom: 2px;      background: linear-gradient(to right, currentColor, currentColor 4px, transparent 4px) repeat-x 0 bottom/7px 1px;      }</code></pre>    <p>由于背景图片是在原本区域内显示,有别于 border-bottom 或者 box-shadow 区域外显示,因此,实现的下划线实际上和文字还是很近的,尤其类似 yqp 这种基线以下的字母,就会合体。一般有两种处理手段,一种是文字增加白色描边,类似下面CSS:</p>    <pre>  <code class="language-css">a {      text-shadow: 0 1px #fff, 0 -1px #fff, 1px 0 #fff, -1px 0 #fff;  }</code></pre>    <p>效果类似下面这样:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/9c806d2ce6cbbbff99defc85c3bfa4e4.png"></p>    <p>第二种就是使用 padding-bottom 对内联元素增加可视高度。所以,上面实线下划线和虚线下划线均有 padding-bottom:2px 的设置。</p>    <p>对了,突然想起来,demo中的下划线使用的是 currentColor 变量,但是在Chrome浏览器和IE浏览器下, currentColor 作为背景图片色值的时候,当 :hover 改变元素的 color 颜色值的时候,背景图片颜色并不会跟着变,Firefox浏览器的表现符合预期,因此,如果使用此方法,需要 :hover 时候,背景图片重新绘制下。</p>    <p>使用 background-image 绘制的好处在于,我们对样式的控制更灵活的,例如我们可以把线放在文字的后面,我们可以上下划线,我们控制虚线的稀松程度,我们也可以使用圆点表示虚线,我们甚至也可以使用径向渐变绘制波浪样子的下划线,甚至可以把线做成倾斜的等等。不足在于IE10+浏览器才支持。</p>    <h3><strong>方法五:使用SVG滤镜处理</strong></h3>    <p>该SVG滤镜相关HTML代码如下:</p>    <pre>  <code class="language-css"><svg class="out">    <filter id="svg-underline" primitiveUnits="objectBoundingBox">      <!-- 原图文基础上水平垂直方向一点点扩展并存储到新的层上 -->      <feMorphology in="SourceGraphic" operator="dilate" radius="0.0075 0.05" result="outline"></feMorphology>      <!-- 一个蓝色矩形,高度3%然后宽度100%,位置稍微往下一点 -->      <feFlood flood-color="#34538b" width="1" height="0.03" x="0" y="0.9" result="underline"></feFlood>      <!-- 遮罩蓝色矩形,这样,文字重合部分边缘会镂空 -->      <feComposite in="underline" in2="outline" operator="out" result="underline"></feComposite>      <!-- 效果合体 -->      <feMerge>        <feMergeNode in="underline"></feMergeNode>        <feMergeNode in="SourceGraphic"></feMergeNode>      </feMerge>    </filter>  </svg></code></pre>    <p>相关CSS代码如下:</p>    <pre>  <code class="language-css">a {      -webkit-filter: url('#svg-underline');      filter: url('#svg-underline');      text-decoration: none;  }</code></pre>    <p>然后,实现的效果类似下面的截图(截自Chrome浏览器):</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/5650c30a2b9a548c2bdc74a7ebec62d1.png"></p>    <p>看上去很麻烦很啰嗦,hover变色还需要另外的处理,SVG滤镜兼容性并不乐观,IE现在都不支持,所以,这种方法的意义在哪里?</p>    <p>意义就在于可以实现真正意义上的 text-decoration-skip 效果,也就是下划线和文字重叠的位置自动从文字下面穿过,并且附近完全是真正的透明,仔细看上面截图,可以看到,文字和下划线接触的位置的地方,看上去有1像素的接触点是透明的。</p>    <p>原生的Safari外加SVG滤镜下的Chrome/Firefox,也就是绝大多数浏览器都可以实现下划线和文字自动接触点镂空的效果。</p>    <h3><strong>方法六:使用canvas实现(著名的Underline.js)</strong></h3>    <p>underline.js同样实现的是下划线和文字重叠自动避让的效果,类似下图:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/7d4fa045028c4beb07cb48597f4c4f7c.png"></p>    <p>基本上,下划线文字穿越效果只有英文才好看,中文如果穿越,我去,基本上下划线就没了,尤其类似“金玉全王”这样的汉字:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/b22f8817c8cb863a8b74902a76f484b6.png"></p>    <p>所以,对于中文,最好的效果还是避让,就是直接线和文字留点距离,这样是最好的。对于,英文为主的内容,则 text-decoration-skip 效果确实还是挺有价值的。</p>    <p>根据我自己对underline.js的使用,发现,局限性还不小,内联元素最好要 inline-block 化,纯 inline 生成的canvas的垂直位置不是很精准,然后,不支持文字自动换行下划线折线显示,毕竟canvas元素是个独立的替换元素,跟图片一样,不可能换行时候分一半上面再一半下面。</p>    <p>基本上,适合用在局部一些大的标语,标题,slogon等位置或者追求视觉的官方网站或活动页面上使用。</p>    <h3> </h3>    <p> </p>    <p> </p>    <p>来自:http://www.zhangxinxu.com/wordpress/2016/11/css-text-decoration-underline-skip-override/</p>    <p> </p>