Skip to content

zylFocus/css-demo

Repository files navigation

分享几个css的小技巧:

1、滚动才出现的分割线

页面上经常需要分割线来划分区域,但有的分割线一直显示并不优雅,滚动时才出现会比较好,比如一些组件库的 dialog 由上图可以看到组件库的 dialog 在 header 和 footer 处都有分割线,只有滚动使得有部分超出时才会出现。

组件库的做法:

  • 通过 scrollTop, scrollHeight, clientHeight 来判断是否有上下溢出
  • ResizeObserver 和 scroll 事件时去检测溢出

可以用js做,但是麻烦,性能也略差。

骚操作:纯html加css也能实现

直接上图: 简单讲一下实现原理: 以 header 处的分割线举例,我们用了两个 div,

  • div-one:一直在要要分割的地方,是灰色的
  • div-two:跟随 body 容器滚动,颜色和 body 的背景色一样。

让 div-two 的层级在在 div-one 上面,现在我们开始滚动:

  • 当 body 没有上溢出时,第二个 div 刚好完全挡住第一个 div,实现分割线隐藏。
  • 当 body 有上溢出时第一个 div 显示,实现分割线显示。

footer 处同理。 遵循这个思路我们可以写个滚动出现分割线的容器:

const ScrollContainer = ({ children, className }: { children: ReactNode; className?: string }) => {
  return (
    <div className={classNames('relative overflow-auto', className)}>
      {/* 滚动才出现的分割线 上 */}
      <div className={classNames('w-full border-b border-solid border-gray-300 z-10 top-0 sticky')}></div>

      <div className={classNames('w-full h-px bg-[#fff] z-30 top-0 absolute')}></div>

      {children}

      {/* 滚动才出现的分割线 下 */}
      <div className={classNames('w-full h-px bg-[#fff] relative z-10')}></div>
      <div className={classNames('w-full border-t border-solid border-gray-300 sticky bottom-0')}></div>
    </div>
  )
}

使用的时候:

<ScrollContainer className={classNames('flex-1')}>
  <div className="p-5">
    <FormCom />
  </div>
</ScrollContainer>

如果你只需要上分割线,我们还可以 css 加个类就能实现效果 :

.has-scroll-top-divider::before {
    content: '';
    @apply block w-full border-b border-solid border-gray-300 z-10 top-0 sticky
}
.has-scroll-top-divider::after {
    content: '';
    @apply w-full h-px bg-[#fff] z-30 top-0 absolute
}

2、container 容器查询:

参考:

css 目前的媒体查询通常用来查视口的宽高,不能直接查询某个容器的宽高。 现在可以使用 container query 来解决这个问题,不过 chrome 版本要求较高

这东西可以用来干嘛?

我暂时只想到这几个:

“height: 100%” 不生效

是否遇到过 “height: 100%” 不生效,因为父元素没有 height,这时候要么用 flex,要么一路把 height 传下来。现在有了容器查询,你多了一种方法了。

根据容器自适应文字大小和效果

自适应文本头像

核心思路: 文字大小需要和文字数量成反比,用固定大小的文字撑出容器,然后通过 cqw 可以获取查询容器的宽度,最后通过 calc({num1}px - {num2}cqw)。 步骤是:

  • 父容器设置为 relative 定位
  • 子容器 一,用固定大小的文字撑出一个真实的容器,隐藏这个容器
  • 子容器二,设置 绝对定位和容器查询 container-type: inline-size;
  • 子容器二,下面设置一个 span 元素来展示文字,文字大小和外层容器成反比,故设置为 font-size: calc(30px - 10cqw)

使用方法:

第一步: 父容器设置 container-type: inline-size; size 查询将基于容器的行向和块向尺度,将布局、样式和大小的限制应用于容器。 inline-size 查询将基于容器的行向尺度,将布局、样式和行向大小的限制应用于元素。 normal 该元素不是任何容器大小查询的查询容器,但仍然是容器样式查询的查询容器。 第二步: 子容器通过 cqw 来设置宽度,cwh 来设置高度。 容器查询长度单位包括:

  • cqw:查询容器宽度的 1%
  • cqh:查询容器高度的 1%
  • cqi:查询容器行向尺寸的 1%
  • cqb:查询容器块尺寸的 1%
  • cqmin:cqi 和 cqb 中较小的值
  • cqmax:cqi 和 cqb 中较大的值

3、视图过渡

参考:

关于过渡有个思想是 flip 动画,flip对应着四个单词:First 、Last、Inverse、Play 。 flip 是一种动画的制作思路,核心是记住开始和结束的状态,然后通过 transform 不影响布局的特点来反向设置一个 translate,然后倒转播放一下动画。 然后这种思想已经渐渐的变成了 css 官方的 api,View Transition 的 API 设计和这个思想非常像,不能说非常像,简直就是一模一样。不过 css 把它集成为标准后,用起来很方便。 先看几个案例

案例:

使用方法:

非常简单,分两步 第一步: 给要变化的元素添加 view-transition-name,属性,值随意,自定义就好 第二步: 通过 document.startViewTransition 函数开始动画,这个函数接受一个callback,这个callback里进行你需要的视图操作

示例:

js:

<div
    className="grid grid-cols-[repeat(auto-fill,100px)] gap-5"
    id="list"
    onClick={e => {
      console.log('click ====', e.target)
      const targetEle = e.target as HTMLDivElement
      if (targetEle.classList.contains('zzz-list-item')) {
        if (document.startViewTransition) {
          document.startViewTransition(() => {
            targetEle.remove() // 执行销毁dom元素的操作
          })
        } else {
          targetEle.remove()
        }
      }
    }}
  >
  // ....省略

4、滚动驱动动画

参考:

案例:Scroll-driven Animations: Stacking Cards (CSS)

上图是滚动的时候,卡片会逐渐变小并堆叠在上面。 如果我们要实现上面这种效果,该怎么做呢? 传统方法: 大概是用js或者滚动高度的变化,然后算出每张卡片在这个高度和大小。这种方法性能较差,不够丝滑 换个思路,如果把卡片变小到堆叠在上面这个过程写成一个动画,那么性能会好很多,也丝滑。 那么问题来了,怎么实现滚动和动画结合呢?

  • 滚动过程做成动画播放的时间线
  • 指定是获取哪个容器滚动
  • 滚动的那个容器,滚动距离和动画播放进度的对应关系。(也就是我滚 100px,你动画应该播放多少进度)

解决这三点,就可以实现滚动驱动动画,那么我们可以迎接 css的新特性,scroll-driven animation 用起来也是非常的简单

使用方法:

第一步: 写一个动画,如下面这个简单例子

@keyframes grow-x {
    0% {
        transform: scaleX(0);
    }
    100% {
        transform: scaleX(1);
    }
}

第二步: 给要变化的元素加上动画,并指定这个动画跟随哪个容器的滚动来播放

.scroll-process {
    animation: grow-x 3s linear;
    animation-timeline: scroll(y);
}

scroll(y) 指的是侦测y轴的滚动。 scroll函数,可以传递两个参数,分别是和 表示滚动容器,支持以下几个关键值

  • nearest:使用最近的祖先滚动容器*(默认)*
  • root:使用文档视口作为滚动容器。
  • self:使用元素本身作为滚动容器。

表示滚动方向,支持以下几个关键值

  • block:滚动容器的块级轴方向*(默认)*。
  • inline:滚动容器内联轴方向。
  • y:滚动容器沿 y 轴方向。
  • x:滚动容器沿 x 轴方向。

上述简单两步,我们就实现了显示页面阅读进度的进度条。 这时候还有个坑没填: 滚动范围和动画播放进度的对应关系,比如我想实现一个页面滚动200px下面就会出现一个回到顶部的按钮。 我们可以给按钮一个出现动画,然后设置 animation-range为 0 200px 即可

5、路径动画

参考:animateMotion - SVG:可缩放矢量图形 | MDN 元素定义了一个元素如何沿着运动路径进行移动。 CSS Motion Path 规范主要包含以下几个属性:

  • offset-path:接收一个 SVG 路径(与 SVG 的path、CSS 中的 clip-path 类似),指定运动的几何路径
  • offset-distance:控制当前元素基于 offset-path 运动的距离
  • offset-position:指定 offset-path 的初始位置
  • offset-anchor:定义沿 offset-path 定位的元素的锚点。 这个也算好理解,运动的元素可能不是一个点,那么就需要指定元素中的哪个点附着在路径上进行运动
  • offset-rotate:定义沿 offset-path 定位时元素的方向,说人话就是运动过程中元素的角度朝向

使用方法:

  • Css 里定义一个keyframes ,关键帧里设置 offset-distance
  • 在要使用的元素上加上 animation 和 offset-path 即可
.motion-path-item {
    offset-path: path("M 0 80 C 80 10, 130 10, 190 80 S 300 150, 360 80");
    animation: move 2000ms infinite alternate ease-in-out;
}
@keyframes move {
    0% {
        offset-distance: 0%;
    }
    100% {
        offset-distance: 100%;
    }
}

6、路径动画和滚动动画结合

就可以实现下面这个效果。 箭头后面的线是 svg 画的,详情见:【Web动画】SVG 线条动画入门 - ChokCoco - 博客园 Svg 线条动画的重点是:

  • stroke-dasharray:值是一组数组,没数量上限,每个数字交替表示划线与间隔的宽度;
  • stroke-dashoffset:则是虚线的偏移量

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published