我做前端这些年,被问得最多的一个“灵异现象”是:给按钮写了background: linear-gradient(...),再配上transition: background 0.3s,鼠标移上去颜色直接“啪”地跳过去,一点过渡都没有。很多人第一反应是浏览器不支持、是 bug、是写法有问题,然后开始翻文档、换all、加will-change,全都没用。问题根本不在过渡,在于你给background这个简写塞进去的东西,本质上是css3 渐变,而渐变属于<image>类型,不属于<color>类型,浏览器在默认情况下不会把两张渐变图当作可以插值的两个状态。这一条认知不打通,后面所有的渐变写法都会别扭。
这篇内容我打算把两件事揉在一起讲:一是CSS3 渐变(linear、radial、conic 三兄弟,加上 repeating 变体)的角度坐标系、色标规则和尺寸关键字;二是文本格式化里那一堆被严重低估的属性——text-shadow、background-clip: text、text-decoration的子属性、white-space、word-break、overflow-wrap、text-overflow之间的关系网。适合已经能写 CSS、但总觉得“样式写着写着就玄学”的初中级前端,也适合做设计还原时经常卡在细节上的同学。我会把每个属性“为什么长这样”讲清楚,再给你能直接抄的组合写法。
1. 渐变的真实身份是 image,不是 color
先把最根上的事情说透。CSS 里background这个简写属性其实同时控制background-color和background-image两套东西。background-color: red赋值的是一个颜色,颜色是可以插值的——红到蓝之间,浏览器知道怎么算出中间态。而background-image: linear-gradient(red, blue)赋值的是一个图像,图像和图像之间,浏览器默认不会去猜“这两张图怎么渐变到彼此”。
1.1 为什么 transition 对渐变无动于衷
这里有个很隐蔽的细节:如果你写的是background-image: linear-gradient(...),那transition: background-image是无效的;如果你写的是简写background: linear-gradient(...),transition: background会尝试去过渡,但它能过渡的只有background-color那一部分,background-image那一部分被直接跳过,所以你看到的效果就是“瞬间切换”。这不是兼容问题,是规范层面的行为。
我第一次遇到这个问题时,试图用transition: all 0.3s强行解决,结果依然无效,还额外引入了一堆意外过渡。后来才想明白:all只是把“所有可过渡属性”都列了一遍,background-image本来就不在可过渡的名单里。
那想要渐变之间平滑变化,业内通行的做法有三种,各自的代价我列在下面:
| 方案 | 写法要点 | 优点 | 代价 |
|---|---|---|---|
| 双层叠加 + opacity | 父元素放默认渐变,伪元素放目标渐变,只切换伪元素opacity | 兼容性最好,性能可控 | 需要额外一层,DOM 结构要留位置 |
@property注册自定义属性 | 声明--c1为<color>类型,在渐变里引用它,再对--c1做 transition | 写法干净,纯 CSS | 需要较新的浏览器,老环境要降级 |
| 直接换 class + 无过渡 | 放弃动画,接受硬切 | 零成本 | 视觉效果打折 |
第二种展开说一下,它是目前最“优雅”的路子:
@property --grad-start { syntax: "<color>"; inherits: false; initial-value: #ff6b6b; } .btn { --grad-start: #ff6b6b; background-image: linear-gradient(120deg, var(--grad-start), #4ecdc4); transition: --grad-start 0.35s ease; } .btn:hover { --grad-start: #845ef7; }关键点在于@property给--grad-start声明了明确的syntax: "<color>"。不声明的话,自定义属性默认是“未解析的字符串”,浏览器不知道它是颜色,自然也没法插值。这个坑我在一个卡片项目里踩过整整一个下午,写了个transition: --x 0.3s死活不动,加上@property立刻就好了。
1.2 渐变写在 background 简写里的顺序陷阱
还有一个新手高频翻车点:background简写里,background-color必须写在最后,因为它只有这一个颜色值,而渐变是 image。如果你写成:
/* 错误示范 */ .card { background: #fff linear-gradient(180deg, #f8f9fa, #fff); }浏览器解析时会因为#fff出现在 image 之前而直接判定整条声明无效,整个背景消失。正确写法是:
.card { background: linear-gradient(180deg, #f8f9fa, #fff) #fff; }提示:只要用了
background简写,background-size、background-repeat、background-position都会被重置成默认值。如果你在别处单独设置过它们,简写会把它们统统冲掉。我的习惯是背景图相关一律拆开写,只有纯色填充才用简写。
2. linear-gradient 的角度坐标系与色标规则
线性渐变的语法看着简单,但角度和色标这两块,几乎每个人都记反过一次。
2.1 0deg 朝上,这事和数学课本是反的
CSS 的角度系统是这样的:0deg 指向正上方,90deg 指向正右方,角度按顺时针递增。也就是说:
0deg=to top90deg=to right180deg=to bottom(这是省略角度时的默认值)270deg=to left
为什么容易记混?因为数学课本和很多图形库(比如 Canvas 的arc)里,0 度指向正右方,角度逆时针递增。两套坐标系完全不一样,切过来的时候脑子必须手动转一下。我的记忆方式是:把它想成钟表,12 点方向是 0,指针顺时针走,3 点是 90,6 点是 180,9 点是 270。
还有一个更隐蔽的点:用to关键字时,角度到底是多少,取决于盒子的宽高比。linear-gradient(to top right, red, blue)里的to top right并不是 45deg,它是“从左上角指向右上角那个方向”,如果盒子是 400×100 的横条,这个方向大概是 14 度左右;如果盒子是 100×400 的竖条,就变成 76 度左右。所以你在一个宽盒子上调好的to top right渐变,挪到方盒子上颜色分布会明显不同。
需要“无论盒子什么形状,渐变方向都稳定”时,用角度值,别用to关键字。这是我在做响应式卡片时的固定习惯。
2.2 色标位置省略、乱序、双位置分别会发生什么
色标(color stop)的完整写法是颜色 位置,位置可以是百分比也可以写长度。这里有三个规则值得吃透:
规则一:不写位置的色标会自动均分。linear-gradient(red, green, blue)等价于三个色标分别落在 0%、50%、100%。如果只写linear-gradient(red, green 60%, blue),那 red 在 0%、green 在 60%、blue 在 100%。浏览器会自动把第一个色标补到 0,最后一个补到 100。
规则二:位置乱序时,浏览器会自动抬升。你写linear-gradient(red 80%, green 20%),浏览器不会报错,而是把 green 的位置抬到 80%,结果就是 80% 之前全是 red,之后全是 green,中间没有过渡。这个行为在 conic-gradient 里做饼图时是核心技巧,在线性渐变里则经常是“颜色怎么突然断了”的元凶。
规则三:双位置语法可以做出硬边。现代浏览器支持颜色 起点 终点的写法:
.stripes { background-image: linear-gradient( 90deg, #212529 0 25%, #f8f9fa 25% 50%, #212529 50% 75%, #f8f9fa 75% 100% ); }这四段会拼出清晰的竖条纹,中间完全没有模糊过渡。以前要实现同样效果,得写成#212529 25%, #f8f9fa 25%, #f8f9fa 50%, #212529 50%这种“同位置重复”的笨办法,双位置语法把可读性拉回来了不少。
关于颜色提示点,还有个少见的用法:在两个色标之间插入一个只有位置没有颜色的值,用来控制中点位置。比如linear-gradient(red, 20%, blue)表示红蓝的中点被拉到 20% 的位置,红色区域被压缩。做那种“大部分是浅色、边缘快速转深”的卡片底色时很好用。
3. radial 与 conic:尺寸关键字和饼图累加规则
线性渐变之外的两个兄弟,用法上坑更多,因为它们的默认值经常不是你想要的。
3.1 farthest-corner 这个默认值让渐变“没渐变完”
径向渐变的完整语法是radial-gradient(形状 尺寸关键字 at 圆心位置, 色标...)。形状默认是ellipse(椭圆),尺寸关键字默认是farthest-corner(最远的角)。
farthest-corner的意思是:让渐变的边缘刚好碰到距离圆心最远的那个角。这意味着渐变的“100% 位置”通常落在盒子外面,盒子里只能看到渐变的一段,颜色往往“没走完全程”就结束了。这是很多人写radial-gradient(#fff, #000)却看不到完整黑白过渡的原因。
四个尺寸关键字的行为对照:
| 关键字 | 渐变边缘落在哪 | 典型用途 |
|---|---|---|
closest-side | 最近的边 | 想要渐变在小盒子里完整走完 |
closest-corner | 最近的角 | 圆形头像的光晕 |
farthest-side | 最远的边 | 长条元素的背景光 |
farthest-corner | 最远的角(默认) | 大面积的柔和扩散光 |
实测下来,做卡片高光、按钮内发光这类效果,用closest-side更可控,因为它的渐变范围始终在盒子内部,不会“跑出去”。
圆心位置用at控制,at 30% 40%就是横向 30%、纵向 40% 的位置,也可以写at top left、at center。写光斑效果时这个参数比尺寸关键字更关键,光斑放偏一点,整个卡片的质感就不一样。
3.2 conic-gradient 画饼图的色标累加规则
圆锥渐变的角度从 12 点方向开始,顺时针递增,这点跟线性渐变的“0 度朝上”是一致的。它的杀手锏是做饼图和数据环。
饼图的标准写法是这样:
.pie { width: 160px; height: 160px; border-radius: 50%; background-image: conic-gradient( #ff6b6b 0 40%, #4ecdc4 0 70%, #845ef7 0 90%, #dee2e6 0 100% ); }注意中间那些0的写法。这里的规则是:如果某个色标的起点小于前一个色标的终点,浏览器会自动把它抬升到前一个终点的位置。所以第二段写#4ecdc4 0 70%,那个 0 会被自动抬到 40%,实际就是从 40% 到 70%。这样写的好处是不需要手动计算每一段的起点,改数据时只改终点就行,维护成本低很多。
同样的规则也适用于conic-gradient做色轮、加载环、进度圈。做进度圈时,可以用一个变量控制进度百分比:
.ring { --progress: 65%; border-radius: 50%; background-image: conic-gradient(#845ef7 var(--progress), #e9ecef 0); }这里#e9ecef 0的 0 会被抬到var(--progress)的位置,正好衔接上,一行搞定。
3.3 repeating 系列为什么间距总是不对
repeating-linear-gradient、repeating-radial-gradient、repeating-conic-gradient三个变体,重复周期的计算逻辑是:以最后一个色标的位置为周期长度。这听起来简单,实际写起来经常翻车。
问题出在“如果色标没写位置,周期会是多少”。比如:
/* 周期不确定的写法 */ .bad { background-image: repeating-linear-gradient( 45deg, rgba(255, 255, 255, 0.06) 0, rgba(255, 255, 255, 0.06) 10px, transparent 10px, transparent 20px ); }这段是对的,因为每个色标位置都写清楚了,周期就是 20px。但如果有人图省事写成repeating-linear-gradient(45deg, #000, #fff),两个色标的位置是 0 和 100%,那么“100%”指的是整个渐变区域的长度,重复一次就铺满,看不出条纹。
所以写 repeating 系列的固定套路是:每个色标都补上长度值,最后一个色标的长度就是条纹周期。用双位置语法会更清楚:
.stripes-fixed { background-image: repeating-linear-gradient( 45deg, rgba(0, 0, 0, 0.05) 0 8px, transparent 8px 16px ); }16px 就是条纹间距,改这个数字就能调密度,不用动其他任何地方。
4. 文本阴影、文字渐变与装饰线
渐变讲完,转文本这一块。文本格式化里被用得最多、也最容易用歪的,是text-shadow和background-clip: text这两条链路。
4.1 text-shadow 的多层叠加与描边替代方案
text-shadow的语法是水平偏移 垂直偏移 模糊半径 颜色,四值。多项之间用逗号分隔,前面的阴影绘制在上层,后面的在下层。这个顺序很重要,做多层发光时如果顺序反了,光晕会被压在文字底下看不见。
一个常见需求是给文字加描边。CSS 有没有原生的文字描边?有,-webkit-text-stroke,但它只支持-webkit-前缀,而且它的描边是居中的,会吃掉一部分字形,细笔画会糊成一团。所以在实际项目里,我更多用text-shadow的四向偏移来模拟描边:
.text-outline { color: #fff; text-shadow: 1px 0 0 #212529, -1px 0 0 #212529, 0 1px 0 #212529, 0 -1px 0 #212529; }这个方案的缺点很明显:四个方向只能覆盖横竖,斜角处会有缺口,所以描边不能太粗。要做 2px 以上的描边,四向就不够了,得写八向甚至十六向,代码会膨胀。这种时候我会退回-webkit-text-stroke,接受它“吃字形”的代价,然后再用paint-order: stroke fill调整绘制顺序:
.text-stroke-2 { -webkit-text-stroke: 2px #212529; paint-order: stroke fill; }paint-order让描边画在填充下面,字形就不会被吃掉,这是很多人不知道的一个细节。
多层发光则是另一回事,text-shadow堆叠三四层,模糊半径依次增大:
.glow { color: #f8f9fa; text-shadow: 0 0 4px rgba(78, 205, 196, 0.8), 0 0 12px rgba(78, 205, 196, 0.5), 0 0 24px rgba(78, 205, 196, 0.3); }注意:
text-shadow的模糊半径和box-shadow的算法一致,但阴影不占据布局空间,也不会触发滚动条。阴影太重时性能会有感知,尤其是在滚动列表里给每一项都加三层阴影。我的经验是列表项最多两层,且模糊半径控制在 16px 以内。
4.2 文字渐变:background-clip 那条链路每一步都有坑
文字渐变效果现在的标准写法是:
.gradient-title { background-image: linear-gradient(90deg, #ff6b6b 0%, #845ef7 100%); -webkit-background-clip: text; background-clip: text; color: transparent; }这一条链路上至少有四个坑,我逐个说。
坑一:背景尺寸是按 padding box 计算的,不是按文字范围。如果你的标题元素有左右 padding,那渐变的起止点会覆盖到 padding 区域,文字只占渐变中间的一段,颜色分布跟你心里想的完全不一样。解决办法有两个:给文字套一层display: inline-block的内层元素,把渐变写在内层上;或者用background-size手动校准。
坑二:color: transparent会继承。如果标题里有<span>强调词,它会跟着变透明,除非再给它单独设回颜色。用-webkit-text-fill-color: transparent更安全一些,它不影响color的继承,也不会破坏子元素的颜色:
.gradient-title { background-image: linear-gradient(90deg, #ff6b6b, #845ef7); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }坑三:挑选中的文字看不见。因为填充色被设成透明,用户框选时高亮区里看不到字。修复方式是给::selection单独设置:
.gradient-title::selection { background: #845ef7; -webkit-text-fill-color: #fff; }坑四:background-clip: text在不支持的环境下会退化成什么。标准属性background-clip: text现在主流浏览器都支持了,但如果是很老的环境,它会静默失效,结果是“整个文字块背后铺了一块渐变方块”,视觉上非常难看。稳妥的降级办法是配合@supports:
@supports (background-clip: text) or (-webkit-background-clip: text) { .gradient-title { background-image: linear-gradient(90deg, #ff6b6b, #845ef7); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; } }4.3 text-decoration 的新增子属性
text-decoration以前只有一个“简写 + 几个值”的粗放写法,现在它已经拆成了一套子属性,做下划线细节时非常好用:
| 子属性 | 作用 | 常用值 |
|---|---|---|
text-decoration-line | 装饰线位置 | underline/overline/line-through |
text-decoration-color | 装饰线颜色 | 任意颜色 |
text-decoration-style | 装饰线形状 | solid/double/dotted/dashed/wavy |
text-decoration-thickness | 装饰线粗细 | 1px/auto/from-font |
text-underline-offset | 下划线与文字的距离 | 2px/0.2em |
text-decoration-skip-ink | 下划线跳过字母下伸部 | auto/none |
其中text-underline-offset和text-decoration-thickness是我用得最多的两个。默认下划线离文字太近,字母的降部(比如 g、p、y 的下半截)会跟线粘在一起,加上text-underline-offset: 3px立刻就干净了。
text-decoration-skip-ink: auto是默认值,它会让下划线在遇到字母下伸部时自动断开,视觉上更清爽;但做那种“粗线贯穿”的强调效果时,我会把它设成none,让线连续不断地穿过去。
还有一个不常用但很好玩的text-underline-position: under,它把下划线放到文字降部以下的位置,配合text-decoration-thickness做那种“设计感下划线”非常合适。
5. 溢出、断行与省略号的三角关系
这一块是 CSS 文本格式化里最容易出问题的地方,因为涉及的属性名字太像,功能互相交叠。
5.1 单行省略那三件套缺一不可
text-overflow: ellipsis本身什么都不做,它只是一个“声明”——告诉浏览器“如果有溢出,用省略号表示”。要让溢出真的发生,必须同时满足三个条件:
.ellipsis { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }white-space: nowrap阻止文本换行,让内容真的超出容器宽度overflow: hidden把超出部分裁掉text-overflow: ellipsis在这条裁切线上画上省略号
少任何一个,省略号都不会出现。我见过太多人只写了text-overflow: ellipsis,然后纳闷为什么不生效。还有一个隐性条件:容器必须有确定的宽度。如果容器在 flex 布局里,父级又没约束宽度,容器会被内容撑开,永远不溢出,省略号自然也不会出现。这种场景要给容器加min-width: 0或者overflow: hidden。
多行省略是另一套写法,用的是-webkit-box:
.clamp-2 { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }它的坑在于display: -webkit-box会覆盖掉元素原本的display,如果这个元素本来是个 flex 容器,布局会整个塌掉。所以我一般会套一层:外层管布局,内层管文本截断。
<div class="card-title-wrap"> <h3 class="clamp-2">一段很长的标题文字...</h3> </div>.card-title-wrap { display: flex; align-items: center; } .clamp-2 { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; min-width: 0; }5.2 white-space 六个值的实际差别
white-space控制的是“空白字符(空格、制表符、换行符)怎么处理”和“能不能自动换行”两件事。六个值的组合方式用表格看最清楚:
| 值 | 连续空格 | 源码换行符 | 自动换行 |
|---|---|---|---|
normal | 合并成一个 | 合并成一个空格 | 允许 |
nowrap | 合并成一个 | 合并成一个空格 | 禁止 |
pre | 原样保留 | 原样保留 | 禁止 |
pre-wrap | 原样保留 | 原样保留 | 允许 |
pre-line | 合并成一个 | 原样保留 | 允许 |
break-spaces | 原样保留 | 原样保留 | 允许(行尾空格也保留) |
pre和pre-wrap的差别只在换行:pre会横向撑破容器,pre-wrap会在容器边缘折行。做代码块展示时,我用pre-wrap配合横向滚动作为兜底,这样长命令既能折行又不会丢缩进。
pre-line是个很实用的中间态:它会保留源码里的换行符(用户输入的换行会显示出来),但会合并多余空格。做评论区、留言展示时用这个最合适——用户敲的回车有反应,连续空格不会撑出一堆空白。
break-spaces是后来补的值,它跟pre-wrap的区别是行尾的空格不会被吃掉,而是折到下一行占位。这个值的实际项目用途很少,但在做等宽文本对齐时偶尔会用到。
5.3 word-break 与 overflow-wrap 的分工
这两个属性都能“让长单词换行”,但作用机制完全不同,混用会导致布局尺寸计算出现意外。
word-break: break-all的规则是:任意两个字符之间都允许断行,包括英文单词中间的字母。它的副作用是会影响元素的min-content尺寸计算——因为任何位置都能断,浏览器认为这个元素的最小宽度可以是“一个字符宽”,于是 flex 布局里它会被压得非常窄。
overflow-wrap: break-word的规则是:优先按正常单词断行,只有当整词放不下时才从中间断开。它不影响min-content的计算,元素的最小宽度仍然是“最长的那个单词”的宽度。
这个差异在 flex 布局里特别关键。我之前做过一个标签列表,标签文字里有个特别长的英文标识符,用word-break: break-all之后,整个 flex 行被压扁,标签全挤成一列,查了半天才定位到这个属性上。换成overflow-wrap: break-word配合min-width: 0,问题立刻消失。
还有一个overflow-wrap: anywhere,它跟break-word的区别是:anywhere会在计算min-content时把“任意位置可断”考虑进去,所以它确实会缩小元素的最小宽度。需要“强制容器可以缩得很窄”的场景用它,其他场景用break-word。
中文的断行默认规则跟英文不同:中文任意两字之间都可以断,所以中文长文本不需要word-break干预就能正常折行。但如果你想在中文环境下做“整词不断”,可以用word-break: keep-all,它会让 CJK 文本按词组断行——前提是文本里真的有空格或标点分隔,否则会整段不换行撑出屏幕。
6. 把渐变和文本属性拼起来的几个常用组合
前面拆开讲了,这节讲怎么拼。下面这几个组合是我在项目里反复复用的,直接抄就能跑。
6.1 渐变边框的三种写法对比
做“渐变描边卡片”是高频需求。三种做法的实现和代价差别很大:
| 做法 | 核心写法 | 优点 | 缺点 |
|---|---|---|---|
border-image | border: 1px solid transparent+border-image: linear-gradient(...) 1 | 一行搞定 | 圆角会失效,永远直角 |
| 双背景叠加 | background: linear-gradient(#fff,#fff) padding-box, linear-gradient(...) border-box+border: 1px solid transparent | 支持圆角,纯 CSS | 内层背景必须是不透明的实色 |
| 伪元素 + mask | 伪元素铺满父级,渐变背景 +mask挖空内部 | 支持圆角、支持透明内层 | 代码略长,要注意层级 |
第二种是我最常用的,因为它代码最短又能保圆角:
.grad-border-card { border: 1px solid transparent; border-radius: 12px; background: linear-gradient(#ffffff, #ffffff) padding-box, linear-gradient(135deg, #ff6b6b, #845ef7) border-box; }原理是:padding-box那层背景只铺在内边距区的内部,border-box那层铺到边框外沿,两层叠加后,边框区域露出的就是渐变,内部被白底盖住。所以内层背景必须写不透明色,如果你想要半透明卡片,这套方案就不行了,得换第三种。
第三种用mask做挖空:
.grad-border-mask { position: relative; border-radius: 12px; } .grad-border-mask::before { content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 1px; background: linear-gradient(135deg, #ff6b6b, #845ef7); -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude; pointer-events: none; }这里padding: 1px决定了描边粗细,mask-composite: exclude把内容区的遮罩挖掉,只留下 1px 的环。这套写法支持透明内层,也支持圆角,代价是多一层伪元素和几行前缀属性。
6.2 数字表格对齐与竖排文字
表格里数字列不对齐,是设计还原时最容易被挑出来的细节。默认字体里数字宽度不一致(尤其是1比0窄很多),一列数字排下来参差不齐。解决方案是使用等宽数字:
.num-cell { font-variant-numeric: tabular-nums; }这一行让所有数字占用相同宽度,小数点自然对齐。如果你还要控制小数位数对齐,那就得上font-feature-settings或者干脆用text-align: right配合固定宽度。
竖排文字用writing-mode:
.vertical-label { writing-mode: vertical-rl; text-orientation: upright; letter-spacing: 2px; }vertical-rl是竖排从右往左,符合传统中文阅读习惯。text-orientation: upright让拉丁字母也立起来(默认是旋转 90 度)。这里有个坑:竖排之后,width和height在视觉上像是交换了,text-align控制的是纵向对齐,margin的方向也跟着转。我第一次用的时候调了半天 padding,就是因为思维还停留在横排。
6.3 一条容易忘记的排版细节:字体平滑
最后补一个不属于渐变也不属于严格意义上的文本格式化,但跟文字渲染质量直接相关的属性:
body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }这两行让 macOS 上的字体渲染从“次像素抗锯齿”切成“灰度抗锯齿”,文字看起来会更细更清晰。代价是字重看起来会变轻,如果你的设计里正文本来就用的是font-weight: 300,加上这两行之后可能会细到看不清。所以我一般只在标题和按钮上开,正文保持默认。
做完这几块,回头看最开始那个“渐变不能过渡”的问题,其实答案一直很清楚:搞清楚一个属性接受的数据类型是什么,比记住它的语法重要得多。渐变是图像,图像和图像之间默认不插值;text-overflow是个声明,声明背后需要overflow和white-space撑住;word-break和overflow-wrap都能断词,但一个改的是断行规则,一个改的是溢出兜底。
我在实际项目里踩过最久的一个坑,不是上面任何一个属性本身,而是把它们串起来时的相互覆盖——background简写冲掉了background-size,display: -webkit-box冲掉了 flex,color: transparent继承了子元素。所以现在的习惯是:只要一个元素同时用了渐变和多行截断,我一定先把它拆成两层结构,外层管布局,内层管视觉。多写一个div看起来笨,但排查问题的时候能省掉半小时。
7. 实测下来最值得记住的几条
把上面这些压缩成几条能背下来的结论,方便你下次写样式时快速对照:
- 渐变是
<image>,不是<color>,所以transition: background对渐变无效,要做渐变过渡就上@property或者伪元素叠opacity。 - 角度 0deg 朝上、顺时针递增;
to top right不是 45deg,它的实际角度由盒子宽高比决定。 radial-gradient的默认尺寸是farthest-corner,渐变范围常常超出盒子,想要完整过渡就用closest-side。conic-gradient里色标起点小于前一段终点时会自动抬升,这是饼图不用手算起点的原因。repeating-*系列的周期等于最后一个色标的位置,每个色标都要补长度值。text-overflow: ellipsis需要overflow: hidden+white-space: nowrap+ 确定宽度三件套。word-break: break-all会改变min-content计算,flex 布局里优先用overflow-wrap: break-word+min-width: 0。- 文字渐变用
-webkit-text-fill-color: transparent比color: transparent安全,别忘了补::selection的样式。
最后再分享一个小技巧:调试渐变时,我会临时把background-size设成100% 100%并加一个outline: 1px solid red,先把盒子的实际边界看清楚,再判断渐变是“没走完”还是“超出去”了。很多时候颜色不对不是色标写错了,是盒子的实际尺寸跟你以为的不一样,尤其是元素被 flex 拉伸或者被box-sizing影响的时候。