这是我参与8月更文挑战的第19天,活动详情查看:8月更文挑战

问题起源

就在昨天,我们通过文章纯CSS绘制五角星简单介绍了CSS中的一个截取属性值:clip-path可以按照指定的方式截取指定形状的图形,并且介绍了clip-path的两种取值:

  1. 按照盒模型取值:margin-boxborder-box

  2. 取函数,如polygon多边形函数,我们了解到可以通过如下方式绘制,或者说截取一个多边形:

    1
    clip-path: polygon(x1 y1, x2 y2, x3 y3, ....)

那么,clip-path还有哪些精妙的取值来绘制图形呢?

今天我们来认识一下其他函数。

inset

改函数定义为截取一个矩形,4个参数分别表示距离外层盒模型的上、右、下、左边界的偏移量。类似marginpadding,也可以通过1,2,4个值来设定4个偏移量。(刚知道这种简略写法被称为:边际速记语法)。

如下所示,第二行类似border-radius,设置截图图形的4角的弧度。

1
2
clip-path: inset(22% 12% 15px 30px);
clip-path: inset(22% 12% 15px 30px round 6px);

如图所示:

完整图形:

image.png

截图代码:

1
clip-path: inset(10% 20% 20% 20% round 280px 10px 10px 280px);

截图效果:

image.png

circle

见字知意,截取一个圆形图案,函数参数解释如下所示:

1
clip-path: circle(6rem at 0rem 0rem);

这段代码表示在盒模型中,以坐标(0rem, 0rem)的位置为圆心,已6rem长度为半径R,截图圆形图案。当然,这个位置截图的效果会是一个扇形。

仍然采用上图为原图,以下代码的截图效果:

1
clip-path: circle(200px at 40% 40%);

image.png

ellipse

同样见字知意,绘制椭圆,其含义为:

1
ellipse(x半径 y半径 as x y)

x, y表示圆心位置。对比circle并不难理解。

代码:clip-path: ellipse(200px 100px at 40% 40%);

截图效果如下:

image.png

遗留了一个未解决的问题

一个图形能否使用两个clip-path截取函数呢?

比如我对完整图形先使用circle截取,如何再对截图后的图案再次进行截取,CSS允许这样做吗?

这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战

问题起源

问题起源于最近在读的《CSS Secret》书籍中介绍了一个CSS属性,clip-path,没听过这个属性,所以略微研究了一下。

clip-path,MDN文档链接:https://developer.mozilla.org/zh-CN/docs/Web/CSS/clip-path

官网释义:

CSS 属性使用裁剪方式创建元素的可显示区域。区域内的部分显示,区域外的隐藏。

如何理解这一点呢?clip-path可取哪些值呢?

各式各样的裁剪取值

可按照盒模型取值

根据MDN给的例子,我们可以取:margin-boxborder-boxpadding-boxcontent-box等等,各个取值含义如下图所示:

image.png

函数

clip-path取的函数范围在MDN被定义为<basic-shape>,其中文翻译为<几何盒>

函数包括:inset(), circle(), ellipse(), polygon(), path()

本文题为“如何绘制五角星”,即如何绘制复杂的多边形,用到的函数是polygon()

polygon,翻译为多边形,熟悉MATLAB绘图的小伙伴应该对这个函数不陌生,在MATLAB中polygon就是一个用来绘制二维多边形的函数。

那么,如何在在CSS中使用polygon绘制多边形呢?

polygon

先来看官网释义

polygon( [<fill-rule>,]? [<shape-arg> <shape-arg>]# )

每一对在列表中的参数都代表了多边形顶点的坐标, xiyi ,i代表顶点的编号,即,第i个顶点。

如何理解这句话呢?我们来看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<title>clip-path裁剪</title>
<body>
<div class="box">
</div>
</body>
<style>
.box {
width: 876px;
height: 576px;
background: url('https://cdn.pixabay.com/photo/2018/01/12/10/19/fantasy-3077928_960_720.jpg') no-repeat;
background-size: 100% 100%;
/* clip-path: polygon(50% 0, 50% 50%, 0 50%, 0 0); */
}
</style>
</html>

在注释掉clip-path一行后,完整的展示样式如下图所示:

image.png

当我们取消注释后,图又是什么样子的呢?

image.png

可以看到图片只剩下左上角1/4的部分,其他部分都被裁剪掉了。不难理解,polygon的参数就是一个一个的多边形顶点坐标,即:

1
clip-path: polygon(x1 y1, x2 y2, x3 y3, ....)

则五角星也很容易理解了,只要将其10个顶点坐标给出即可。

1
clip-path: polygon(50% 2.4%, 34.5% 33.8%, 0% 38.8%, 25% 63.1%, 19.1% 97.6%, 50% 81.3%, 80.9% 97.6%, 75% 63.1%, 100% 38.8%, 65.5% 33.8%);

效果如下图所示:

image.png

如果图形是正方形的,效果会更好。

这是我参与8月更文挑战的第17天,活动详情查看:8月更文挑战

问题起源

问题起源于在生产环境要做一个轮播图,之前我们在文章:纯CSS实现轮播图 以及文章:无框架从零实现一个轮播图 | 8月更文挑战介绍了两种生成轮播图的方式,偶然发现VUE中有一个动画功能:进入/离开&列表过渡,其中有个功能与我们想要的轮播效果很相似。下图取自进入/离开&列表过渡官网第一个例子,效果图如下:

8ea1eccf-4ac1-463f-bd11-582aac51c558.gif

这跟我们想要的轮播图切换效果很相似。

由此开启我们的学习之路,出发~~

<transition>的基本用法

官网给出的例子解释说,<transition>支持以下4种“进入/离开”,包括:

  • 条件渲染 (使用 v-if)
  • 条件展示 (使用 v-show)
  • 动态组件
  • 组件根节点

例如:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>Document</title>
</head>

<body>
<div id="components-demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="fade">
<p v-if="show">hello</p>
</transition>
</div>
</body>

<script>

new Vue({
el: '#components-demo',
data: {
abb: 'abc',
show: false
},
methods: {

}
});


</script>
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity 2s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
</style>

</html>

这个官网示例简单的说明了如何使用<transition>

并且通过官网解释的动画原理可以看出,其基本原理是通过动态绑定CSS实现动画效果的。

那么问题来了,能够通过<transition>实现轮播图呢?根据含义猜测这应该是VUE中“列表过渡”部分的知识,我们来尝试一下

使用<transition-group>实现轮播图

vue的<transition>只能使用单一组件而不支持列表过渡,列表过渡需要使用<transition-group>,完整代码如下:

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>Document</title>
</head>

<body>
<div id="app">
<button @click="activeIndex++">btton</button>
<transition-group name="list" tag="div" style="overflow: hidden;height: 40px;border: 1px solid black;" class="center">
<div v-for="index in list" :key="index" v-show="activeIndex === index" style="border: 1px solid black;margin: 0;padding:0;background: lightblue;">
{{index}}
</div>
</transition-group>
</div>
</body>

<script>

new Vue({
el: '#app',
data: {
abb: 'abc',
show: false,
list: [
1,2,3,4,5
],
activeIndex: 1
},
methods: {

}
});


</script>
<style>
.list-enter-to {
transition: all 1s ease;
transform: translateY(0);
}

/*上一个元素消失的动画*/
.list-leave-active {
transition: all 1s ease;
transform: translateY(-40px);

}

/*下一个元素进入的动画效果*/
.list-enter {
transform: translateY(100%);
}

.list-leave {
transform: translateY(0);
}

.center {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

</style>

</html>

动画效果:

60aabd5d-869c-4ce9-8d4f-483c50c06ae7.gif

很奇怪的一点是,最后元素总要抖动一下。暂未查明原因。

这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战

毛玻璃效果后续

在介绍如何生成平行四边形之前,之前我的一篇文章纯CSS生成毛玻璃效果,有用户评论说backdrop-filter: blur(xxx);这个属性。

所以先来了解一下这个backdrop-filter是个什么样的属性?

先来看一下效果,如下图所示,可以说非常不错。

image.png

完整代码:

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
<!DOCTYPE html>
<title>毛玻璃效果</title>

<body>
<div class="background-box">
<div class="txt-box">
文字内容, 毛玻璃效果:
backdrop-filter: blur(20px);
</div>
</div>
</body>
<style>
.background-box {
width: 800px;
height: 600px;
background: url("https://cdn.pixabay.com/photo/2021/07/12/19/49/landscape-6421773__340.jpg") 0 / cover fixed;
/* background-attachment: fixed; */

display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}

.txt-box {
z-index: 2;
width: 600px;
height: 400px;
font-size: 20px;
font-weight: bold;
/* background: hsla(0, 0%, 100%, .3); */

display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
backdrop-filter: blur(20px);
}

</style>

</html>

至此,我们又学会了一种简易的生成毛玻璃效果的方法!!!感谢Forx-Js

平行四边形

transform可用函数中有个叫skew, 相关的还有skewX, skewY,我们来看一下效果。

55ca0f35-a63a-440f-b8df-3357922bcaba.gif

26736fdd-66ae-479f-8db7-798bbb92aa29.gif

fa8a7097-a57d-4e2c-917d-ddf8a03f04db.gif

但是存在一个严重的问题是文字也会随着整体变形而变形,那么如何使得文字不变动,只让图形变动呢?根据毛玻璃那篇文章的想法,我们将有色图形设置为文字元素下一层z-index: -1的伪元素,对伪元素使用skew函数使得其发生变形,而文字本身的DOM并不变,来看一下效果:

5d142c9b-6ce3-4c29-aaaf-883ab4165e6e.gif

源代码如下所示:

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
55
56
57
58
<!DOCTYPE html>
<title>平行四边形</title>
<body>
<div class="box">
skewX(-45deg)
</div>
</body>
<style>
body {
width: 100%;
height: 100vh;

/*居中*/
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.box {
height: 200px;
width: 400px;
font-size: 30px;

/*居中*/
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;

transform: skew(0, 0);

position: relative;
border: 1px solid black;

}
.box::before {
animation: skew 3s infinite;
background-color: lightblue;
content: ''; /* 用伪元素来生成一个矩形 */
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
z-index: -1;
background: lightblue;
}

@keyframes skew {
from {
transform: skewX(0);
}

to {
transform: skewX(-45deg);
}
}


</style>
</html>

这是我参与8月更文挑战的第14天,活动详情查看:8月更文挑战

今天我们尝试使用CSS绘制一个毛玻璃效果,在学习过程中,可以了解到CSS的几个属性:

1
2
filter: blur(模糊半径); // 元素模糊
background: hsla(色相, 饱和度, 亮度, 透明度)

blur

CSS中有一个blur()函数可以生成模糊效果,如下图所示:

image.png

上图基本代码:

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
<!DOCTYPE html>
<title>毛玻璃效果</title>
<body>
<div class="background-box">
<div class="txt-box">
文字内容
</div>
</div>
</body>
<style>
.background-box {
width: 700px;
height: 500px;
background: url('https://cdn.pixabay.com/photo/2021/07/14/09/14/siberian-cat-6465485_960_720.jpg') no-repeat;
background-size: 100% 100%;

display: flex;
flex-direction: row;
align-items: center;
justify-content: center;

filter: blur(4px);
}

/* .txt-box {
width: 300px;
height: 200px;
background: white;
filter: blur(4px);
} */
</style>
</html>

blur函数官方释义:https://developer.mozilla.org/zh-CN/docs/Web/CSS/filter-function/blur()

但是blur会使得整个元素都变得模糊,无法生成我们想要的毛玻璃效果。

使用半透明背景

最基本最简单的方式,使用半透明背景,如下图所示:

image.png

基础代码:

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
<!DOCTYPE html>
<title>毛玻璃效果</title>
<body>
<div class="background-box">
<div class="txt-box">
文字内容, 毛玻璃效果
</div>
</div>
</body>
<style>
.background-box {
width: 800px;
height: 600px;
background: url("https://cdn.pixabay.com/photo/2021/07/14/09/14/siberian-cat-6465485_960_720.jpg") no-repeat;
background-size: 100% 100%;

display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}

.txt-box {
width: 600px;
height: 400px;
/*关键代码*/
background: hsla(0,0%,100%,.3);

display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
</style>
</html>

通过调整半透明颜色调整透明度,动画效果如下所示:

f63f8b1a-82fc-4cfc-b514-c817852658ef.gif

但是这种效果并不理想,透明度高的时候文字不易阅读,透明度太低视觉效果不好。

半透明

我们使用伪元素在原文字区域下方生成一个同样大小的半透明区域背景,来看下效果:

image.png

1
2
3
4
5
6
7
8
9
10
.txt-box::before {
z-index: -1;/*将背景设置于文字之下*/
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba(255, 0, 0, .5);
}

然后我们将外层的背景图片加载到伪元素上:(为了便于区分,我们给伪元素添加了一层边框)

image.png

然后我们对伪元素添加模糊效果:

image.png

实际上,这时已经是非常好的毛玻璃效果了。

通过学习《CSS Secret》书籍,其中阐述到这种效果,作者仍然不满意毛玻璃的边框区域,仍然有改进空间。

后续通过margin: -30px扩大伪元素模糊范围,以及文字元素overflow: hidden切割超出部分,从而实现完美的毛玻璃效果,如下所示。

image.png

在学习过程中遇到一个新的属性:background-attachment,官方链接:(https://developer.mozilla.org/zh-CN/docs/Web/CSS/background-attachment)

background-attachment CSS 属性决定背景图像的位置是在视口内固定,或者随着包含它的区块滚动。

可取值:fixed, scroll, local

总结

  1. 当背景图不适合background-attachment: fixed时,需要使用简单的给文本元素添加透明度即可,虽然不完美。

  2. 当背景图可以使用background-attachment: fixed,此时可以使用比较复杂的方法:

    1
    2
    3
    4
    1. 在文字与背景之间,添加一层元素(伪元素或者DOM元素)
    2. 该层元素与文字元素大小相同,且其背景与最外层背景完全重合。
    3. 对该层背景设置filter: blur(*)模糊效果
    4. 通过模糊层元素外边距与文字元素的`overflow: hidden`生成边界清晰的毛玻璃边界

这是我参与8月更文挑战的第12天,活动详情查看:8月更文挑战

CSS渐变色逃不过的一个函数就是linear-gradient

MDN官方文档:https://developer.mozilla.org/zh-CN/docs/Web/CSS/gradient/linear-gradient()

linear-gradient定义为:

1
2
3
4
5
6
7
8
9
10
linear-gradient(
[ <angle> | to <side-or-corner> ,]? <color-stop-list> )
\---------------------------------/ \----------------------------/
Definition of the gradient line List of color stops

where <side-or-corner> = [ left | right ] || [ top | bottom ]
and <color-stop-list> = [ <linear-color-stop> [, <color-hint>? ]? ]#, <linear-color-stop>
and <linear-color-stop> = <color> [ <color-stop-length> ]?
and <color-stop-length> = [ <percentage> | <length> ]{1,2}
and <color-hint> = [ <percentage> | <length> ]

这个含义看上去很复杂。

比如包括angle渐变方向,是从上到下渐变,还是从左向右渐变,还是以一定角度渐变。

color-stop-list定义的是渐变节点。

我们来看几个例子。

基础框架代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>

<body>
<div class="my-box"></div>
</body>

<style>
.my-box {
width: 300px;
height: 300px;
/* background: linear-gradient(#fb3, #58a); */
}
</style>

</html>
  1. 仅使用颜色:
1
background: linear-gradient(#fb3, #58a);

效果如下:

image.png

  1. 指定渐变节点

    如下代码所示,我们定义了4个渐变节点,其中第二个与第三个渐变节点的颜色相同。

1
background: linear-gradient(#fb3 10%, #58a 50%, #58a 60%, red 80%);

展示效果如下所示:

image.png

  1. 指定渐变方向

    我们添加渐变方向,先来尝试一下角度问题:

    1
    background: linear-gradient(45deg, #fb3 10%, #58a 50%, #58a 60%, red 80%);

    展示效果如下所示,可以看到其中的45deg是左下角开始的。但究竟是从哪里转动的45deg呢?

    image.png

    尝试一下其他的角度,或者我们做一下动画看看:

    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
    <!DOCTYPE html>

    <body>
    <div class="my-box"></div>
    </body>

    <style>
    .my-box {
    width: 300px;
    height: 300px;
    background: linear-gradient(0deg, #fb3 10%, #58a 50%, #58a 60%, red 80%);
    animation: change 3s infinite;
    }
    @keyframes change {
    from {
    background: linear-gradient(0deg, #fb3 10%, #58a 50%, #58a 60%, red 80%);
    }
    25% {
    background: linear-gradient(11.25deg, #fb3 10%, #58a 50%, #58a 60%, red 80%);
    }
    50% {
    background: linear-gradient(22.5deg, #fb3 10%, #58a 50%, #58a 60%, red 80%);
    }
    75% {
    background: linear-gradient(33.75deg, #fb3 10%, #58a 50%, #58a 60%, red 80%);
    }
    to {
    background: linear-gradient(45deg, #fb3 10%, #58a 50%, #58a 60%, red 80%);
    }
    }
    </style>

    </html>

    动画效果如下:

    499de5d0-e2f0-452d-bc47-96dca17e8b38.gif

    可以看到其转换方向从是“从下到上”的方向开始,大约是以组件中心为圆心顺时针转动45deg

    利用linear-gradient的特性可以做很多有意思的背景色或样式,如条纹等等。《CSS揭秘》中详细阐述了如何使用该属性做条纹以及做更复杂的背景图案。

这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战

问题起源

最近在做的一个网站的登录页面,本来设计好好的,时间测试的时候却发现了一个比较严重的问题。

如下图所示,因为Chrome的用户名与密码输入提示,导致输入框变了颜色。与设计颜色完全不一样了。怎么办呢?

image.png

image.png

方案查找

不知道怎么解决,先去搜索吧~

以关键字“input 关闭输入提示”进行搜索,查找到一些解决方案。

一些相关文章:

  1. 关于浏览器自动展示用户名、密码等输入框的解决办法
  2. 点击密码input框禁止浏览器弹出已经记录的账号密码

文章中提出了多种实现方式,其中包括:

  1. autocomplete="off",尝试了一下,无效,仍然变色
  2. 使用js在加载或者onload时进行重置操作,未尝试,将问题复杂化了
  3. 使用<form>标签和<input type=”password”/>来兼容Chrome与Safari,仍然太复杂,不好不好

最后,在我学习的项目vue-element-admin中找到了一种比较好的纯CSS的解决方案。

其中的几个自己不会用,不常用的关键点

关键点1:cater-color

cater-color:定义插入光标(caret)的颜色

文档链接:https://developer.mozilla.org/zh-CN/docs/Web/CSS/caret-color

关键点2:@supports

@supports: 指定依赖于浏览器中的一个或多个特定的CSS功能的支持声明

文档链接:https://developer.mozilla.org/zh-CN/docs/Web/CSS/@supports

方案选择

最终的实现代码:代码主要来源与修改花裤衩vue-element-admin项目中的登录页。

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
<style lang="scss">
/* 修复input 背景不协调 和光标变色 */
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */

$bg:#fff;
$light_gray:#fff;
$cursor: #999999;

@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
.el-input input {
color: $cursor;
}
}

/* reset element-ui css */
.el-input {
display: inline-block;
width: 100%;
border-radius: 6px;

input {
background: transparent;
border: 1px solid #E5E5E5;;
-webkit-appearance: none;
border-radius: 6px;
color: $light_gray;
height: 47px;
caret-color: $cursor;

&:-webkit-autofill {
box-shadow: 0 0 0px 1000px $bg inset !important;
-webkit-text-fill-color: $cursor !important;
}
}

input:focus {
border-color: #555555;
}
}
</style>

这是我参与8月更文挑战的第10天,活动详情查看:8月更文挑战

双重边框甚至多重边框是设计上的常用样式,如何用代码实现呢?

层叠DOM元素

最原始的方法自然是可以通过层叠不同背景色的DOM元素来实现,通过调整DOM元素的大小和背景色从而实现设置多重边界的目的。

比如要实现两个边框,则需要至少编写两个包裹的DOM,内层DOM设置border为第一层边框,内层覆盖外层后,外层漏出的部分显示为外层边框。

实现效果如下图所示:为了说明层叠DOM效果,添加了一个动画效果。

147ee4ba-3fce-4f02-8a44-ffb733f61f5a.gif

具体实现代码如下所示:

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
<!DOCTYPE html>

<body>
<div class="outer">
<div class="inner"></div>
</div>
</body>
<style>
body {
background: black;
}

.outer {
background: lightblue;
width: 300px;
height: 300px;
margin: 50px;
position: relative;
}

.inner {
background: lightcoral;
width: 200px;
height: 200px;
border: 25px solid lightgreen;
position: absolute;
top: 25px;
left: 500px;
animation: move 10s infinite;
}

@keyframes move {
from {
left: 500px;
}
to {
left: 25px;
}
}

</style>

</html>

但是这种方法繁琐,且如果更多边框的话会造成DOM过多,代码一点儿都不优雅,不好,不好!

CSS除border外其他实现边框的方式

CSS除border外是否还有其他实现边框的方式呢?有的。

outline

该属性为设置DOM的轮廓。

MDN官方文档:https://developer.mozilla.org/zh-CN/docs/Web/CSS/outline

outline是outline-coloroutline-styleoutline-width的简写。

border 和 outline 很类似,但有如下区别:

  • outline不占据空间,绘制于元素内容周围。
  • 根据规范,outline通常是矩形,但也可以是非矩形的。

box-shadow

box-shadow是添加阴影的,那么怎么用它设置边框呢?

该属性可设置的值包括阴影的X轴偏移量、Y轴偏移量、模糊半径、扩散半径和颜色,X轴偏移量、Y轴偏移量、模糊半径均设置为0,仅设置扩散半径与颜色,则效果与边框是一样的。

而且,根据《CSS Secret》中阐述,box-shadow支持逗号分隔,如:box-shadow: 0 0 0 10px #655, 0 0 0 15px deeppink;,

如何可以很方便的给元素添加多重边框。

如下图为一个复杂的多重边框图案,但是其代码十分简单

image.png

实现代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>

<body>
<div class="my-transparent">11111</div>
</body>
<style>
body {
background: black;
}
.my-transparent {
margin-left: 100px;
margin-top: 100px;

border-radius: 10px;
background: white;
width: 300px;
height: 300px;
/*核心代码*/
border: 10px solid hsla(0,0%,100%,.5);
outline: 10px solid deeppink;
box-shadow: 0 0 0 20px white, 0 0 0 30px green, 0 0 0 40px yellow, 0 0 0 50px blue;
}
</style>
</html>

这是我参与8月更文挑战的第9天,活动详情查看:8月更文挑战

生产实际中产长有这样的设计:点击某横向栏的某个标签或链接,页面滚动到指定版块位置。如下图所示,为京东首页的一个设计,右侧栏列出的页面版块,随着用户点击,可以快递到达页面指定位置,从而实现快速定位。

image.png

那么如何实现这种设计呢?

本文介绍两种实现方式:

使用scrollIntoView函数

见字知义,scrollIntoView()方法会使元素对用户可见。其官方文档链接:https://developer.mozilla.org/zh-CN/docs/Web/API/Element/scrollIntoView

使用实例效果:

d804d6c4-b009-42df-bdc3-00e96f56f88b.gif

实现代码:

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
55
56
57
58
59
60
61
62
63
<!DOCTYPE html>
<script type="text/javascript">
function myscroll() {
// console.log("dd");
document.getElementById('e8').scrollIntoView();
}
</script>
<body>
<div class="fixed">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<input type="button" onclick="myscroll()" value="8" />
<div>9</div>
<div>10</div>
<div>11</div>
<div>12</div>
<div>13</div>
<div>14</div>
</div>
<div>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div id="e8">8</div>
<div>9</div>
<div>10</div>
<div>11</div>
<div>12</div>
<div>13</div>
<div>14</div>
</div>

</body>
<style>
body {
font-size: 200px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.fixed {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 15px;
position:fixed;
top: 0;
right: 20%;
}
</style>

</html>

放在VUE中,实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
....
<div ref="element" @click.native="scroll">

</div>
....
</template>
<script>
...
methods: {
scroll() {
this.$refs.element.$el.scrollIntoView()
}
}
...
</script>

使用Window.scrollTo函数

window.scrollTo函数官方文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/scrollTo

使用这个函数可以实现或平滑,或瞬时的滚动效果,且可以灵活的控制滚动距离。

1
2
3
4
5
// 设置滚动行为改为平滑的滚动
window.scrollTo({
top: 1000,
behavior: "smooth"
});

近期在VUE中实现的一个例子如下所示:

1
2
3
4
5
6
7
8
9
10
11
elementToView(ref) {
let y = this.$refs[ref].$el.offsetTop
/*注释部分代码实现的是由于点击组件可能在滚动过程中position变为fixed而引起的组件距离顶部的变化而做的动态修改*/
// if (this.fixed || ref === 'overview') {
// y = y - this.tabRowHeight
// } else {
// y = y - this.tabRowHeight * 2
// }
// 关键在这里
window.scrollTo(0, y)
}

最初实现这个过程中遇到很多问题,还好都解决了,尤其是DOM各个值的含义,检索过程中的文章列在下面:

  1. 令人头疼的clientTop、scrollTop、offsetTop

「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!

问题复现

首先来看一段简单的网页代码,使用min-height控制A区域的最小高度为父节点的50%。

1
2
3
4
5
6
7
8
9
10
11
12
...
<body class="body">
<div class="parent">
<div class="child-a">
A: min-Height: 50%;
</div>
<div class="child-b">
B: flex: 1
</div>
</div>
</body>
...

其相关样式表代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<style>
.body {
height: 300px; /*充满整个屏幕*/
width: 300px;
}

.parent {
min-height: 100%; /*parent充满整个body*/
display: flex;
flex-direction: column;
border: 1px solid black;
}

.child-a {
min-height: 50%; /*期待:A至少能充满半个区域*/
background-color: cornflowerblue;
}

.child-b {
flex: 1; /* 其他B填充除A外parent的剩余空间*/
background-color:bisque;
}

期待效果图如下图,希望通过min-height使得A至少占满50%的空间。

image.png

然而,实际效果图却是下图这样:

image.png

为什么A区域的min-height没有如我们所愿呢?

查找问题

我们试图通过查看min-height的定义来定位问题。

CSS官方文档中,我们查找到min-height定义与解释,其中提到,当其取值为百分比时,其高度是根据父节点(准确的说是包含块)的高度计算的,如果没有明确指定包含块的高度,并且该元素不是绝对定位的,其高度将取决于内容高度

原文如下:

<percentage>

Specifies a percentage for determining the used value. The percentage is calculated with respect to the height of the generated box’s containing block. If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the percentage value is treated as 0 (for min-height) or none (for max-height).

换句话说,当父节点的height未设置,而min-height为百分比取值时,其没有可依赖计算的基础值,因此无法计算其高度。此时按照CSS规范,元素的高度将由内部元素来决定。当 min-height 大于 max-heightheight时,元素的高度会设置为 min-height 的值。

解决问题

1. 给父节点设置height

我们给父节点parent设置height:1px即可。关于heightmin-heightmax-height的优先级,我们文章最后再说。

1
2
3
4
5
6
.parent {
/*新增一行,使得子节点的百分比值可以计算*/
height: 1px;

/*parent原css...*/
}

2. 给父节点外再加一层,并设置最外层display:flex

这一点我不知道原因,只是在查找过程中发现,这样也可以解决问题,所以列在此处,请读者指点

一个可参考的文章:Normalizing Cross-browser Flexbox Bugs

如果发现节点的宽度也受到影响,增加width相关设置调整即可。

1
2
3
4
5
6
.body {
/*新增一行*/
display: flex;

/*原css不变...*/
}

3. 设置为绝对布局:absolute

这一点是根据定义来的,当元素为绝对定位时,百分比的设置min-height也可以生效。(若影响了width,添加相关属性)

虽然这种方式可以解决min-height的问题,但是引入绝对布局,无疑会将页面变复杂。不可取!

1
2
3
4
5
6
7
8
.parent {
position: relative;
...
}

.child-a {
position: absolute;
}

优先级

heightmin-heightmax-height的优先级可以通过简单的代码来测试,结果表明:height<min-height或者 max-height< min-height时,其高度的实际取值为min-height

image.png