之前整理过 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 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: 1
,flexbox
会将容器的剩余可用空间应用于最后一个子元素,父级必须具有视口高度
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 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()
函数可以代替元素中任何属性中的值的任何部分
重置所有样式
示例可见 重置所有样式,使用一个属性将所有样式重置为默认值,这不会影响 direction
和 unicode-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 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; }
|
- 利用
input
的 checkbox
的特性来实现整个效果
- 使用
switch::after
来实现开关外形
- 在
input:checked
状态下动态调整 switch::after
的位置
- 最后将
input
隐藏掉,只使用 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 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 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-image
的 linear-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 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); }
|