CSS/C3 功能实现·随记

目录

一、功能实现

1、吸顶与悬停

2、设置标签随文字换行移动

3、一键置灰

4、列表滑动——抽屉推拉效果 

5、去除滚动条

6、高度塌陷

二、CSS 防御

0、CSS变量默认值

1、margin

2、长文本

3、滚动

(1)、锁定滚动链接

(2)、合理使用滚动条属性

(3)、预留滚动条空间,避免重排

4、图片

(1)、如何防止图片被拉伸或压缩呢?

(2)、图片上的文字

(3)、图片最大宽度

6、弹性元素尺寸 min-* 或者 max-*

7、媒体查询 @media

8、粘性定位

9、浏览器兼容性 CSS 请勿批量处理


一、功能实现

1、吸顶与悬停

position: sticky;
position: -webkit-sticky;
top: 0;

上述代码中,可以通过调整 top 的值来修改元素距离顶部悬停的位置。

【拓展】“position: sticky”

“position: sticky” 是基于用户的滚动位置来定位的。

“position: sticky” 的特性

粘性定位的元素是依赖于用户的滚动,在 position:relative 与 position:fixed 定位之间切换。它的行为就像 position:relative; 而当页面滚动超出目标区域时,它的表现就像 position:fixed;,它会固定在目标位置。

元素定位表现为在跨越特定阈值前为相对定位,之后为固定定位。这个特定阈值指的是 top, right, bottom 或 left 之一,换言之,指定 top, right, bottom 或 left 四个阈值其中之一,才可使粘性定位生效。否则其行为与相对定位相同。

“position: sticky” 的踩坑记

  • sticky 不会触发 BFC。
  • 样式表 z-index 无效,行内 style 写有效。

【注意】 Internet Explorer, Edge 15 及更早 IE 版本不支持 sticky 定位。 Safari 需要使用 -webkit- prefix。

position: sticky 详解(防坑指南)

2、设置标签随文字换行移动

css 设置标签随文字换行移动——vertical-alignhttps://blog.csdn.net/mChales_Liu/article/details/123201887

3、一键置灰

一键置灰的 css 代码:

.app-gray {
    filter: grayscale(100%);
}

重点在于加在哪里——只需要加在根元素(html)上就好。

【拓展】

  • 给根元素添加 class:
document.documentElement.className += ' app-gray'
  • 给跟元素添加 style:
const root = document.querySelector(':root') // html
root.style.setProperty('filter', 'grayscale(100%)')

4、列表滑动——抽屉推拉效果 

两种思路:

  • translate 改变目标的left值实现滑动。
  • @keyframes + animation 改变目标的left值实现滑动。

1⃣️、translate 改变目标的 left 值实现滑动

<template lang="pug">
  .test-touch-wrap(style='width:375px;height:40px;position:relative;overflow:hidden;')
    .content(
      style='width:475px;position:absolute;top:0;left:0;'
      ref='touchDom'
      @touchstart.stop='touchstart'
      @touchmove.stop='touchmove'
      @touchend.stop='touchend'
    )
      .left(style='float:left;width:375px;height:40px;line-height:40px;') 左边的内容
      .right(style='float:right;width:100px;height:40px;line-height:40px;') 右边的内容
</template>
<script>
export default {
  props: {
    itemIndex: {
      type: Number,
      default: 0
    }
  },
  data () {
    return {
      screenWidth: document.body.clientWidth,
      startPosition: {},
      range: {},
      setTouchTime: 0,
      cancleTouchTime: 0,
      target: 100
    }
  },
  methods: {
    touchstart (e) {
      const { pageX, pageY } = e.changedTouches[0]
      this.startPosition = { pageX, pageY }
    },
    touchmove (e) {
      const { pageX, pageY } = e.changedTouches[0]
      this.range = {
        x: pageX - this.startPosition.pageX,
        y: pageY - this.startPosition.pageY
      }
      if (Math.abs(this.range.x) > Math.abs(this.range.y)) { // 保证是左右滑动
        if (this.range.x < 0 && !this.setTouchTime) { // 第一次向右滑动
          if (Math.abs(this.range.x) >= this.screenWidth / 2) { // 滑动距离大于等于屏宽的一半
            this.$refs.touchDom.style.left = -this.target + 'px'
            this.$refs.touchDom.style.transition = 'left 0.3s ease 0s'
            this.$emit('cancel-other-touch-state', this.itemIndex) // 取消其兄弟元素的滑动状态
            this.setTouchTime++
          } else { // 滑动距离小于屏宽的一半
            this.$refs.touchDom.style.left = this.range.x + 'px'
          }
        } else if (this.range.x > 0 && !this.cancleTouchTime && this.$refs.touchDom?.style?.left) { // 第一次向左滑动,且已经处于右滑的状态了
          this.cancelCurrentTouchState()
          this.cancleTouchTime++
        }
      }
    },
    touchend (e) {
      if (Math.abs(this.range.x) < this.screenWidth / 2 && !this.setTouchTime && !this.cancleTouchTime) {
        this.cancelCurrentTouchState()
      }
      if (this.setTouchTime) {
        this.setTouchTime = 0
      }
      if (this.cancleTouchTime) {
        this.cancleTouchTime = 0
      }
    },
    cancelCurrentTouchState () {
      this.$refs.touchDom.style.left = '0px'
      this.$refs.touchDom.style.transition = 'left 0.3s ease 0s'
    }
  }
}
</script>

【注意】一般 app 端的这种需求会比 pc 端的多。在 app 端实现时,要注意以下几点:

  • template 模板里,最大宽度应该是动态屏宽(我暂时写了具体值是为了效果),超出这个屏宽的部分要隐藏掉。
  • template 模板里,左右的内容部分用插槽实现更加灵活。

2⃣️、@keyframes + animation 改变目标的 left 值实现滑动

先定义好动画样式:

<style>
  .set-touch {
    animation: set_touch 0.8s ease 0s 1 forwards;
  }
  .cancel-touch {
    animation: cancel_touch 0.3s ease 0s 1 forwards;
  }
  @keyframes set_touch{
    from {left: 0px;}
    to {left: -176px;}
  }
  @keyframes cancel_touch{
    from {left: -176px;}
    to {left: 0px;}
  }
</style>

然后就是 js 的实现,主要逻辑是,动态增删切换 class。

5、去除滚动条

支持多端兼容:

@cancle-scroll: {
  &::-webkit-scrollbar {
    display: none;
    width: 0px;
    -webkit-overflow-scrolling: touch;
    overflow-scrolling: touch;
    opacity: 0;
    &-thumb {
      background: rgba(0,0,0,0);
    }
  }
}

6、高度塌陷

解决办法:

  • 给父元素添加固定高度。不过,不适合高度自适应的布局。
  • 给父元素添加overflow:hidden。不过,不适合与定位的一起使用。
  • 给所有的浮动盒子最后添加一个空的标签,例如 div,且添加声明 clear:both。不过,多了很多空的标签,造成代码冗余。
  • 给高度塌陷的元素添加 min-height: 100vh 样式,让其内容充满屏幕。(推荐
  • 万能清除浮动法。(推荐

万能清除浮动法:

.clearfix () {
  &:after {
    content: '';
    display: block;
    height: 0;
    visibility: visible;
    clear: both;
  }
}

二、CSS 防御

一切使表现和行为偏离预期效果的情景都需要防御。这些问题往往是由于终端环境的多样化造成的。

0、CSS变量默认值

CSS 变量可以实现动态控制元素属性,变量默认值可以保证变量值异常时页面依然能运行。

.box {
  color: var(--test-var, blue);    /* 定义 --test-var 的默认值是:蓝色 */
}

在上面的 CSS 函数中,函数接受两个参数:

  • 第一个参数:自定义属性的名称。
  • 第二个参数:(可选的)表示备用值,当自定义属性值无效时生效。

【注意】这个 CSS 变量的默认值 仅对支持 CSS 自定义属性 的浏览器有效,需要考虑浏览器对CSS 自定义属性的兼容性。

1、margin

需要防止元素与元素之间由于挤压空间而造成的重叠等情况。

.desc{
    margin-right: 1rem;
}

2、长文本

对长文本的处理无非两种:

  • 支持换行
    • 限制显示几行,超出省略号
  • 省略现示

接下来,假设我们要对一个 width 是 300 像素的文本输入框做长文处理。

若支持换行:

overflow-wrap: break-word;
// 若是flex布局,可以用下面这行代码
flex-wrap: wrap;

若是限制现显示3行 :

overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;

省略现示:

white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;

3、滚动

(1)、锁定滚动链接

overscroll-behavior 属性是 overscroll-behavior-x 和 overscroll-behavior-y 的简写。

overscroll-behavior 属性用来:控制元素滚动到边界时的表现。

什么叫“元素滚动到边界时的表现”呢?下面我们来理解一个概念 “滚动链”:

滚动链 —— 在 CSS 世界里,滚动也有冒泡机制,当内部元素滚动到边界时,如果继续滚动,会带动外层祖先元素发生滚。也可以叫做 滚动冒泡  滚动穿透。overscroll-behavior 属性可以设置是否阻止该行为。这就好比,在 JS 的事件冒泡机制里,你可以通过 event.stopPropagation 方法去阻止冒泡的发生一样。

{overscroll-behavior: contain | none | auto}
  • auto:默认效果
  • contain:设置这个值后,默认的滚动边界行为不变(“触底”效果或者刷新),但是临近的滚动区域不会被滚动链影响到,比如对话框后方的页面不会滚动。
  • none:临近滚动区域不受到滚动链影响,而且默认的滚动到边界的表现也被阻止。防止节点本身的滚动效果(例如:Android 炫光或 iOS 回弹

实践:

<div class='one'>
    <div class='two'>
        <div class='three'>
            <div class='four'></div>
        </div>
    </div>
</div>
.one {
    width: 500px;
    height:400px;
    background: aliceblue;
    overflow: scroll;
}
.two {
    width:450px;
    height:500px;
    background: antiquewhite;
    margin: 0 auto;
}
.three {
    width:200px;
    height:200px;
    background: darkkhaki;
    margin: 0 auto;
    overflow: scroll;
}
.four {
    width:150px;
    height:300px;
    background: cadetblue;
    margin: 0 auto;
}

 现在给 class 是 three 的 div 设置上 overscroll-behavior 属性为 contain:

.three {
    width:200px;
    height:200px;
    background: darkkhaki;
    margin: 0 auto;
    overflow: scroll;
    overscroll-behavior: contain;
}

(2)、合理使用滚动条属性

overflow 属性有两个作用很相近的属性值:

  • scroll:当内容大于所占空间时滚动展示。无论滚动到的内容是否为超出容器空间的内容,始终都会展示滚动条。
  • auto:当内容大于所占空间时滚动展示。auto 属性会分辩条件——只有滚动到超出容器空间的内容时,才会展示滚动条。

所以,建议使用 “overflow: auto;” 来设置滚动条。

(3)、预留滚动条空间,避免重排

设想这样一个场景:有一个宽度100vw,高度为100vh的容器盒子,容器内展示商品卡片,滑动到页面底部时,触发滑动加载,当触发懒加载时,容器内商品卡片占用的高度已经超出100vh,依据外层容器设置的overflow:auto,内容超出时会展示滚动条,滚动条的出现,使得页面不得不给滚动条让出一定的宽度,这个切换的场景中,由于不得不给滚动条让位置,最外层的元素发生了元素宽度变化,产生了重排的效果,有没有可能避免这一次不必要的重排呢?答案是有的。

使用 scrollbar-gutter 属性来:预留滚动条空间,避免重排。

scrollbar-gutter 属性用来:为滚动条保留空间,防止在内容增长时不必要的布局更改。同时在不需要滚动时避免不必要的视觉效果(不晃动)。

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

 【拓展】scrollbar-color 和 scrollbar-width

4、图片

图片的添加就下面两种方式:

  • css 添加背景
  • img 标签添加图片

(1)、如何防止图片被拉伸或压缩呢?

若是 css 添加背景:

.picture {
    background-size: cover;
}

若是 img 标签添加图片:

.picture {
    object-fit: cover;
}

(2)、图片上的文字

若要在图片上层展示文字,需考虑:如果图片加载失败,而外层容器的背景色和文字颜色接近,那么文字的展示的效果就不理想了。

解决思路:给容器设置背景色,当图片加载失败时,文字的背景色直接变为容器的背景色,让文字正常显示。至于图片加载失败时左上角的“破图”标记,可以使用伪类进行遮挡美化。

(3)、图片最大宽度

需要对 img 进行 resetCss(样式重置),以避免:当给固定宽高容器设置背景图时,如果背景图尺寸超过容器宽高,图片会溢出。

img {
  max-width: 100%;
  object-fit: cover;
}

6、弹性元素尺寸 min-* 或者 max-*

使用弹性元素尺寸 min-* 或者 max-* 可以 自动适应部分内容所占空间过大或过小的布局。

7、媒体查询 @media

CSS中的条件判断——根据不同的屏幕尺寸加载该尺寸所对应的样式。

例如:

/* 将 body 的背景色设置为蓝色 */
div {
  background-color: black;
}

/* 在小于或等于 800 像素的屏幕上,将背景色设置为黄色 */
@media screen and (max-width: 750px) {
  div {
    background-color: blue;
  }
}

/* 在 600 像素或更小的屏幕上,将背景色设置为红色 */
@media screen and (max-width: 300px) {
  div {
    background-color: green;
  }
}

/* 针对 280px 宽度 */
@media screen and (device-width: 280px){
  div {
    background-color: red;
  }
}

8、粘性定位

position 的粘性定位指的是:通过用户的滚动,元素的 position 属性在 position:relative 与 position:fixed 定位之间切换。

应用场景:滚动吸顶

案例:参见本文的 “吸顶与悬停”

9、浏览器兼容性 CSS 请勿批量处理

根据W3C标准,批量分组选择选择器,如果分组中,其中一个无效,那么整个选择器都将会失效。因此,在遇到浏览器兼容属性时,切勿批量组合书写。(Selectors Level 4

【参考】

编写防御性 CSS 实践

防御式CSS是什么?这几点属性重点防御!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值