【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结构中,不利于灵活的适配。

image.png

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 {
  margin0;
}

/* 其它地方需要微调时 */
.biz-card .mod {
  margin-bottom16px;
}

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. 防止内容溢出

包括文字/图表等内容在宽度变化时或是英文版下容易出现溢出(如图)。

image.png
  • 图表要支持自动 resize。
  • 图片要限制大小范围,如:max-width、max-height min(100px, 100%)、max(100px, 100%)

注意:min() / max() 兼容性:chrome 79+ / safari 11 / firefox 75

image.png
  • 不能固定宽/高。(见规则3)
  • 不要在容器元素定义overflow:hidden

9. 防止内容过度拥挤

为了防止内容过长时紧帖到后面的内容,水平排列元素之间要设置间距,一般是8px。

image.png

如果用flexbox要加上gap。考虑到gap的兼容性:chrome 84,稳定起见用margin。

image.png
.item {
  margin0 8px 0 0;
}
.item:last-child {
  margin-right0;
}

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时,就要考虑内容是否有被截断的可能。一般不要加在容器元素上。
  • 防止长文字被生生截断(如图),加省略号。
线上问题
overflowhidden
text-overflowellipsis
white-spacenowrap;

不想折行,溢出加省略号,这都没问题。但忽略了对inline元素无效,所以要再加一条display: block

13. 防止该折行不折行 / 不该折行的折行

首先必须理解UI,有3种情况:哪些需要折行,哪些不能折行,哪些不能从中间断行。

  1. 大部分情况需要折行,不能为了保持UI美观而损失内容的完整性。

一般用overflow-wrap,尽量不要用word-wrap(不符CSS标准):overflow-wrap: break-word配合overflow-wrap,可再加上hyphens: auto(目前兼容性不够)

限定多行:-webkit-line-clamp: 3

  1. 不能折行,如标题 / 列头 / 按钮等。开发中要理解内容,哪些元素不应该折行。
image.png
overflowhidden
text-overflowellipsis
white-spacenowrap;

表格列数过多(>5列)时,会要求锁列,此时,th 定义 white-space: nowrap 强制不折行

  1. 不能从中间断行的情况(如图)
image.png

14. 防止滚动链问题

浮层的场景下需要避免滚动链问题:子元素可滚动,如果父元素也有滚动区域,在子元素上滚动时,触顶/触底后,会影响父元素滚动。关掉浮层后,用户会发现页面滚到了其它位置。

优化前优化后


overscroll-behaviorcontain;
overflow-yauto;
overflow-xhidden;

注意:避免出现同时出现水平/垂直滚动条 兼容性:chrome 63+ / firefox 59+ / safari和edge不支持

15. 防止图片变形

图片被置于特定比例的容器中时,固定宽/高和约束最大宽/高,都可能会导致图片变形。

image.png
.head img {
  width: 100%;
  height: 100%;
}
image.png
.head img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

在Flexbox容器内,图片高度会被自动拉伸。因为不定义align-items,默认是stretch。

image.png
image.png

16. 防止图片加载失败

需要考虑图片加载慢或加载失败的情景。在图片的容器上加边或加底色。

.head {
  background#eee;
  box-shadow: inset 0 0 0 1px #aaa;
}

17. 防止CSS变量未引入

在标准化开发中,我们提倡使用全局的CSS变量。业务代码中,利用CSS变量也可以方便的进行全局的控制。在使用CSS变量时要加上缺省值。

font-sizevar(--tab-item-text-size-s, 12px);

18. 防止CSS兼容性问题

  • 不要加浏览器厂商前缀,让CSS预编译自动处理,像-webkit-、-moz-。
  • 不要用仅特定浏览器厂商支持的属性。

19. Flexbox常见防御性写法

Flexbox的默认表现比较多,不能简单的定义display:flex,或是flex:1。

  1. Flexbox容器元素通常要做如下定义:要支持多行(默认是单行),交叉轴上垂直居中(默认是stretch),主轴上采用space-between,将自由空间分配到相邻元素之间。
displayflex;
flex-wrapwrap;
justify-contentspace-between;
align-itemscenter;
  1. Flexbox的盒子元素,不要固定宽/高,更不要指定百分比的值。Flexbox会自动拉伸/收缩盒子元素,能够精确到浮点数,指定具体值会破坏原本的“弹性”。

  2. 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%; */
  flex1;
  min-width: max-content;
  margin0 8px 8px 0;
}

20. Grid常见防御性写法

  • 不固定网格的宽度,用minmax(最小值,1fr)。
  • 定义间距grid-gap: 8px。
  • 不固定列数, 利用auto-fit / auto-fill自动适配(如图)。
.wrapper {
  display: grid;
  grid-template-columnsrepeat(auto-fit, minmax(100px1fr));
  grid-gap8px;
}

.item {
  border2px solid #aaa;
  box-sizing: border-box;
  min-height128px;
}


1. JavaScript 重温系列(22篇全)
2. ECMAScript 重温系列(10篇全)
3. JavaScript设计模式 重温系列(9篇全)
4. 正则 / 框架 / 算法等 重温系列(16篇全)
5. Webpack4 入门(上)|| Webpack4 入门(下)
6. MobX 入门(上) ||  MobX 入门(下)
7. 120+篇原创系列汇总

回复“加群”与大佬们一起交流学习~

点击“阅读原文”查看 130+ 篇原创文章

浏览 23
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报