关键帧动画里写了 display 这种不可插值的属性,浏览器会怎么处理?
关键帧中写入不可平滑插值的属性时,动画会按离散规则切换,而不是产生连续变化。display 与 visibility 的切换时机不完全一样;做淡出或退出效果时,通常需要把透明度动画与元素最终隐藏的时间点协调起来。
CSS面试题第 3 页,显示第 101–150 题,共找到 240 道完整解析,可继续按分类、标签与关键词缩小范围。
按稳定语义路径排序
关键帧中写入不可平滑插值的属性时,动画会按离散规则切换,而不是产生连续变化。display 与 visibility 的切换时机不完全一样;做淡出或退出效果时,通常需要把透明度动画与元素最终隐藏的时间点协调起来。
transform 中多个变换函数会按矩阵顺序组合;先写 rotate 再写 translate,与反过来写会得到不同轨迹。父子坐标系和变换原点还会影响视觉结果,排查“位移方向不对”时应先看函数次序。
渐变文字通常把 linear-gradient 作为背景,再用 background-clip: text 裁到字形内,并让文字填充透明。缺少其中一步可能只看到普通文字或整块背景;浏览器前缀、选中态和暗色模式还会影响最终可读性。
系统开启减少动态效果后,页面应减少大幅位移、闪烁或自动播放,必要的状态反馈仍可保留。prefers-reduced-motion 媒体查询可切换时长或替换动画形式;只把动画时长改成极短值,可能影响依赖动画结束事件的代码。
radial-gradient 可用 circle 或 ellipse 约束渐变形状,用 at 调整中心点,再用 closest-side、farthest-corner 等关键字决定终点。容器长宽变化会改变椭圆的观感;背景位置和渐变中心也不能当成同一个参数。
减少动态效果的偏好不只影响 CSS 动画,还涉及平滑滚动、脚本驱动的过渡和第三方动画库。CSS 可用媒体查询覆盖相关属性,JavaScript 可借助 matchMedia 读取并监听变化;设置切换后运行中的动画也应得到处理。
steps() 把连续时间切成离散跳变,常用于打字机效果和逐帧精灵图;它不会像 linear 那样在两帧之间平滑插值。步数、跳变发生在区间起点还是终点,以及文字宽度与字符数是否匹配,都会影响最后一帧。
CSS perspective 决定三维变换的透视强度:距离值越小,近大远小越明显;perspective-origin 则改变观察中心。父元素设置 perspective 与元素自身使用 perspective() 函数的作用范围不同,翻转卡片时还要检查背面可见性。
transform-origin 决定 rotate、scale 等变换围绕哪里进行,同样旋转角度,中心点与左上角作为原点会画出不同路径。百分比原点相对元素自身盒子计算,变换后的视觉位移还与元素尺寸有关。
父元素应用 transform 后会为固定定位后代建立新的包含块,position: fixed 子元素可能不再固定于视口,而是跟随父组件。需要视口级弹层时,可把元素通过 Portal 移出该祖先,或避免在祖先上施加变换。
transform-style: preserve-3d 让子元素保留在父元素的三维空间中,flat 则把它们压到父元素平面。翻牌与立方体效果需要检查父子两级的设置;某些会产生分组绘制的属性也可能迫使结果变平。
独立的 rotate、scale、translate 属性可分别过渡,并按固定次序与 transform 组合;它们不等同于随意调换 transform 函数顺序。迁移旧动画时要检查最终变换矩阵、级联覆盖和目标浏览器支持情况。
translate 百分比是相对元素自身的宽高,不是父元素。translateX 百分比参照自身宽度,translateY 参照自身高度。这个特性常用于不知道元素尺寸时的居中定位。
transitionend 会按实际完成过渡的属性分别触发,可用 propertyName 过滤需要等待的那一个。过渡被中途取消可能触发 transitioncancel 而没有 transitionend;时长为零、元素被移除或目标值未改变时,也不能盲等结束事件。
height 从 0 到 auto 通常缺少可直接插值的明确终点,展开面板需要选择替代策略。max-height 技巧会让时长随内容变化,Grid 行高方案依赖布局结构;支持 interpolate-size 的环境可直接处理固有尺寸,但仍要考虑兼容性。
过渡未完成就更换目标值,浏览器通常从当前插值状态转向新目标,反向过渡还可能采用缩短后的时长。按钮连续悬停或抽屉快速开合会暴露这一点;若看到状态跳动,应确认是过渡被打断还是动画被重新创建。
同一元素的透明度和位移可以分别指定过渡时长、缓动曲线和延迟,transition 简写里的逗号会形成多组属性设置。列表长度不一致时值会循环匹配;面板开合时应对照计算后的样式,确认每项声明落到了预期属性上。
对比 transition-property 取 all 与显式列出属性的实际差异:浏览器只为变化属性创建过渡,帧开销接近;真正区别在意外过渡触发、时长不可拆分和维护风险。
cubic-bezier() 的四个数定义控制点;两个 x 坐标必须在 0 到 1 之间,y 坐标可以越界并产生回弹或超冲。ease 等关键字对应固定曲线,自定义动效时要同时观察起步、收尾和中段速度,不能只看总时长。
transition 需要同一元素的计算后样式发生变化,并且浏览器能识别变化前后的状态。颜色、透明度等属性可插值,display 等离散属性要配合 transition-behavior: allow-discrete;入场还常需 @starting-style 给出起始状态。
只把元素 opacity 降为零,透明区域仍可能接收点击和焦点。把 visibility 的切换延后到淡出完成,可让退出动画结束后再隐藏;重新显示时延迟规则也要配套调整,否则元素可能先不可见再突然出现。
transition 适合按钮悬停、面板开合这类在两种状态间切换的效果;animation 适合多关键帧、循环或自动播放。两者的触发方式、暂停控制和结束状态处理不同,选型应取决于动效是否需要独立时间线。
flex 容器里的绝对定位子项不参与弹性布局,不占空间也不被 flex-grow 分配。但容器加了 position: relative 后仍然是它的包含块,定位坐标从容器 padding 边开始算。
默认不换行的 Flex 容器只有一条 flex 行,align-content 没有可分配的行间空间,设置它通常看不到效果。单行子项的交叉轴位置由 align-items 控制;多行容器还需有多余的交叉轴空间才能体现行组对齐。
多行 Flex 容器只有交叉轴留有空白时,线与线之间的剩余空间才会被分散;只有一行或容器高度随内容增长时,改这个值可能看不到效果。通过固定高度的两行卡片对照项目对齐和线组对齐。
align-content 管的是多条 flex line 之间的交叉轴空间分配,align-items 管的是每条 line 内部子项的对齐。两者作用层级不同,必须配合 flex-wrap: wrap 才能看到 align-content 的效果。
flex-direction: column 时交叉轴变成水平方向,align-items: center 让子项水平居中。很多人以为 align-items 永远管垂直方向,其实它管的是交叉轴,方向随 flex-direction 变化。
align-items 的默认值是 stretch,会让子项在交叉轴方向拉伸填满 flex line 的高度。但前提是子项没有设显式高度,一旦写了 height,stretch 就不起作用了。
align-self 让单个 flex 子项覆盖容器的 align-items 设定,独立控制自己在交叉轴上的对齐方式。它和 justify-content 互不干扰,一个管交叉轴,一个管主轴。
flex 子项在交叉轴方向设 margin auto 会吸收行内所有剩余空间,效果相当于覆盖了 align-items。比如 margin-top: auto 把子项推到底部,比 align-self: flex-end 优先级更高。
flex-grow 和 margin auto 都想吃剩余空间,但 auto margin 先结算。margin auto 吃完空间后 flex-grow 就无事可做了。空间不够时 auto margin 变成 0,shrink 正常工作。
align-items: baseline 让 flex 子项按第一行文字的基线对齐,而不是按盒子的边缘。当子项字号不同或 padding 不同时,文字仍然整齐排列。适合混排按钮、标题和标签的场景。
flex 布局的核心是两条轴:主轴和交叉轴。主轴由 flex-direction 决定,交叉轴永远垂直于主轴。理解了轴的概念,justify-content 和 align-items 的方向就不会搞混。
flex-direction: column 加 flex-wrap: wrap 时,align-content: stretch 会让各列在交叉轴(水平方向)上等分容器宽度。每列分到相同的宽度,子项在各自列里占满这个宽度。
纵向排列的 Flex 项要换列,容器必须提供可用的主轴高度;每列的项目按这个高度分组,而列宽取决于项目与剩余横向空间。对比固定高度分栏和真正瀑布流,说明为何列底会留白、默认拉伸也不保证各列等宽。
多行 flex 容器没有显式高度时,容器高度由内容撑开。每行的高度等于行内最高子项的高度,行与行紧挨着排列,没有多余空间给 align-content 分配。 同时说明未限定高度时为何通常只随内容增长。
flex 交叉轴永远垂直于主轴。flex-direction: row 时交叉轴垂直,column 时交叉轴水平。align-items 和 align-content 都作用在交叉轴上,方向随 flex-direction 变化。
移动端导航使用不同的方向与换行组合,会决定项目是水平换行还是纵向换列。结合固定高度、收缩因子和沟槽计算,说明默认单行布局为何仍可缩小,以及响应式卡片一行三列时如何准确扣除两道间距。
flex-basis: auto 会先看子项有没有设 width,有就用 width,没有就按内容大小。flex-basis: content 则完全忽略 width,始终按内容大小来算。两者在子项没设 width 时效果一样。
flex-basis 百分比相对容器的主轴内部尺寸计算。容器没有明确尺寸时百分比回退为 content。还要注意 flex-basis: 0 和 flex-basis: 0% 的区别:0 不会触发百分比解析,0% 会。
flex-direction: row 让子项水平排列,column 让子项垂直排列。切换方向后 justify-content 和 align-items 管的方向也跟着翻转。column 下子项的宽度默认填满容器,高度由内容决定。
flex-grow 分配的是容器剩余空间,不是总空间。计算方式:先算出剩余空间(容器 - 所有子项 flex-basis 之和),再按各子项 flex-grow 的比例分配。flex-grow: 2 的子项比 1 的多分一倍。
flex-grow 的默认值是 0,意味着子项不会增长来填满剩余空间。子项保持 flex-basis 的尺寸。想让子项填满空间要显式设 flex-grow: 1 或用 flex: 1 缩写。
flex 项空间不足时,每项收缩多少由 flex-shrink 乘以 flex-basis 的加权比例决定。用一组具体数字走完计算过程,弄清公式和 min-width 的影响。
头像旁的长标题设置了收缩却仍把页面撑宽,通常卡在横向 Flex 项的自动最小宽度。通过检查盒子实际尺寸、给正确层级设置零最小宽度,再选择换行或省略方案,弄清收缩计算与内容绘制分别由谁负责。
工具栏按钮设置不收缩后,是否溢出仍取决于容器余量、其他项目的收缩能力和最小尺寸。用由宽到窄的过程观察负空间怎样转移,区分按钮保宽、搜索框收缩和最终横向滚动三个阶段。
响应式卡片使用 Flex 换行时,项目先分到不同的线,每条线再独立计算伸缩与剩余空间。解释为什么最后一排只有一张卡片时可能突然拉宽,并说明需要严格跨行列对齐时应该怎样选择布局方式。
购买按钮用排序属性提前显示,视觉位置会改变,但 DOM、读屏和键盘焦点顺序不会跟着重排。结合相同排序值、换行时的项目分组和交互路径,判断哪些装饰性调整可以用排序属性,哪些必须调整源顺序。
flex-start 和 flex-end 指向主轴的起点与终点,不保证永远对应屏幕左、右。flex-direction 改成 column 或 row-reverse 后方向会变化,RTL 文本方向也会改变 row 的起点;图标靠边布局要先确认主轴朝向。
过宽工具栏强行居中可能让起始侧按钮难以访问,安全对齐可在出现这类溢出风险时回退到起始侧。说明它与普通居中、非安全对齐的表现差异,并区分对齐策略与缩小、换行、滚动等容量处理。