【CSS】1203- 分享 20 个防御式 CSS 开发经验
共 5388字,需浏览 11分钟
·
2022-01-20 04:05
本文原作者为阿里巴巴克军,转载请注明原作者
本文已获得原作者授权
0.前言
当前CSS开发的现状不容乐观,扫了一圈,发现各种问题。前端开发更多关注点还是在JavaScript上,技术性相对更强。
但从前端技术的根本价值出发,实现高可用性的产品用户界面,是用户体验的第一道关,这就跟CSS开发的专业性紧密相关了。轻易改变一下窗囗大小,放大一下字体,页面就被拉垮,这样的产品品质高吗?
本文将涉及一些响应式开发内容,TOB产品同样需要响应式开发。以云安全中心为例,用户屏幕分辩率占比中1920x1080和2560x1440加起来达到52%。平时开发的15寸的本物理分辩率是1440x900只占9%。说明我们的企业用户大多用PC或用外接显示器。请注意:屏幕物理分辨率≠浏览器窗囗大小(如下图)。平时用外接显示器会有各种用法,横着用,坚着用,分屏显示窗囗等等(如封面)。因此,不能简单的依据屏幕分辨率进行设计和开发。我认为体现CSS开发专业性看的就是防御式CSS开发。
(数据来自css-tricks)
“防御性编程(Defensive programming)是防御式设计的一种具体体现,它是为了保证,对程序的不可预见的使用,不会造成程序功能上的损坏。它可以被看作是为了减少或消除墨菲定律效力的想法。”(引自wiki)
现在前端开发还是契约式的,也就是还原设计稿,这是远远不够的。设计稿往往只体现出UI的理想态。防御式CSS开发一部分是为了实现响应式设计,同时还包括适配动态内容,在各种情景下保持UI的完美性和健壮性。
1. 采用扁平化的HTML结构,用CSS控制布局
1-1. 避免用“布局组件”
这样会把模块限死在HTML结构中,不利于灵活的适配。
HTML的结构设计是基本前提,避免“表格思维”,避免多余的行 / 列元素(过度包装元素)。
如,这样设计:
<div class="overview-content">
<div class="sky-card overview-card">...div>
<div class="sky-card overview-card security-defense-card">...div>
<div class="sky-card overview-card">...div>
<div class="sky-card overview-card">...div>
div>
1-2. 不要用JavaScript控制布局
线上问题:
用CSS实现同样的效果:
2. 避免用float / position: absolute / display: table等方式布局
所有布局和对齐需求,无一例外用 Flexbox / Grids 实现。
3. 避免定高/定宽,用min-width/min-height替代
固定宽/高最容易出现的问题是内容溢出。没必要通过定宽高对齐,可以利用Flexbox的位伸/收缩特性。可以定义最小宽/高。
4. 避免侵入性(损人利自己)的写法
避免影响全局样式,如: * { ... }
、:root {...}
、div { ....}
等。避免影响通用组件样式,如: .next-card {...}
,如果要定制单加一个class名。不要直接修改全局CSS变量,把自己的CSS变量定义在模块的范围内。 不要写z-index:999。一般1~9,防止被遮挡10~99,绝对够用了。 不要在标签上定义style属性。不要在JS代码中做样式微调,这样今后无法统一升级CSS样式。 只有完全不可修改的样式才能用!important,利用选择器优先级调整样式。
5. 避免CSS代码的误改 / 漏改
将选择器拆开写,如 .card-a, .card-b { ... }
,写时方便,改时难,修改时容易影响其它元素,不如分开写(除非像css reset这种特别确定的情况)。将样式集中在一起,容易改错。保持CSS代码和文件在相应的层级上,同一模块的放一起。避免混入通用样式中,为了避免改错,允许适当冗余。 用@media时,会集中覆写一批元素的样式,更新样式时非常容易遗漏。所以必须拆开写,和对应模块的样式放在一起。不要集中放在文件底部,或是集中放在某一个文件里。 及时清除“死代码”。 定义样式要写全,微调样式要写具体,如:
.mod {
margin: 0;
}
/* 其它地方需要微调时 */
.biz-card .mod {
margin-bottom: 16px;
}
6. 避免CSS样式冲突
限定作用范围。如, .my-module .xxx { ... }
。业务代码中的样式要加前缀,或借鉴BEM命名方式。如: .overview-card-title { ... }
。用CSS Module也可以。注意选择器的精确性。级层过长过于复杂的CSS选择器会影响性能,但要注意:有时需要精确选择某些元素,如仅选择一级子元素, .overview-card-content > .item { ... }
。
7. 防止内容不对齐
受字体、行高等因素影响(如图),用Flexbox实现对齐最可靠:
height / line-height 不可靠。 display:inline-block / vertical-align:middle 不可靠。
用Flexbox实现对齐
8. 防止内容溢出
包括文字/图表等内容在宽度变化时或是英文版下容易出现溢出(如图)。
图表要支持自动 resize。 图片要限制大小范围,如:max-width、max-height min(100px, 100%)、max(100px, 100%)
注意:min() / max() 兼容性:chrome 79+ / safari 11 / firefox 75
不能固定宽/高。(见规则3) 不要在容器元素定义overflow:hidden
9. 防止内容过度拥挤
为了防止内容过长时紧帖到后面的内容,水平排列元素之间要设置间距,一般是8px。
如果用flexbox要加上gap。考虑到gap的兼容性:chrome 84,稳定起见用margin。
.item {
margin: 0 8px 0 0;
}
.item:last-child {
margin-right: 0;
}
10. 防止内容被遮挡
定义负值时(负margin / top / left),小心内容被遮挡,避免这么定义。定义margin统一朝一个方向,向下和向右定义,再重置一下:last-child。position: relative 平时很常用,发生遮挡时会造成链接无法点击(如图)。
11. 防止可点击区域过小
小于32x32像素的可点击元素,通过下面的方式扩大可点击区域:
.btn-text {
position: relative;
}
/* 比 padding 副作用小 */
.btn-text::before {
content: '';
position: absolute;
top: -6px;
left: -8px;
right: -8px;
bottom: -6px;
}
12. 防止内容显示不全 / 被截断
在定义 overflow:hidden
时,就要考虑内容是否有被截断的可能。一般不要加在容器元素上。防止长文字被生生截断(如图),加省略号。
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
不想折行,溢出加省略号,这都没问题。但忽略了对inline元素无效,所以要再加一条display: block
13. 防止该折行不折行 / 不该折行的折行
首先必须理解UI,有3种情况:哪些需要折行,哪些不能折行,哪些不能从中间断行。
大部分情况需要折行,不能为了保持UI美观而损失内容的完整性。
一般用overflow-wrap
,尽量不要用word-wrap
(不符CSS标准):overflow-wrap: break-word
配合overflow-wrap
,可再加上hyphens: auto
(目前兼容性不够)
限定多行:-webkit-line-clamp: 3
不能折行,如标题 / 列头 / 按钮等。开发中要理解内容,哪些元素不应该折行。
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
表格列数过多(>5列)时,会要求锁列,此时,th
定义 white-space: nowrap
强制不折行
不能从中间断行的情况(如图)
14. 防止滚动链问题
浮层的场景下需要避免滚动链问题:子元素可滚动,如果父元素也有滚动区域,在子元素上滚动时,触顶/触底后,会影响父元素滚动。关掉浮层后,用户会发现页面滚到了其它位置。
优化前 | 优化后 |
---|---|
overscroll-behavior: contain;
overflow-y: auto;
overflow-x: hidden;
注意:避免出现同时出现水平/垂直滚动条 兼容性:chrome 63+ / firefox 59+ / safari和edge不支持
15. 防止图片变形
图片被置于特定比例的容器中时,固定宽/高和约束最大宽/高,都可能会导致图片变形。
.head img {
width: 100%;
height: 100%;
}
.head img {
width: 100%;
height: 100%;
object-fit: cover;
}
在Flexbox容器内,图片高度会被自动拉伸。因为不定义align-items,默认是stretch。
16. 防止图片加载失败
需要考虑图片加载慢或加载失败的情景。在图片的容器上加边或加底色。
.head {
background: #eee;
box-shadow: inset 0 0 0 1px #aaa;
}
17. 防止CSS变量未引入
在标准化开发中,我们提倡使用全局的CSS变量。业务代码中,利用CSS变量也可以方便的进行全局的控制。在使用CSS变量时要加上缺省值。
font-size: var(--tab-item-text-size-s, 12px);
18. 防止CSS兼容性问题
不要加浏览器厂商前缀,让CSS预编译自动处理,像-webkit-、-moz-。 不要用仅特定浏览器厂商支持的属性。
19. Flexbox常见防御性写法
Flexbox的默认表现比较多,不能简单的定义display:flex,或是flex:1。
Flexbox容器元素通常要做如下定义:要支持多行(默认是单行),交叉轴上垂直居中(默认是stretch),主轴上采用space-between,将自由空间分配到相邻元素之间。
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
Flexbox的盒子元素,不要固定宽/高,更不要指定百分比的值。Flexbox会自动拉伸/收缩盒子元素,能够精确到浮点数,指定具体值会破坏原本的“弹性”。
Flexbox的盒子元素要定义间距。
案例分析:
优化后:
参考代码,总结用法:
.new-overview-v2-center-box .left .top {
/* position: relative; */
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
/* height: 100%; */
}
.new-overview-v2-center-box .left .top .item {
/* width: 25%; */
flex: 1;
min-width: max-content;
margin: 0 8px 8px 0;
}
20. Grid常见防御性写法
不固定网格的宽度,用minmax(最小值,1fr)。 定义间距grid-gap: 8px。 不固定列数, 利用auto-fit / auto-fill自动适配(如图)。
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
grid-gap: 8px;
}
.item {
border: 2px solid #aaa;
box-sizing: border-box;
min-height: 128px;
}
回复“加群”与大佬们一起交流学习~
点击“阅读原文”查看 130+ 篇原创文章