CSS 中一些小技巧汇总

CSS 中一些小技巧汇总

之前整理过 JavaScript 中一些常用方法的实现,这次就来整理一下 CSS 当中一些小技巧,部分内容参考自 30 seconds of CSS

清除浮动更好的方式

无需借助辅助元素进行浮动的清除,一般在 float 布局当中才会使用,在实际场景中还是推荐使用 flexbox 布局或者网格布局

1
2
3
4
5
<div class="clearfix">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
1
2
3
4
5
6
7
8
9
.clearfix::after {
content: '';
display: block;
clear: both;
}

.item {
float: left;
}

相邻兄弟选择器

通常我们在实现一个列表的时候,一般需要给列表当中的 li 元素添加边框,比较常见的做法是给所有的 li 都添加某个方向的边框,然后使用 :last-child 或者 :first-child 过滤掉首部或者尾部的元素,如下

1
2
3
4
5
6
7
li {
border-bottom: 1px solid lightblue;
}

li:last-child {
border-bottom: none;
}

但是使用相邻兄弟选择器来实现的话就简单许多

1
2
3
ul > li + li {
border-top: 1px solid lightblue;
}

居中的一种简单实现方式

通常我们在实现居中布局的时候经常会去使用 flex 来实现,比如针对容器 <div class="wrap"><div></div></div> 当中的子元素实现居中,我们采用的方式一般是下面这样的

1
2
3
4
5
6
7
8
9
10
11
.wrap {
display: flex;
align-items: center;
justify-content: center;
}

div {
width: 200px;
height: 200px;
background: lightblue;
}

除了以上方式以外,还有一种更为简便的方式也可以达到我们想要的效果

1
2
3
4
5
6
7
8
9
10
.wrap {
display: flex;
}

div {
width: 200px;
height: 200px;
background: lightblue;
margin: auto;
}

不变宽高比(等比)

示例可见 不变宽高比(等比),给定宽度可变的元素,它将确保其高度以响应方式保持成比例(即其宽高比保持不变)

1
<div class="box"></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.box {
width: 50%;
background: rgb(66, 201, 201);
}

.box::before {
content: '';
padding-top: 100%;
float: left;
}

.box::after {
content: '';
display: block;
clear: both;
}
  • ::before,为元素定义一个伪元素
  • padding-top: 100%,设置伪元素的内上边距,百分比的值是按照宽度计算的,所以元素是响应式的
  • 此方法还允许将内容正常放置在元素内

图片在容器中自适应

示例可见 图片在容器中自适应,设置图像在其容器内的适合度和位置,同时保留其宽高比,等同于 background-size 的效果,但是其可以直接作用于 img 标签上

1
<img src="https://raw.githubusercontent.com/heptaluan/blog-backups/master/cdn/cover/81.webp">
1
2
3
4
5
6
7
8
9
img {
object-fit: contain;
object-position: center;
}

img {
object-fit: cover;
object-position: right top;
}
  • object-fit: contain,容器内显示整个图像,并且保持宽高比
  • object-fit: cover,用图像填充容器,并保持宽高比
  • object-position: [x] [y],对图像的显示部位进行调整

将元素垂直居中于另一个元素

示例可见 将元素垂直居中于另一个元素

1
2
3
<div class="center">
<p>这是一段测试文本(深色区域是由我撑开的)</p>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.center {
height: 150px;
background: rgb(11, 121, 121);
}

.center::before {
content: '';
display: inline-block;
height: 100%;
vertical-align: middle;
}

.center p {
display: inline-block;
vertical-align: middle;
font-size: 14px;
color: #fff;
}
  • 使两个元素在水平方向上垂直对齐,不设置前者的宽度,而是设置高度为 100% 使其保持与容器一致的高度
  • 尝试给 .center::before 添加一点宽度并且设置一个背景色就很明了了
  • 使用 :before 伪元素的样式垂直对齐内联元素而不更改其 position 属性

最后一项占满剩余高度

示例可见 最后一项占满剩余高度,通过为最后一个元素提供当前视口中剩余的可用空间,即使在调整窗口大小时,也可以利用可用的视口空间

1
2
3
4
5
<div class="wrapper">
<div class="header">Header</div>
<div class="content">Content</div>
<div class="footer">Footer</div>
</div>
1
2
3
4
5
6
7
8
9
.wrapper {
height: 100%;
display: flex;
flex-direction: column;
}

.wrapper > div:last-child {
flex: 1;
}
  • display: flex,启用 flex
  • flex-direction: column,将项目的顺序设置成从上到下
  • flex-grow: 1flexbox 会将容器的剩余可用空间应用于最后一个子元素,父级必须具有视口高度
  • flex-grow:1 可以应用于第一个或第二个元素,它将具有所有可用空间

列表计数器

示例可见 列表计数器,计数器本质上是由 CSS 维护的变量,其值可以通过 CSS 规则递增以跟踪它们被使用的次数

1
2
3
4
5
6
7
8
9
10
11
12
<ul>
<li>List item</li>
<li>List item</li>
<li>
List item
<ul>
<li>List item</li>
<li>List item</li>
<li>List item</li>
</ul>
</li>
</ul>
1
2
3
4
5
6
7
8
ul {
counter-reset: counter;
}

li::before {
counter-increment: counter;
content: counters(counter, '.') ' ';
}
  • 可以使用任何类型的 HTML 标签创建有序列表
  • counter-reset,初始化计数器,该值是计数器的名称,默认情况下计数器从 0 开始,此属性还可用于将其值更改为任何特定数字
  • counter-increment,用于可数的元素,一旦计数器重置初始化,计数器的值可以增加或减少
  • counter(name, style),显示节计数器的值,通常用于内容属性,此函数可以接收两个参数,第一个作为计数器的名称,第二个参数表示占位内容
  • CSS 计数器对于制作轮廓列表特别有用,因为计数器的新实例是在子元素中自动创建的,使用 counters() 函数,可以在不同级别的嵌套计数器之间插入分隔文本

创建动态阴影

示例可见 创建动态阴影,创建类似于 box-shadow 的阴影,但基于元素本身的颜色

1
<div class="box"></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.box {
width: 200px;
height: 200px;
position: relative;
z-index: 1;
background: linear-gradient(75deg, #6d78ff, #00ffb8);
}

.box::after {
content: '';
width: 100%;
height: 100%;
position: absolute;
background: inherit;
top: 10px
filter: blur(8px);
opacity: .7;
z-index: -1;
}
  • ::after,定义一个伪元素
  • position: absolute,使伪元素脱离文档流并相对于父级定位
  • width/height: 100%,对伪元素进行大小调整以填充其父元素的大小,使其大小相等
  • background: inherit,使伪元素继承父级的线性渐变
  • top: 10px,将伪元素相对于其父元素略微偏移
  • filter: blur(8px),设置伪元素模糊效果,以创建下方阴影效果
  • opacity: 0.7,设置伪元素透明度
  • z-index: -1,将伪元素定位在父元素后面但在背景前面

鼠标悬停渐变效果

示例可见 鼠标悬停渐变效果,一种鼠标悬停效果,其中渐变跟随鼠标光标

1
2
3
<button>
<span>Hover me</span>
</button>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
button {
position: relative;
background: #6d78ff;
padding: 20px 70px;
border: none;
color: white;
font-size: 22px;
cursor: pointer;
outline: none;
overflow: hidden;
border-radius: 10px;
}

span {
position: relative;
pointer-events: none;
}

button::before {
--size: 0;
content: '';
position: absolute;
left: var(--x);
top: var(--y);
width: var(--size);
height: var(--size);
background: radial-gradient(circle closest-side, #00ffb8, transparent);
transform: translate(-50%, -50%);
transition: width .2s ease, height .2s ease;
}

button:hover::before {
--size: 300px;
}
1
2
3
4
5
6
document.querySelector('button').onmousemove = (e) => {
const x = e.pageX - e.target.offsetLeft
const y = e.pageY - e.target.offsetTop
e.target.style.setProperty('--x', `${x}px`)
e.target.style.setProperty('--y', `${y}px`)
}
  • 利用伪元素来达到渐变效果,使其显示位置与鼠标悬停位置一致
  • var() 函数可以代替元素中任何属性中的值的任何部分

重置所有样式

示例可见 重置所有样式,使用一个属性将所有样式重置为默认值,这不会影响 directionunicode-bidi 属性

1
2
3
4
<div class="box">
<p>这是一段测试文本(这一段文本属性没有被重置,默认使用的继承过来的属性)</p>
<p>这是一段测试文本(这一段文本属性已被重置,使用控制台可以发现继承过来的属性均已重置)</p>
</div>
1
2
3
.box p:last-child {
all: initial;
}
  • all 属性允许您将所有样式(继承或不继承)重置为默认值

形状分隔符

示例可见 形状分隔符,使用 SVG 形状分割两个不同的块以创建更有趣的视觉外观

1
<div class="box"></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
.box {
position: relative;
height: 50px;
}

.box::after {
content: '';
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 12'%3E%3Cpath d='m12 0l12 12h-24z' fill='%23fff'/%3E%3C/svg%3E");
position: absolute;
width: 100%;
height: 12px;
bottom: 0;
}
  • background-image: url(),添加 SVG 形状作为伪元素的背景图像,默认情况下重复,它必须与要分割的块颜色相同
  • 如果想使用其他图形,可以使用 URL-encoder for SVG

滑动开关

示例可见 滑动开关,可以依靠纯 CSS 来实现一个 Switch 滑动开关效果

1
<input type="checkbox" id="checkbox" /> <label for="checkbox" class="switch"></label>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 30px;
background-color: rgba(0, 0, 0, 0.25);
border-radius: 20px;
cursor: pointer;
transition: all 0.3s;
}

.switch::after {
content: '';
position: absolute;
width: 28px;
height: 28px;
border-radius: 18px;
background-color: white;
top: 1px;
left: 1px;
transition: all 0.3s;
}

input[type="checkbox"]:checked + .switch::after {
transform: translateX(30px);
}

input[type="checkbox"]:checked + .switch {
background-color: #499AFF;
}

input[type="checkbox"] {
border: 0;
width: 0;
height: 0;
}
  • 利用 inputcheckbox 的特性来实现整个效果
  • 使用 switch::after 来实现开关外形
  • input:checked 状态下动态调整 switch::after 的位置
  • 最后将 input 隐藏掉,只使用 label 来进行关联

画一个三角形

示例可见 画一个三角形

1
<div class="box"></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
.box01 {
width: 0;
height: 0;
border-top: 30px solid #499AFF;
border-left: 30px solid transparent;
border-right: 30px solid transparent;
}

.box02 {
width: 0;
height: 0;
border-right: 30px solid #499AFF;
border-top: 30px solid transparent;
border-bottom: 30px solid transparent;
}

.box03 {
width: 0;
height: 0;
border-bottom: 30px solid #499AFF;
border-left: 30px solid transparent;
border-right: 30px solid transparent;
}

.box04 {
width: 0;
height: 0;
border-left: 30px solid #499AFF;
border-top: 30px solid transparent;
border-bottom: 30px solid transparent;
}

.box05 {
width: 0;
height: 0;
border-bottom: 50px solid #499AFF;
border-left: 30px solid transparent;
border-right: 30px solid transparent;
}

.box06 {
width: 30px;
height: 30px;
border-top: 2px solid #499AFF;
border-right: 2px solid #499AFF;
}

.box07 {
width: 30px;
height: 30px;
border-top: 2px solid #499AFF;
border-right: 2px solid #499AFF;
transform: rotate(45deg);
}
  • 将高度和宽度设为 0,剩下四个边框,再将某一方向边框去掉,除开对应的一边,将另外两边设置为透明即可
  • 如果需要调整角度,在上面基础之上调整对应宽度即可
  • 如果需要空心箭头,设置夹角两边边框即可,方向可以根据需要进行调整

斑马线效果

示例可见 斑马线效果

1
<div class="box"></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.box01 {
width: 100%;
height: 20px;
background-color: #499AFF;
background-image: linear-gradient(45deg, hsla(0, 0%, 100%, .15) 25%, transparent 0, transparent 50%, hsla(0, 0%, 100%, .15) 0, hsla(0, 0%, 100%, .15) 75%, transparent 0, transparent);
background-size: 36px 36px;
}

.box02 {
width: 100%;
height: 20px;
background-color: #499AFF;
background-image: linear-gradient(45deg, hsla(0, 0%, 100%, .15) 25%, transparent 0, transparent 50%, hsla(0, 0%, 100%, .15) 0, hsla(0, 0%, 100%, .15) 75%, transparent 0, transparent);
background-size: 36px 36px;
animation: progress-bar-stripes 2s linear infinite;
}

@keyframes progress-bar-stripes {
from {
background-position: 36px 0;
}

to {
background-position: 0 0;
}
}
  • 利用 background-imagelinear-gradient() 函数创建斑马线
  • 如果想让其运动起来,添加动画效果改变其 background-position 位置即可

加载动画

示例可见 加载动画,下面是一种实现方式

1
2
3
4
5
<div class="box">
<div></div>
<div></div>
<div></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
.box {
height: 80px;
display: flex;
justify-content: center;
align-items: center;
}

.box > div {
width: 12px;
height: 12px;
margin: 15px 8px;
background: #fff;
border-radius: 50%;
animation: loading .6s infinite alternate
}

.box > div:nth-child(2) {
animation-delay: .2s;
}

.box > div:nth-child(3) {
animation-delay: .4s;
}

@keyframes loading {
to {
opacity: 0.1;
transform: translate3d(0, -10px, 0);
}
}

另外一种方式

1
2
3
<div class="box">
<div class="loading"></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@keyframes loading {
from {
transform: rotate(0deg);
}

to {
transform: rotate(360deg);
}
}

.box {
height: 80px;
background: #499AFF;
display: flex;
justify-content: center;
align-items: center;
}

.box .loading {
width: 20px;
height: 20px;
border: 2px solid #f3f3f3;
border-top: 2px solid #00ffb8;
border-radius: 50%;
animation: loading 3s infinite linear;
}
  • 两者原理一致,使用 @keyframes 来定义动画效果,使元素在竖直方向上运动
  • 使用 animation-delay 延迟执行来达到交替的效果
  • 如果设定了元素的 border-radius,则 border-top 会显示为弧形

按钮边框动画

示例可见 按钮边框动画,例一如下

1
2
3
<div class="box">
<button>提交</button>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
button {
padding: 15px 50px;
outline: none;
border: none;
position: relative;
background: #499AFF;
cursor: pointer;
color: #fff;
transition: all .3s;
}

button::before,
button::after {
border: 0 solid transparent;
transition: all .3s;
position: absolute;
content: '';
height: 24px;
width: 24px;
}

button::before {
border-top: 2px solid rgb(41, 137, 255);
left: 0;
top: -8px;
}

button::after {
border-bottom: 2px solid rgb(41, 137, 255);
right: 0;
bottom: -8px;
}

button:hover {
background: rgb(41, 137, 255);
}

button:hover::before,
button:hover::after {
width: 100%;
height: 100%;
}

例二

1
2
3
4
5
<div class="box">
<button>提交</button>
<div></div>
<div></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
.box {
position: relative;
overflow: hidden;
}

.box div {
transition: all .35s;
cursor: pointer;
}

.box div:nth-of-type(1) {
width: 126px;
height: 50px;
border: solid #499AFF;
border-width: 0 2px;
position: absolute;
left: 0;
top: 0;
transform: translate(0, -200px);
}

.box div:nth-of-type(2) {
width: 130px;
height: 46px;
border: solid #499AFF;
border-width: 2px 0;
position: absolute;
left: 0px;
top: 0;
transform: translate(-200px, 0);
}

.box button {
width: 130px;
height: 50px;
outline: none;
border: none;
position: relative;
background: #ccc;
cursor: pointer;
transition: all .3s;
}


.box:hover button {
background: rgb(187, 187, 187);
}

.box:hover div:nth-of-type(1),
.box:hover div:nth-of-type(2) {
transform: translate(0, 0);
}
  • 两个示例的原理是一致的,均是使用 :before:after 伪元素作为在悬停时设置动画的边框

悬停下滑线动画

示例可见 悬停下滑线动画,当文本悬停时,创建文本下划线动画效果

1
<p>这是一段测试文本</p>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
p {
display: inline-block;
color: #fff;
position: relative;
font-size: 16px;
}

p:after {
content: '';
position: absolute;
width: 100%;
transform: scaleX(0);
height: 2px;
bottom: -2px;
left: 0;
background: #fff;
transform-origin: bottom right;
transition: transform .3s ease-out;
}

p:hover::after {
transform: scaleX(1);
transform-origin: bottom left;
}
  • display: inline-block,使 p 成为内联块,以防止下划线跨越整行宽度而不仅仅是文本内容
  • transform: scaleX(0),最初将伪元素缩放为 0,因此是看不见的
  • bottom: 0 and left: 0,将伪元素放在父元素的左下角
  • transition: transform 0.25s ease-out,设置动画效果为 ease-out,并且在 0.25 秒内完成
  • transform-origin: bottom right,变换中心点到父元素的右下角
  • :hover::after,然后使用 scaleX(1) 将宽度转换为 100%,然后将中心点更改为左下角,允许它在悬停时从另一个方向转换出来

兄弟元素淡化

示例可见 兄弟元素淡化,悬停时兄弟节点淡化显示

1
2
3
4
5
6
7
<ul class="box">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.box {
width: 100%;
height: 80px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: row;
}

li {
list-style: none;
width: 50px;
height: 50px;
line-height: 50px;
text-align: center;
font-size: 16px;
margin: 0 20px;
background: #499AFF;
color: #fff;
transition: opacity .3s;
cursor: pointer;
}

.box:hover li:not(:hover) {
opacity: 0.5;
}
  • transition: opacity 0.2s,设置 0.2 秒的淡化动画
  • .box:hover li:not(:hover),当父级悬停时,选择当前未悬停的 li 子项并将其透明度更改为 0.5

target 选择器

示例可见 target 选择器,点击切换的时候 div 会同步变化

1
2
3
4
5
6
7
8
<a href="#1">1</a>
<a href="#2">2</a>
<a href="#3">3</a>
<div class="box">
<div id="1"></div>
<div id="2"></div>
<div id="3"></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.box {
display: flex;
align-items: center;
}

.box div {
width: 100px;
height: 100px;
margin: 5px;
background: #499AFF;
transition: flex 1s;
}

.box div:target {
flex: 1;
background: lightcoral;
}

立体感按钮

示例可见 立体感按钮,页面布局就是一个单纯的 <button></button> 按钮,样式如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
button {
padding: 1em 3em;
border-radius: .2em;
outline: none;
border: none;
color: #fff;
cursor: pointer;
background: linear-gradient(#3de5fb, #26acbd);
text-shadow: 0 1px 1px grey;
box-shadow: 0 0.3em 0 #068494, 0 0.3em 0.3em grey;
}

button:active {
box-shadow: 0 0.1em 0 #068494, 0 0.1em 0.1em grey;
transition: translate(0, 0.05em);
}
# CSS

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×