# 防御式编程 - 防御式 CSS

什么是防御式编程 ?

防御性编程是一种细致、谨慎的编程方法(习惯)。我们在写代码时常会有“以防万一”的心态,把以防万一有可能出现的情况提前考虑进去,规避以免以防万一出现带来的问题。

应用防御性编程技术,你可以侦测到可能被忽略的错误,防止可能会导致灾难性后果的“小毛病”的出现,在时间的运行过程中为你节约大量的调试时间。

比如:我们在写下面这个效果时,如果只是按设计师设计效果来开发,我们就不会考虑标题内容过长的问题。但是在实际的应用中,数据是从后台加载而来,标题的字数就有可能过长,过长之后就会导致标题溢出折行的效果如下图,带来不好的体验。

如果站在防御式编程的角度来思考,那我们就会提前把这种问题规避掉。如果标题过长,我们可以使用...省略号来处理。而不是等到项目上线,实际问题发生时,再来修改代码。

设计师设计效果 实际效果: 内容过长 处理后效果:文本溢出省略号
设计师设计效果 实际效果: 内容过长 处理后效果:文本溢出省略号

# 什么是防御式 CSS

TIP

防御式 CSS 是一个片段的集合,可以帮助我们规避“以防万一”产生的问题。

我们在 CSS 布局时,是按照设计师的效果来开发的,但是实际的网页内容是动态的,网页上的内容是可以改变的,如:文字数量,图片尺寸、窗口大小等,再加上用户的一些意想不到的行为和运行环境,从而造成 CSS 布局的效果并没有按照我们预期的效果显示。

我们可以通过添加某些 CSS 代码,来避免这种情况带来的问题。防御式 CSS 是实现项目稳定性建设重要但极其容易忽视的一环。

以下是:9 个具有防御式的 CSS 代码

接下来我们分享 9 个应用场景下,具有防御式的 CSS 代码。

# 场景一: 单行文本过长

我们设计时的理想效果是标题文字不超过 8 个字,正好显示完整。但实际应用时,有可能标题内容过长造成换行显示。我们可以添加文字溢出显示..省略号来解决。

设计师设计效果 实际效果: 内容过长 处理后效果:文本溢出省略号
image-20220526162249582 image-20220526162055955 image-20220526161739730
<style>
  body,
  h3 {
    margin: 0;
    padding: 0;
  }
  .box {
    width: 150px;
    height: 150px;
    position: relative;
    margin: 40px auto;
  }
  .box h3 {
    height: 30px;
    line-height: 30px;
    font-weight: 100;
    width: 100%;
    background-color: rgba(0, 0, 0, 0.5);
    font-size: 16px;
    color: #fff;
    position: absolute;
    bottom: 0;
    text-align: center;
    /*以防万一,标题过长时,用...省略号显示*/
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
</style>
<body>
  <div class="box">
    <img src="images/flex-06.jpg" alt="" />
    <h3>"以防万一"标题过长产生的问题</h3>
  </div>
</body>

# 场景二:类别标签中文本过长

在这个效果中,我们并不希望标签延伸到最右侧,我们希望内容过长时,可以在一定的长度时就折行显示。我们可以通过添 max-width属性来避免这种“以防万一”的问题。

同类的应用还有 min-width,在此就不演示了

设计师设计效果 实际效果 内容过长 处理后效果 折行处理后效果
image-20220526170222329 image-20220526170245096 image-20220526170328905
<style>
      .box {
        width: 250px;
        height: 250px;
        position: relative;
      }
      .box span {
        position: absolute;
        background-color: rgba(119, 245, 197, 0.8);
        line-height: 1.3;
        font-size: 12px;
        padding: 5px 10px;
        border-radius: 0 50px 50px 0px;
        left: 0px;
        top: 5px;
        /*以防万一标签内容过长,控制最大宽度,内容过多折行显示*/
        max-width: 70%;
      }
    </style>
  </head>
  <body>
    <div class="box">
      <img src="images/ms.jpg" alt="" />
      <span>植物奶油 巧克力 草莓 榴莲 花生 芝麻 小米 鸡蛋</span>
    </div>
  </body>

# 场景三:防止图片拉伸或挤压

我们预想的是用户按 1:1 的大小来上传头像图片,但实际用户上传的头像比例是五花八门,就会造成图片被拉伸或挤压变形。我们可以添加Object-fit: cover来等比例裁剪图片尺寸,这样图片就不会被拉伸或压缩,不过会有一部分图片被裁剪掉。

设计师设计效果 (图片尺寸 1:1) 实际效果:图片尺寸(1:1.4) 处理后效果:保持原尺寸比例裁剪图片
image-20220526172933378 image-20220526173100167 image-20220526173221648
<style>
  .box {
    width: 200px;
    height: 200px;
    border-radius: 50%;
    overflow: hidden;
  }
  .box img {
    width: 100%;
    height: 100%;
    /*保持图片原有尺寸来裁剪*/
    object-fit: cover;
  }
</style>
<body>
  <div class="box">
    <img src="images/tx2.png" alt="" />
  </div>
</body>

# 场景四:图片加载失败,文字显示问题

当图片上有文字时,如果图片加载失败,而外层容器的背景色和文字颜色接近,那么文字的展示效果就不理想;此时我们可以给图片加上对应的背景色。

设计师设计效果 实际效果:图片加载不出来,问字显示不出来 处理后效果:给图片加上背景色后的效果
image-20220526175137524 image-20220526175206134 image-20220526175225539

这个效果大家只需做个了解就好。通常如果图片上有文字,设计师在设计效果图时都会在图片和文字中间加上一层黑色的半透明遮罩层,这样即使图片加载不出来,也不影响文字的展示效果。

<style>
  .box {
    width: 250px;
    height: 156px;
    position: relative;
  }
  .box img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    /*"以防万一"图片加载失败,加上背景色,保证文字能正常显示*/
    background-color: #666;
  }
  .box h3 {
    width: 100%;
    font-size: 20px;
    text-align: center;
    position: absolute;
    top: 40px;
    color: #fff;
  }
</style>
<body>
  <div class="box">
    <img src="images/rotate3.webp" alt="" />
    <h3>美丽的风景图</h3>
  </div>
</body>

# 场景五:必要时显示滚动条

在内容比较长的情况下,可以通过设置 overflow-y 控制滚动条是否展示。但是这里更推荐将overflow-y 的值设置为 auto。如果你将 overflow-y 显式设置为 scroll 时,不管容器内容长短,滚动条都会展示出来,这种体验是不好的

设计师设计效果 实际应用效果 修改后效果(内容不足,不显示滚动条,内容溢出显示滚动条)
image-20220526194254423 image-20220526194402060 image-20220526194254423image-20220526194432340
<style>
  .box {
    width: 160px;
    padding: 20px;
    height: 200px;
    background-color: skyblue;
    line-height: 2;
    border-radius: 20px;
  }
  .box .content {
    padding-right: 10px;
    max-height: 100%;
    /*以防万一,用户内容不足时,不需要显示滚动条,只有内容溢出时才显示*/
    overflow-y: auto;
  }
  /* 整个滚动条*/
  .content::-webkit-scrollbar {
    width: 5px;
    padding: 0px 20px;
  }
  /* 滚动条轨道*/
  .content::-webkit-scrollbar-track {
    border-radius: 10px;
    background-color: #000;
    margin: 20px 0px;
  }
  /*滚动条上的滚动滑块*/
  .content::-webkit-scrollbar-thumb {
    width: 14px;
    border-radius: 10px;
    background-color: #ddd;
  }
</style>
<body>
  <div class="box">
    <div class="content">
      在内容比较长的情况下,可以通过设置
      overflow-y控制滚动条是否展示。但是这里更推荐将
    </div>
  </div>
</body>

# 场景六:预留滚动条空间,避免重排

当内容不足时不会出现滚动条,文字占据的宽度要宽些。当内容溢出出现滚动条时,因为滚动条要占据一部分空间,则会造成文字占据的空间变窄,因而会造成重排。我们可以元素添加scrollbar-gutter: stable;来避免这个问题。

scrollbar-gutter 属性有三个值

属性值 描述
auto 就是默认表现。没有滚动条的时候,内容尽可能占据宽度,有了滚动条,可用宽度减小
stable 如果 overflow 属性计算值不是 visible,则提前预留好空白区域,这样滚动条出现的时候,整个结构和布局都是稳定的。
both-edges 让容器左右两侧同时预留好空白区域,目的是让局部绝对居中对称。

没有加 scrollbar-gutter 时,未出现滚动条和出现滚动条之间的差别

没有滚动条时 有滚动条时
image-20220526200254683 image-20220526200329842

加上 scrollbar-gutter:stable;后,出现滚动条和没有出现滚动,前后文字显示效果没有差异

没有滚动条时效果 有滚动条时的效果
image-20220526200605384 image-20220526200638567
<style>
  .box {
    width: 160px;
    padding: 20px;
    height: 200px;
    background-color: skyblue;
    line-height: 2;
    border-radius: 20px;
  }
  .box .content {
    max-height: 100%;
    /*以防万一,用户内容不足时,不需要显示滚动条,只有内容溢出时才显示*/
    overflow-y: auto;
    /*预留好滚动条位置,必免引起重排*/
    scrollbar-gutter: stable;
  }
  .content::-webkit-scrollbar {
    width: 10px;
  }
  .content::-webkit-scrollbar-track {
    border-radius: 10px;
    background-color: #000;
    margin: 20px 0px;
  }
  .content::-webkit-scrollbar-thumb {
    width: 14px;
    border-radius: 10px;
    background-color: #ddd;
  }
</style>
<body>
  <div class="box">
    <div class="content">
      当内容不足时不会出现滚动条,文字占据的宽度要宽些。当内容溢出出现滚动条时,因为滚动条要占据一部分空间,则会造成文字占据的空间变窄,因而会造成重排。
    </div>
  </div>
</body>

# 场景七:锁定滚动链

我们会发现当子元素滚动到顶部或底部继续滚动滚轮时,会导致父元素的滚动,但这种行为有时会影响页面体验。在子元素上应用overscroll-behavior: contain就可以禁止掉这一行为。

image-20220526212331546
<style>
  body {
    height: 2000px;
  }
  .box {
    height: 400px;
    width: 200px;
    margin: 0px auto;
    overflow-y: auto;
    background-color: skyblue;
    /*当滚动到滚动条底部和顶部时,会触发父元素的滚动条滚动*/
    overscroll-behavior-y: contain;
  }
</style>
<body>
  <div class="box">
    <p>1</p>
    <p>2</p>
    <p>3</p>
    <p>4</p>
    <p>5</p>
    <p>6</p>
    <p>7</p>
    <p>8</p>
    <p>9</p>
    <p>10</p>
    <p>11</p>
    <p>12</p>
    <p>13</p>
    <p>14</p>
    <p>15</p>
    <p>16</p>
    <p>17</p>
    <p>18</p>
    <p>19</p>
    <p>20</p>
    <p>21</p>
    <p>22</p>
    <p>23</p>
    <p>24</p>
    <p>25</p>
    <p>26</p>
    <p>27</p>
    <p>28</p>
    <p>29</p>
    <p>30</p>
    <p>31</p>
    <p>32</p>
  </div>
</body>

# 场景八:flex 布局中,元素使用 space-between 最后一行两边分布的问题 ?

如果我们每一行显示的个数为 n,那我们可以最后一行子项的后面加上 n-2 个 span 元素,span 元素的宽度和其它子项元素宽度一样,但不用设置高度。

为什么是添加 n-2 个 span 元素呢?

  • 当最后一行只有 1 个子元素时,他会默认靠左,不用处理
  • 当最后一行子元素正好时,我们就不用关心这个问题。

所以要去掉这两种情况,只需要加 n-2 个 span 元素就好

设计师设计效果 实际效果 处理后的效果
image-20220526202336016 image-20220515110815717 image-20220515111311217
 <style>
      .container {
        width: 500px;
        display: flex; /*弹性布局*/
        justify-content: space-between; /*两端对齐*/
        flex-wrap: wrap; /*超出部分换行*/
      }
      .item {
        width: 120px;
        height: 100px;
        background-color: pink;
        margin-top: 10px;
      }
      .container span {
        width: 120px; /*span宽和子项宽一样*/
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
      <div class="item">4</div>
      <div class="item">5</div>
      <div class="item">6</div>
      <div class="item">7</div>
      <!--以防万一,子项个数不够,最后一排出现两端对齐,达不到预期效果-->
      <span></span>
      <span></span>
    </div>
  </body>

# 场景九:grid 网格中的响应式断行效果的处理

当我们想尽可能多的在一行显示子项的个数时,有可能会出现子项个数不满一行的情况。那这个时候利用网格布局,使用 auto-fill 和 auto-fit 就会是两个完全不同的效果。

  • auto-fill :网格的最大重复次数(正整数),如果有剩余空间,则会保留剩余空间,而不改变网格项目的宽度。
  • auto-fit:网格的最大重复次数(正整数),如果有剩余空间,网格项平分剩余空间来扩展自己的宽度。

以下情况只会出现在子项内容不能占满一行时。也就是说万一内容不能占满一行,则使用 auto-fill 就会出现空白问题。我们把 auto-fill 改成 auto-fit 就解决了这个问题

设计师设计期望的效果 实际效果:使用 auto-fill 时的效果 处理后效果:使用 auto-fit 时的效果
image-20220526205907916 image-20220526205424465 image-20220526205530332
<style>
  .container {
    width: 100%;
    display: grid;
    /*grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));*/
    /*以防万一,子项不足占据一行时*/
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    grid-template-rows: 250px;
    grid-auto-flow: row;
    grid-auto-rows: 250px;
    gap: 10px;
  }
  .container .item:nth-child(even) {
    background-color: skyblue;
  }
  .container .item:nth-child(odd) {
    background-color: pink;
  }
</style>
<body>
  <div class="container">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
  </div>
</body>
上次更新时间: 6/8/2023, 9:23:17 PM

大厂最新技术学习分享群

大厂最新技术学习分享群

微信扫一扫进群,获取资料

X