文字适应纹理
刀刀
1/3/2025
0 字
0 分钟
目前有一个需求,需要文字适应背景图片的纹理,且能实现文字内容颜色自定义转换的功能。
咋一看该功能不好实现,一般情况下可以找设计师给 UI 图,但是无法适配纹理。因此还是需要回到前端自己实现,不过可以参考一下UI的实现思路——滤镜。
前端的滤镜第一时间先考虑到 filter
,但是找遍 filter
所有属性值都无法实现。因此继续往下思考,想到了 SVG 的滤镜。
SVG的滤镜效果更强大,可以说 CSS 的 filter
滤镜是 SVG 滤镜的子集,尝试一下。
SVG滤镜
首先写一个 svg
标签,标签内放置一个图片 image
和一个文本 text
,代码如下:
<svg viewBox="0 0 600 330">
<Image
href="./cat.png"
x="0"
y="0"
width="100%"
height="100%"
preserveAspectRatio="none">
</Image>
<text
x="50%"
y="50%"
font-size="10em"
font-weight="bold"
text-anchor="middle"
alignment-baseline="middle"
fill="#000">
Logo
</text>
</svg>
其中设置了图片标签的 x 轴和 y 轴位置、宽高缩放设置,设置了文本的 x 轴和 y 轴位置、字体大小和粗细、横轴纵轴对齐方式、字体颜色。
现在需要添加纹理,由于是让文字适配背景,因此要给文字添加滤镜。滤镜添加在 svg
内,通过 defs
和 filter
标签实现,为 filter
设置唯一值 id
,然后为 text
绑定。代码如下:
<svg viewBox="0 0 600 330">
<defs>
<filter id="conform"></filter>
</defs>
<Image
href="./cat.png"
x="0"
y="0"
width="100%"
height="100%"
preserveAspectRatio="none">
</Image>
<text
x="50%"
y="50%"
font-size="10em"
font-weight="bold"
text-anchor="middle"
alignment-baseline="middle"
fill="#000"
filter="url(#conform)">
Logo
</text>
</svg>
现在刷新页面后文本内容不见了,这是必然的,因为 filter
内没设置任何东西,所以无效果,后续一步步来。
文字效果
首先,想要实现文字适配图片纹理,首先得要有一个图片滤镜,设置图片的路径以及其 x 轴和 y 轴起始坐标。最后通过 result
导出一个名称 ORIGIN_IMAGE
给后续的滤镜使用。
<feImage href="./cat.png"
result="ORIGIN_IMAGE"
x="0"
y="0"
width="100%"
height="100%"
preserveAspectRatio="none">
</feImage>
然后图片不需要太多颜色,设置为灰度图,通过 in
引入上一个滤镜的名称,再通过 result
导出名称 GRAY_IMAGE
给下一个滤镜使用。
<feColorMatrix in="ORIGIN_IMAGE"
type="saturate"
values="0"
result="GRAY_IMAGE">
</feColorMatrix>
接着为文字设置置换滤镜,其本质就是改变文本里的每一个像素点。 in
引入原始图像 SourceGraphic
(也就是 text
文本)和灰度图像 GRAY_IMAGE
,以灰度图作为参考,通过一个算法来实现偏移。该算法用大白话来说就是当参考点越黑,他就越往右下偏移;参考点越白他就越往左上偏移;不黑不白则不偏移。再通过 result
导出名称 TEXTURED_TEXT
给下一个滤镜使用。
<feDisplacementMap in="SourceGraphic"
in2="GRAY_IMAGE"
scale="15"
xChannelSelector="R"
yChannelSelector="R"
result="TEXTURED_TEXT">
</feDisplacementMap>
紧接着要让文字和图片纹理贴合,需要 in
引入 TEXTURED_TEXT
把图像在写一遍,让图像和文本融合。再通过 result
导出名称 BG
给下一个滤镜使用。
<feImage href="./cat.png"
in="TEXTURED_TEXT"
x="0"
y="0"
width="100%"
height="100%"
preserveAspectRatio="none"
result="BG">
</feImage>
再然后为滤镜添加不透明度,导出名称 OPACITY_TEXT
。
<feColorMatrix in="TEXTURED_TEXT"
type="matrix"
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 9 0"
result="OPACITY_TEXT">
</feColorMatrix>
最后得到不透明度的背景和融合成功的文本,把二者结合起来即可。
<feBlend in="BG"
in2="OPACITY_TEXT"
mode="multiply"
result="BLENDED_TEXT">
</feBlend>
总体代码
点击查看代码
<template>
<svg viewBox="0 0 600 330">
<defs>
<filter id="conform">
<feImage href="./cat.png"
result="ORIGIN_IMAGE"
x="0"
y="0"
width="100%"
height="100%"
preserveAspectRatio="none">
</feImage>
<feColorMatrix in="ORIGIN_IMAGE"
type="saturate"
values="0"
result="GRAY_IMAGE"></feColorMatrix>
<feDisplacementMap in="SourceGraphic"
in2="GRAY_IMAGE"
scale="15"
xChannelSelector="R"
yChannelSelector="R"
result="TEXTURED_TEXT"></feDisplacementMap>
<feImage href="./cat.png"
in="TEXTURED_TEXT"
x="0"
y="0"
width="100%"
height="100%"
preserveAspectRatio="none"
result="BG">
</feImage>
<feColorMatrix in="TEXTURED_TEXT"
type="matrix"
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 9 0"
result="OPACITY_TEXT"></feColorMatrix>
<feBlend in="BG"
in2="OPACITY_TEXT"
mode="multiply"
result="BLENDED_TEXT"></feBlend>
</filter>
</defs>
<Image href="./cat.png"
x="0"
y="0"
width="100%"
height="100%"
preserveAspectRatio="none">
</Image>
<text x="50%"
y="50%"
font-size="10em"
font-weight="bold"
text-anchor="middle"
alignment-baseline="middle"
fill="orange"
filter="url(#conform)">
Logo
</text>
</svg>
</template>
功能拓展
效果实现后,可以来点功能拓展,比如文本自定义、文本颜色自定义、背景图修改等。这些可以尝试一下。