> For the complete documentation index, see [llms.txt](https://alphardex.gitbook.io/coder-operation-record/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://alphardex.gitbook.io/coder-operation-record/qian-duan/css.md).

# CSS 技巧

评判一个网页的美观程度，首要的当然是看它的 CSS 样式写的如何。

日本某宅写了一个非常厨二的页面——[臆病な魔女](https://yui540.graphics/)，可以说是把 CSS 动画玩得非常 6 了，看得笔者顿时燃起了学好 CSS 的欲望。

如果想 CSS 玩的溜，除了熟悉基本的知识以外，掌握大量技巧也是必不可少的。

## 形状

### 扩张式矩形

目的：创建一个矩形，鼠标悬浮时扩张一定的大小

[预览](https://codepen.io/alphardex/pen/KKPZObw)

```markup
<div class="expanding-box"></div>
```

```css
body {
  display: flex;
  height: 100vh;
  justify-content: center;
  align-items: center;
}

.expanding-box {
  position: relative;
  width: 15em;
  height: 10em;

  &::after {
    position: absolute;
    content: "";
    top: -1em;
    right: -1em;
    bottom: -3em;
    left: -1em;
    background: black;
    --path: inset(2rem 0 2rem 2rem round 10px);
    clip-path: var(--path);
    transition: clip-path 0.3s;
  }

  &:hover::after {
    --path: inset(0 round 10px);
  }
}
```

首先利用伪元素`::after`生成一个矩形

利用`clip-path`的`inset`来裁切矩形（顺序是上右下左圆角）

鼠标悬浮时去除裁切效果即可

## 字体排印

### 分割符

目的：实现分隔符效果

[预览](https://codepen.io/alphardex/pen/MWgeoKz)

```markup
<ul>
  <li><a href="#">Home</a></li>
  <li><a href="#">Archive</a></li>
  <li><a href="#">About</a></li>
</ul>
```

```css
ul {
  display: flex;
  font-weight: bold;
  list-style-type: none;

  li {
    &:not(:last-child) {
      margin-right: 5px;

      &::after {
        content: "|";
        margin-left: 5px;
      }
    }
  }
}
```

添加伪元素`::after`，内容`content: "|"`，设置间距

再用`:not(:last-child)`去除伪元素的最后一个子元素即可

## 用户体验

### 提示用角标

目的：在按钮右上角创建一个提示用的角标

[预览](https://codepen.io/alphardex/pen/KKPWMRq)

```markup
<button class="badge" count="7">消息</button>
```

```css
body {
  display: flex;
  justify-content: center;
}

button {
  position: relative;
  padding: 20px;
  border-radius: 20px;
  font-size: 24px;
}

.badge::before {
  content: attr(count);
  position: absolute;
  right: 10px;
  top: -8px;
  background: tan;
  padding: 0 8px;
  border-radius: 12px;
  transform: translate(50%, 0);
}
```

伪元素的`content`可通过`attr()`来获取标签的某一属性值

类似的提示框也可以配合过渡动画来实现：[预览](https://codepen.io/alphardex/pen/ExYvYzP)

### 伸缩式按钮

目的：实现伸缩式按钮（鼠标悬浮按钮则展开，移开按钮则收缩）

[预览](https://codepen.io/alphardex/pen/eYOegOx)

```markup
<a href="#" class="sliding-button">
  <span>下载</span>
  <span>720p</span>
</a>
<a href="#" class="sliding-button">
  <span>下载</span>
  <span>1080p</span>
</a>
```

```css
$tianyi-blue: #66ccff;

body {
  display: flex;
  height: 100vh;
  align-items: center;
  justify-content: center;
}

.sliding-button {
  background: $tianyi-blue url(https://i.loli.net/2019/09/04/JULm1Agr5Gzy7iK.png)
    no-repeat -30px center;
  overflow: hidden;
  transition: padding 0.2s ease, background-position 0.2s ease,
    transform 0.5s ease;

  border: 1px solid $tianyi-blue;
  border-radius: 4px;
  color: #fff;
  text-decoration: none;
  text-transform: uppercase;
  padding: 6px 16px 6px 16px;
  font-size: 18px;
  font-weight: bold;
  line-height: 27px;

  &:nth-child(1) {
    margin-right: 1em;
  }

  span:nth-child(1) {
    position: absolute;
    left: -80px;
  }

  &:hover {
    padding-left: 69px;
    background-position: 5px center;
    transform: scale(1, 1);

    span:nth-child(1) {
      left: 30px;
    }
  }
}
```

给“下载”设置负的`left`用于将其移除视界范围

鼠标悬浮时设置`padding-left`使按钮给“下载”留出空间

`left: 30px;`和`transform: scale(1, 1);`把“下载”拉回按钮中（这个很 hack）

最后设定过渡动画即可看到流畅的过渡效果了

## 结构与布局

### 圣杯布局

目的：实现圣杯布局（左中右三列，左右两列定宽，中间列自适应宽度）

[预览](https://codepen.io/alphardex/pen/ewVLJZ)

```markup
<div class="g-container">
  <div class="g-left">left</div>
  <div class="g-middle">middle</div>
  <div class="g-right">right</div>
</div>
```

```css
.g-container {
  display: flex;
  height: 100vh;
  min-width: 400px;

  & > div {
    text-align: center;
    color: #fff;
    line-height: 100vh;
    font-size: 3vw;
  }

  .g-left {
    order: 1;
    flex: 200px 0 0;
    background: cyan;
  }

  .g-middle {
    order: 2;
    flex: auto 1 0;
    background: purple;
  }

  .g-right {
    order: 3;
    flex: 200px 0 0;
    background: red;
  }
}
```

左右列的`flex-grow`设为`200px`，表示它们各占`200px`空间

中间列的`flex-grow`设为`auto`，`flex-shrink` 设为 1，表明是自适应宽度

## 过渡与动画

### 动态侧边栏

目的：创建一个导航用的侧边栏，里面包含一个列表，用户鼠标浮动到链接上时会显示过渡动画

[预览](https://codepen.io/alphardex/pen/QXvgaq)

```markup
<body>
  <nav>
    <ul>
      <li><a href="#">home</a></li>
      <li><a href="#">resume</a></li>
      <li><a href="#">tags</a></li>
      <li><a href="#">categories</a></li>
      <li><a href="#">archives</a></li>
      <li><a href="#">search</a></li>
    </ul>
  </nav>
</body>
```

```css
nav {
  position: relative;
  background: hsl(60, 100%, 65%);
  width: 218px;
  padding-top: 5px;
}

ul {
  list-style: none;
  width: 197px;
  margin: 0 auto;
  padding: 0;
  vertical-align: baseline;
  li {
    margin: 2.5px 0;
    a {
      display: inline-block;
      position: relative;
      padding: 8px 0;
      padding-left: 20px;
      color: black;
      font-weight: 800;
      font-size: 22px;
      letter-spacing: 0.075em;
      text-decoration: none;
      text-transform: uppercase;
      &::before {
        content: "";
        position: absolute;
        opacity: 0;
        background: url("https://test.demo-1s.com/images/2019/06/24/d31DXx0KYav6cZkG.png")
          left center no-repeat;
        top: 0;
        left: 2px;
        width: 16px;
        height: 100%;
        transform: translateX(10px);
        transition: 0.3s ease-out;
      }
      &:hover::before {
        opacity: 1;
        transform: translateX(0);
      }
      &::after {
        content: "";
        position: absolute;
        height: 4px;
        width: 0;
        bottom: 2px;
        left: -3px;
        opacity: 0;
        background: white;
        border: 2px solid black;
        transition: all 0.3s cubic-bezier(0.445, 0.05, 0.55, 0.95);
      }
      &:hover::after {
        opacity: 1;
        width: calc(100% + 6px);
      }
    }
  }
}

body {
  margin: 0;
  padding: 0;
}
```

给 a 添加 2 个伪元素，并分别为其设置`transition`以及`hover`时的状态即可

### 图片幻灯片

目的：四幅图片（这里用颜色代替）按顺序依次向右滑动显示，最后被四道白色矩形依次遮住

[预览](https://codepen.io/alphardex/pen/WqaJbG)

```markup
<body>
  <main id="slider">
    <div class="image"></div>
    <div class="image"></div>
    <div class="image"></div>
    <div class="image"></div>
    <div class="paint">
      <div></div>
      <div></div>
      <div></div>
      <div></div>
    </div>
  </main>
</body>
```

```css
$imgs: blue, cyan, yellow, tan;

html,
body {
  margin: 0;
  padding: 0;
}

body {
  display: flex;
  min-height: 100vh;
}

#slider {
  position: relative;
  width: 500px;
  height: 300px;
  margin: auto;
}

.image {
  position: absolute;
  width: 0%;
  height: 100%;
  overflow: hidden;

  &::after {
    content: "";
    display: block;
    width: 500px;
    height: 300px;
    background-size: cover;
    background-position: center;
  }

  @for $i from 1 through length($imgs) {
    &:nth-child(#{$i})::after {
      background-color: nth($imgs, $i);
    }
  }
}

.paint {
  position: absolute;
  width: 100%;
  height: 100%;

  div {
    width: 100%;
    height: 25%;
    background-color: white;
    transform: translateX(-100%);
  }
}

// animation
@for $i from 1 to 5 {
  .image:nth-child(#{$i}) {
    animation: show-image 0.7s ease (0.5s + 0.2s * $i - 0.2s) forwards;
  }
}

@for $i from 1 to 5 {
  .paint div:nth-child(#{$i}) {
    animation: slide-right 0.5s ease (1.6s + 0.1s * $i - 0.1s) forwards;
  }
}

// keyframes
@keyframes show-image {
  from {
    width: 0%;
  }
  to {
    width: 100%;
  }
}

@keyframes slide-right {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0%);
  }
}
```

添加一个 slider，用`flex`使其垂直居中

在 slider 上添加 4 个 image，并使其大小和 slider 相同并重叠在一起，利用`overflow:hidden`隐藏它们

为这些 image 设置`::after`矩形伪元素，用作图片背景

创建`show-image`关键帧：元素的宽度从 0%变为 100%

为 image 创建动画：把`show-image`作为关键帧，每张图设置不同的延时`delay`，`fill-mode`设置`forwards`表示动画完成时保持最后一个关键帧的属性值，这样就完成了 4 张图依次向右滑动的效果

添加一个 paint 以及 4 个子 div，表示 4 道白色矩形，默认的位置是向 x 轴左侧平移 1 个元素单位

创建`slide-right`关键帧：向 x 轴左侧平移 1 个元素单位变为平移 0 个单位，也就是平移到原点

为 paint 的 4 个子 div 创建动画：把`slide-right`作为关键帧，同样给每个矩形设置不同的延时`delay`和`forwards`的`fill-mode`，就完成了四道白色矩形依次将图片遮住的效果
