CSS技术分享: 文字在圆形内沿着弧线边界排版

栏目: IT技术 · 发布时间: 4年前

内容简介:byzhangxinxu from本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。

byzhangxinxu from https://www.zhangxinxu.com/wordpress/?p=9352

本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。

CSS技术分享: 文字在圆形内沿着弧线边界排版

一、圆形区域文字排版问题

如果容器是正方形,则文字排版很Easy,菜市场的老太太也能实现,因为天热排版就是OK的,例如:

p {
  padding: 10px;
  width: 12em;
  background: deepskyblue;
  color: #fff;
}

实时效果如下:

如果你在其他地方看到zxx或者zhangxinxu文字的内容,说明是盗版的我的文章,欢迎反馈

但是,如果我们设置了巨大的圆角,则文字排版效果就有些惨不忍睹了,例如:

p {
  padding: 10px;
  width: 12em;
  background: deepskyblue;
  color: #fff;
  border-radius: 50%;
}

实时效果如下:

如果你在其他地方看到zxx或者zhangxinxu文字的内容,说明是盗版的我的文章,欢迎反馈

可以看到部分文字直接都看不见了,上下左右留下的间隙也不一致,看起来好难受。

此时,水谷雫托着下巴,对着窗外感叹道:“要是文字可以沿着圆弧的边界排版就好了。”

CSS技术分享: 文字在圆形内沿着弧线边界排版

吉田春满脸泡泡茶壶地回道:“我有办法实现的呢~”

CSS技术分享: 文字在圆形内沿着弧线边界排版

二、CSS Shapes布局与环形排版

如果对CSS Shapes布局还不太了解,可以参阅我之前这篇热文:“ 写给自己看的CSS shapes布局教程 ”。

其中,CSS Shapes布局可以围绕图片布局(根据Alpha通道透明度),这个图片包括渐变,于是乎,我们只需要绘制两个内凹的圆弧径向渐变,然后让文字环绕布局不就好了。

说干就干,首先,我们需要现在文字前面插入两个元素,一个左浮动,一个右浮动,然后绘制内凹的径向渐变。

HTML如下:

<p>
    <before></before><after></after>
    ...文字内容
</p>

CSS代码如下:

.circle {
    border-radius: 50%;
    width: 207px; height: 250px;
    color: white;
    background-color: deepskyblue;
    padding: 10px;
}
before {
    float: left;
    width: 50%; height: 100%;
    shape-outside: radial-gradient(farthest-side ellipse at right, transparent 100%, red);
}
after {
    float: right;
    width: 50%; height: 100%;
    shape-outside: radial-gradient(farthest-side ellipse at left, transparent 100%, red);
}

结果如下图所示:

CSS技术分享: 文字在圆形内沿着弧线边界排版

您可以狠狠地点击这里: CSS Shapes布局让文字在圆环内排版demo

原理就是构建两个弧形,然后使用CSS Shapes布局让文字沿着这个弧形排列即可。

不要高兴地太早

然后上面的实现仍然有一些局限。

首先容器需要定高,不然左右浮动的元素高度不会存在,或者 <before><after> 元素设置具体的长度值才可以(这样不一定可以正好和形状匹配)。

其次需要在文字前面插入 <before><after> 这两个元素实在是太不方便了,每次都插入两个元素,又啰嗦又不好维护。怎么办,有没有什么优化的方法呢?

试试看使用自定义元素。

三、使用自定义元素优化环形排版

自定义一个名为 <zxx-circle> 的元素,使用Shadow DOM把 <before><after> 元素藏在自定义元素里面,这样,HTML代码就会很干净了,如下:

<zxx-circle>在CSS ... by zhangxinxu</zxx-circle>

就会有如下图所示的效果了:

CSS技术分享: 文字在圆形内沿着弧线边界排版

同时,如果元素不设置高度,也能有效果,但是,最终的高度不一定精准,我是粗略实现了下,因此,实际开发,如果可以,建议开始设定好高度,体验更好。

JS代码如下:

class HTMLZxxCircleElement extends HTMLElement {
  constructor() {
    self = super();

    let shadow = this.attachShadow({
        mode: 'open'
    });
    
    // 文本内容移动到shadow dom元素中
    let style = document.createElement('style');
    shadow.appendChild(style);
    // 前后元素
    let before = document.createElement('zxx-before');
    let after = document.createElement('zxx-after');
    shadow.prepend(after);
    shadow.prepend(before);
    // 内容
    let content = document.createElement('div');
    shadow.appendChild(content);

    let ro = new ResizeObserver( entries => {
      for (let entry of entries) {
        self._updateRendering();
      }
    });
    
    // 观察当前元素尺寸变化
    ro.observe(this);
  }
  
  connectedCallback() {
    // 执行渲染更新
    this._updateRendering();
  }
  _updateRendering() {
    let shadow = this.shadowRoot;
    let content = shadow.querySelector('div');
    let before = shadow.querySelector('zxx-before');
    before.style.height = 'auto';
    // 内容更新
    content.innerHTML = this.innerHTML;
    // 此时内容高度
    let heightContent = parseFloat(getComputedStyle(content).height);
    let heightBefore = parseFloat(getComputedStyle(before).height);
    
    if (heightContent == 0) {
        return;
    }
    
    // 没有设置具体的高度值
    if (heightBefore == 0 && heightContent != 0) {
        // 同样面积的椭圆的高度是?
        // s = π×a×b
        let height = (2 *  heightContent * 2 / Math.PI) + 'px';
        
        console.warn('<zxx-circle> no height, set it to ' + height + '!');
        this.style.height = height;
    }
    before.removeAttribute('style');
    // 样式设置
    shadow.querySelector('style').textContent = `:host {
    border-radius: 50%;
}
zxx-before,
zxx-after {
    width: 50%; min-height: 100%; height: ${heightContent}px;
}
zxx-before {
    float: left;
    shape-outside: radial-gradient(farthest-side ellipse at right, transparent 100%, red);
}
zxx-after {
    float: right;
    shape-outside: radial-gradient(farthest-side ellipse at left, transparent 100%, red);
}`;
  }
}
// 定义zxx-circle标签元素
customElements.define('zxx-circle', HTMLZxxCircleElement);

眼见为实,您可以狠狠地点击这里: 自定义元素优化文字在圆环内排版demo

如果高度是auto,则效果是下图这样:

CSS技术分享: 文字在圆形内沿着弧线边界排版

四、其他一些说明

Chrome浏览器下,这个左右浮动的CSS Shapes布局有个和搞笑的奇偶bug,其实上面这个图就有这个问题了,中间的文字莫名只显示了左边50%,右边50%没显示。

我看可以看下下面这个GIF录屏示意:

CSS技术分享: 文字在圆形内沿着弧线边界排版

和英文单词或者换行什么的都没有任何关系,全部都是中文也是这样,大家有兴趣可以去demo页面自己感受下。

抓紧机会,怕是过十几个版本这个问题就会被修复了。Firefox浏览器没有任何问题,表现完全OK。

<zxx-circle> 自定义元素的实现就是刚刚个把小时折腾了下,想要完全精准计算最佳高度,有些超出自己的能力范围了,只能大致处理下,欢迎有兴趣的人进行优化下。当元素高度auto的时候,精准计算左右Shapes图形的高度。

好了,就说这么多。

CSS Shapes布局 IE浏览器,Edge浏览器都不支持,目前适合中后台项目,或者移动端产品(老手机不支持的项目) 。

非典型场景,但是,万一哪个小伙伴遇到这样的需求,说不定就帮了大忙。

以上,感谢阅读,欢迎分享。

CSS技术分享: 文字在圆形内沿着弧线边界排版

本文为原创文章,欢迎分享,勿全文转载,如果实在喜欢,可收藏,永不过期,且会及时更新知识点及修正错误,阅读体验也更好。

本文地址: https://www.zhangxinxu.com/wordpress/?p=9352

(本篇完)


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Speed Up Your Site

Speed Up Your Site

Andrew B. King / New Riders Press / 2003-01-14 / USD 39.99

There's a time bomb on the web: user patience. It starts ticking each time someone opens one of your pages. You only have a few seconds to get compelling content onto the screen. Fail, and you can kis......一起来看看 《Speed Up Your Site》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具