《 CSS Secrets 》是 @Lea Verou 最新著作,这本书讲解了有关于CSS中一些小秘密。是一本CSSer值得一读的一本书,经过一段时间的阅读,我、@南北和@彦子一起将在W3cplus发布一系列相关的读后感,与大家一起分享。
尽管这不是一个常见的文本效果,有时候有一些比较短的文本需要遵循环形路径显示。这种时候,CSS就弃我们而去了。没有任何CSS属性或功能可以完成这个效果,我们唯一想到的CSS解决方案都非常麻烦,所以我们也就只是想想而已。真的没有什么办法可以实现这样的样式吗?除了使用图像,除了不影响我们文本的整体美观?
在 juliancheal.co.uk 上使用环形文本作为左边的按钮(知道我指的是哪里吗?);注意那里的环形文本是避免打破按钮的唯一办法,按钮形状的中间位置是由孔和螺纹组成的
有一些脚本可以完成这个效果。它们通过将每个字母包裹在单独的 元素中,然后旋转到合适的角度来把它们一个一个组合成圆。这个方案不仅非常麻烦,而且还给页面的DOM元素添加了很多不必要的臃肿的标记。
尽管目前没有办法通过纯CSS来完成这个效果,但是我们可以通过一点内联SVG来很简单地完成。SVG本身就支持文本以任何路径显示,环形只不过是路径的一个特殊情况。我们来试一下!
SVG中文本按路径显示的基本方案是通过一个
可惜,
假设我们要把“circular reasoning works because”这句话做成环形文本,占据一个圆圈的整个圆周,如图所示。
我们需要在HTML中添加一个内联SVG,并定义一个圆形路径:
<div class="circular"> <svg viewBox="0 0 100 100"> <path d="M 0,50 a 50,50 0 1,1 0,1 z" id="circle" /> </svg></div>
注意我们是通过 viewBox ,而不是 width 和 height 来定义它的单位。这可以让我们设置坐标系统和长宽比,而不是一个固定的大小。这不仅是因为它更紧凑,还因为它帮我们节省了几行CSS,因为我们不再需要为
如果你不清楚 path 的语法,别担心。大家都是一样的,甚至是那些已经了解了SVG path语法的人,还是会忘记语法。如果你好奇,下面这三个命令已经非常好地概括了下面这些语法:
为什么SVG路径的语法这么隐蔽?它当初被设计出来的时候,大家觉得没有人会手动编写SVG,所以SVG工作小组尽可能地用了最紧凑的语法,来减少文件大小。
目前,我们的路径只是一个黑色的圆。
我们需要通过
<div class="circular"> <svg viewBox="0 0 100 100"> <path d="M 0,50 a 50,50 0 1,1 0,1 z" id="circle" /> <text> <textPath xlink:href="#circle"> circular reasoning works because </textPath> </text> </svg></div>
如上图所示,尽管我们还需要做很多东西,来让它更像样更有可读性,我们已经取得了我们想要的效果,这是CSS很多年内都无法完成的!
下一步是移除我们的圆形路径上的黑色填充。我们并不希望圆形以任何方式显示出来;我们只是想要它作为我们文本的一个引导。有很多方式可以完成,比如把它加入到一个
.circular path { fill: none; }
现在黑色的圆已经消失了
我们可以仔细研究其它问题了。下一步最大的问题是,我们大多数的文本是在SVG元素之外的,还被裁剪了。为了解决这个问题,我们需要让我们的容器元素更小一些,然后为SVG元素应用 overflow: visible ,这样它就不会裁剪它的视窗之外的任何内容了:
.circular { width: 30em; height: 30em;}.circular svg { display: block; overflow: visible;}
你可以在上图中看到效果。注意到我们已经差不多完成了,但是有一些文本还是被裁剪了。原因是SVG元素是根据它的尺寸浮动的,而不是溢出。因此,事实上,溢出盒子边界的
.circular { width: 30em; height: 30em; margin: 3em auto 0;}.circular svg { display: block; overflow: visible;}
就是它了!我们的示例现在看起来和下图非常相像
文本也是可访问的。如果我们的圆形文本只有一个实例(如,一个网站的logo),那我们到这里就完成了。但是,如果我们关于这种类型的文本有不止一个实例,我们不希望每次都重复这些SVG标签,可以写一个简短的脚本来自动生成所需的SVG元素,如类似这样的标签:
<div class="circular"> circular reasoning works because</div>
该代码可以通过一个“circular”类遍历所有元素,移除它们的文本并把它存储在一个变量中,并添加必要的SVG元素:
$$('.circular').forEach(function(el) { var NS = "http://www.w3.org/2000/svg"; var xlinkNS = "http://www.w3.org/1999/xlink"; var svg = document.createElementNS(NS, "svg"); var circle = document.createElementNS(NS, "path"); var text = document.createElementNS(NS, "text"); var textPath = document.createElementNS(NS, "textPath"); svg.setAttribute("viewBox", "0 0 100 100"); circle.setAttribute("d", "M0,50 a50,50 0 1,1 0,1z"); circle.setAttribute("id", "circle"); textPath.textContent = el.textContent; textPath.setAttributeNS(xlinkNS, "xlink:href", "#circle"); text.appendChild(textPath); svg.appendChild(circle); svg.appendChild(text); el.textContent = ''; el.appendChild(svg);});