1、 选用合适的鼠标光标——cursor:pointer
主要通过 cursor属性来指定光标类型
- 比如
pointer光标可以提示某个元素是可点击的 - 而 help 光标用来暗示这里有提示信息。
- 某些开发者还会利用 wait 或progress 光标来替代(或配合)一个加载提示
1.1 提示禁用状态——cursor:not-allowed
<!DOCTYPE html>
<html>
<head>
<style>
:disabled,
[disabled],
[aria-disabled="true"] {
cursor: not-allowed;
}
</style>
</head>
<body>
<button>Button</button>
<button disabled>Disabled button</button>
</body>
</html>
1.2 隐藏鼠标光标——cursor: none
当你观看视频的时候,往往会不自觉地把鼠标移到屏幕的最右侧, 进行隐藏。
可以直接使用 cursor: none
2. 扩大元素的可点击区域
2.1 设置透明边框
设置一圈透明边框,因为鼠标对元素边框的交互也会触发鼠标事件,这一点是描边和投影所不及的
<!DOCTYPE html>
<html>
<head>
<style>
button {
padding: 0.3em 0.5em;
border: 10px solid transparent; /*把元素的可点击区域在四个方向上各向外扩大 10px*/
border-radius: 50%;
background: #58a;
background-clip: padding-box; /*把背景限制在原本的区域之内*/
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.3) inset; /*用内嵌投影来模拟出一道(实色)边框*/
color: white;
font: bold 150%/1 sans-serif;
cursor: pointer;
}
</style>
</head>
<body>
<button>+</button>
</body>
</html>
2.2 伪元素
伪元素同样可以代表其宿主元素来响应鼠标交互
基于伪元素的方案极为灵活,可以把元素可点击区域设置为任何想要的尺寸、位置或形状,甚至可以脱离元素原有的位置
在按钮的上层覆盖一层透明的伪元素,并让伪元素在四个方向上都比宿主元素大出 10px
<!DOCTYPE html>
<html>
<head>
<style>
button {
position: relative;
padding: 0.3em 0.5em;
background: #58a;
border-radius: 50%;
border: 1px solid rgba(0, 0, 0, 0.3);
box-shadow: 0 0.1em 0.2em -0.05em rgba(0, 0, 0, 0.5);
color: white;
font: bold 150%/1 sans-serif;
cursor: pointer;
}
button:before {
content: "";
position: absolute;
top: -10px;
right: -10px;
bottom: -10px;
left: -10px;
}
</style>
</head>
<body>
<button>+</button>
</body>
</html>
3. 自定义复选框样式
:checked伪类只在复选框被勾选时才会匹配
- 为
<label>元素添加生成性内容(伪元素),并基于复选框的状态来为其设置样式。 - 然后,就可以把真正的复选框隐藏起来(但不能把它从 tab 键切换焦点的队列中完全删除),
- 再把生成性内容美化一番,用来顶替原来的复选框
<!DOCTYPE html>
<html>
<head>
<style>
/*把原来的复选框以一种不损失可访问性的方式隐藏起来*/
/*不能使用 display: none*/
input[type="checkbox"] {
position: absolute;
clip: rect(0, 0, 0, 0);
}
/*要生成一个伪元素,作为美化版的复选框*/
input[type="checkbox"] + label::before {
content: "\a0";
display: inline-block;
vertical-align: 0.2em;
width: 0.8em;
height: 0.8em;
margin-right: 0.2em;
border-radius: 0.2em;
background: silver;
text-indent: 0.15em;
line-height: 0.65;
}
/*要给复选框的勾选状态加上不同的样式。*/
input[type="checkbox"]:checked + label::before {
content: "\2713";
background: yellowgreen;
}
/*聚焦或禁用时改变它的样式*/
input[type="checkbox"]:focus + label::before {
box-shadow: 0 0 0.1em 0.1em #58a;
}
input[type="checkbox"]:disabled + label::before {
background: gray;
box-shadow: none;
color: #555;
cursor: not-allowed;
}
body {
font: 150%/1.6 sans-serif;
}
</style>
</head>
<body>
<input type="checkbox" id="awesome" autofocus />
<label for="awesome">Awesome!</label>
<br />
<input type="checkbox" id="awesome2" checked />
<label for="awesome2">Awesome!</label>
<br />
<input type="checkbox" id="awesome3" disabled />
<label for="awesome3">Awesome!</label>
<br />
<input type="checkbox" id="awesome4" checked disabled />
<label for="awesome4">Awesome!</label>
</body>
</html>
3.1 开关式按钮样式
开关式按钮与复选框的行为十分相似,可以用来切换某个选项的开关状态:启用时,它是被按下的状态;停用时,它就是浮起的状态。
只需要把 label 设置为按钮的样式即可,并不需要用到伪元素
<!DOCTYPE html>
<html>
<head>
<style>
/*把原来的复选框以一种不损失可访问性的方式隐藏起来*/
input[type="checkbox"] {
position: absolute;
clip: rect(0, 0, 0, 0);
}
/*把 label 设置为按钮的样式*/
input[type="checkbox"] + label {
display: inline-block;
padding: 0.35em 0.5em 0.2em;
background: #ccc;
background-image: linear-gradient(#ddd, #bbb);
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 0.3em;
box-shadow: 0 1px white inset;
text-align: center;
text-shadow: 0 1px 1px white;
cursor: pointer;
}
input[type="checkbox"]:checked + label,
input[type="checkbox"]:active + label {
box-shadow: 0.04em 0.1em 0.2em rgba(0, 0, 0, 0.6) inset;
border-color: rgba(0, 0, 0, 0.3);
background: #bbb;
}
body {
font: 150%/1.6 sans-serif;
}
</style>
</head>
<body>
<input type="checkbox" id="awesome" autofocus />
<label for="awesome">Awesome!</label>
<input type="checkbox" id="awesome2" checked />
<label for="awesome2">Awesome!</label>
</body>
</html>
4. 通过阴影来调暗背景
通过一层半透明的遮罩层来把后面的一切整体调暗,以便凸显某个特定的 UI 元素,引导用户关注。比如,弹出层
4.1 增加一个额外的 HTML 元素
最常见的实现方法就是增加一个额外的 HTML 元素用于遮挡背景,然后为它添加如下样式:
<!DOCTYPE html>
<html>
<head>
<style>
.overlay {
/* 用于遮挡背景,遮罩层负责把这个关键元素背后的所有东西调暗*/
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba(0, 0, 0, 0.8);
}
/*指定一个更高的 z-index,以便绘制在遮罩层的上层*/
.lightbox {
/* 需要吸引用户注意的元素 */
position: absolute;
z-index: 1;
/* [其余样式] */
}
</style>
</head>
<body>
<div class="overlay">
<img src="http://csssecrets.io/images/adamcatlace.jpg" class="lightbox" />
</div>
<p>
Bacon ipsum dolor amet consectetur short loin ut tri-tip alcatra ground
round jowl beef meatloaf in pork. Elit chicken ea spare ribs. Shank
andouille ex boudin picanha turkey esse. Do doner fugiat tongue.
</p>
<p>
Pork chop ad cow spare ribs capicola ball tip alcatra cillum magna short
ribs tempor. Pork loin do sint magna ea pork belly duis. Shoulder ullamco
chicken porchetta, ham anim veniam venison. Fugiat tenderloin venison,
turducken non pork chop ribeye enim. Beef turkey salami, ipsum prosciutto
commodo cupidatat. Tri-tip ham hock non brisket pig cupim commodo ball tip
nulla turkey kielbasa corned beef flank. Hamburger pariatur ham, porchetta
cupidatat sirloin pork loin quis nulla culpa tail esse.
</p>
</body>
</html>
4.2 伪元素方案
用伪元素来消除额外的 HTML 元素
- 把遮罩层交给这个元素自己的
::before伪元素来实现 - 给伪元素设置 z-index: -1; 就可以让它出现在元素的背后
- 当使用弹出层自己的伪元素来实现遮罩层时,就无法判断用户到底是点了弹出层还是遮罩层
4.3 box-shadow 方案
利用 box-shadow 的扩张参数可以把元素的投影向各个方向延伸放大。具体做法就是生成一个巨大的投影,不偏移也不模糊
box-shadow: 0 0 0 999px rgba(0,0,0,.8);
1vmax 相当于 1vw 和 1vh 两者中的较大值。100vw 等于整个视口的宽度,100vh 就是视口的高度
<!DOCTYPE html>
<html>
<head>
<style>
.lightbox {
position: fixed; /*遮罩层的尺寸是与视口相关,而不是与页面相关*/
top: 50%;
left: 50%;
margin: -200px;
box-shadow: 0 0 0 50vmax rgba(0, 0, 0, 0.8);
}
</style>
</head>
<body>
<img src="http://csssecrets.io/images/adamcatlace.jpg" class="lightbox" />
<p>
Bacon ipsum dolor amet consectetur short loin ut tri-tip alcatra ground
round jowl beef meatloaf in pork. Elit chicken ea spare ribs. Shank
andouille ex boudin picanha turkey esse. Do doner fugiat tongue.
</p>
<p>
Pork chop ad cow spare ribs capicola ball tip alcatra cillum magna short
ribs tempor. Pork loin do sint magna ea pork belly duis. Shoulder ullamco
chicken porchetta, ham anim veniam venison. Fugiat tenderloin venison,
turducken non pork chop ribeye enim. Beef turkey salami, ipsum prosciutto
commodo cupidatat. Tri-tip ham hock non brisket pig cupim commodo ball tip
nulla turkey kielbasa corned beef flank. Hamburger pariatur ham, porchetta
cupidatat sirloin pork loin quis nulla culpa tail esse.
</p>
</body>
</html>
4.4 backdrop 方案
HTML元素<dialog> 会自带一个遮罩层。借助 ::backdrop 伪元素,这个原生的遮罩层也是可以设置样式的
<!DOCTYPE html>
<html>
<head>
<style>
dialog::backdrop {
background: rgba(0, 0, 0, 0.8);
}
</style>
</head>
<body>
<button onclick="document.querySelector('#modal').showModal()">
Click me
</button>
<dialog id="modal">
O HAI!
<button onclick="this.parentNode.close()">Close</button>
</dialog>
</body>
</html>
5. 通过模糊来调暗背景
把关键元素之外的一切都模糊掉,用来配合(或取代)阴影效果。
需要用一个额外的 HTML 元素来实现:把页面上除了关键元素之外的一切都包裹起来,这样就可以只对这个容器元素进行模糊处理了
<!DOCTYPE html>
<html>
<head>
<style>
/*CSS 滤镜是可以设置动画的*/
main {
transition: 0.6s;
background: white;
}
/*每当弹出一个对话框,都需要给 <main> 元素增加一个类,以便对它应用模糊滤镜*/
main.de-emphasized {
-webkit-filter: blur(3px);
filter: blur(3px);
}
dialog {
position: fixed;
top: 50%;
left: 50%;
z-index: 1;
width: 10em;
padding: 2em;
margin: -5em;
border: 1px solid silver;
border-radius: 0.5em;
box-shadow: 0 0.2em 0.5em rgba(0, 0, 0, 0.5),
0 0 0 100vmax rgba(0, 0, 0, 0.2);
}
dialog:not([open]) {
display: none;
}
body {
font: 150%/1.6 Baskerville, Palatino, serif;
}
</style>
</head>
<body>
<dialog>O HAI, I’m a dialog. Click on me to dismiss.</dialog>
<main>
<button>Show dialog</button>
<p>
Bacon ipsum dolor sit amet consectetur short loin ut tri-tip alcatra
ground round jowl beef meatloaf in pork. Elit chicken ea spare ribs.
Shank andouille ex boudin picanha turkey esse. Do doner fugiat tongue.
</p>
<p>
Pork chop ad cow spare ribs capicola ball tip alcatra cillum magna short
ribs tempor. Pork loin do sint magna ea pork belly duis. Shoulder
ullamco chicken porchetta, ham anim veniam venison. Fugiat tenderloin
venison, turducken non pork chop ribeye enim. Beef turkey salami, ipsum
prosciutto commodo cupidatat. Tri-tip ham hock non brisket pig cupim
commodo ball tip nulla turkey kielbasa corned beef flank. Hamburger
pariatur ham, porchetta cupidatat sirloin pork loin quis nulla culpa
tail esse.
</p>
</main>
</body>
<script>
function $(sel) {
return document.querySelector(sel);
}
var dialog = $("dialog");
var main = $("main");
$("button").onclick = function() {
dialog.setAttribute("open", "");
main.classList.add("de-emphasized");
};
dialog.onclick = function() {
if (dialog.close) {
dialog.close();
} else {
dialog.removeAttribute("open");
}
main.classList.remove("de-emphasized");
};
</script>
</html>
6. 元素内容可滚动的提示
需要两层背景:一层用来生成阴影提示,另一层就是一个用来遮挡阴影的白色矩形,其作用类似于遮罩层。
- 生成阴影的那层背景将具有默认的 background-attachment 值(scroll),因为我们希望它总是保持在原位。
- 我们把遮罩背景的 background-attachment 属性设置为 local,这样它就会在我们滚动到最顶部时盖住阴影,在向下滚动时跟着滚动,从而露出阴影。
<!DOCTYPE html>
<html>
<head>
<style>
ul {
display: inline-block;
/*高度略短于内容,从而让其内容可以滚动*/
overflow: auto;
width: 7.2em;
height: 7em;
border: 1px solid silver;
padding: 0.3em 0.5em;
list-style: none;
margin-top: 2em;
font: 100 200%/1.6 "Frutiger LT Std", sans-serif;
background: linear-gradient(white 15px, hsla(0, 0%, 100%, 0)) 0 0 / 100%
50px,
radial-gradient(at top, rgba(0, 0, 0, 0.2), transparent 70%) 0 0 /
100% 15px,
linear-gradient(to top, white 15px, hsla(0, 0%, 100%, 0)) bottom /
100% 50px,
radial-gradient(at bottom, rgba(0, 0, 0, 0.2), transparent 70%) bottom /
100% 15px;
background-repeat: no-repeat;
/*让遮罩背景跟着元素的内容一起滚动local,从而露出阴影滚动提示*/
background-attachment: local, scroll, local, scroll;
margin-top: 30px;
}
</style>
</head>
<body>
<ul>
<li>Ada Catlace</li>
<li>Alan Purring</li>
<li>Schrödingcat</li>
<li>Tim Purrners-Lee</li>
<li>Webkitty</li>
<li>Json</li>
<li>Void</li>
<li>Neko</li>
<li>NaN</li>
<li>Cat5</li>
<li>Vector</li>
</ul>
</body>
</html>
7. 交互式的图片对比控件
把两张图片叠加起来,允许用户拖动分割条来控制这两张图片的显露区域
7.1 CSS resize 方案
图片对比滑动控件基本上可以理解为两层结构:
- 下层是一张固定的图片;
- 上层的图片则可以在水平方向上调整大小,从而或多或少地显露出下层图片
对
<textarea>元素来说,resize属性被默认设置为 both,这让它在水平和垂直方向上都是可以调整大小的。但resize属性实际上适用于任何元素,只要它的 overflow 属性不是 visible。
一般resize 默认都是设置为 none 的,即禁用调整大小;resize属性值还有horizontal 和 vertical,它们可以限制元素调整大小的方向
<!DOCTYPE html>
<html>
<head>
<style>
.image-slider {
position: relative;
display: inline-block;
}
.image-slider > div {
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 50%; /* 初始宽度 */
max-width: 100%; /*<div> 的宽度不能拉伸到超过图片宽度*/
overflow: hidden; /* 让它可以裁切图片 */
resize: horizontal;
}
/*调节手柄不容易辨认,把一个假的调节手柄覆盖在它上面*/
.image-slider > div:before {
content: "";
position: absolute;
right: 0;
bottom: 0;
width: 12px;
height: 12px;
padding: 5px;
background: linear-gradient(-45deg, white 50%, transparent 0);
background-clip: content-box;
cursor: ew-resize;
-webkit-filter: drop-shadow(0 0 2px black);
filter: drop-shadow(0 0 2px black);
}
.image-slider img {
width: 300px;
height: 270px;
display: block;
user-select: none;
/*即使用户在没有点中调节手柄的情况下拖动鼠标,也不会误选图片*/
}
</style>
</head>
<body>
<div class="image-slider">
<!--用一个 <div> 作为图片元素的容器,再对这个容器应用 resize属性--->
<div>
<img
src="http://csssecrets.io/images/adamcatlace-before.jpg"
alt="Before"
/>
</div>
<img src="http://csssecrets.io/images/tiger.jpg" />
</div>
</body>
</html>
7.2 HTML范围输入控件方案 <input type="range" />
将一个原生的滑块控件(HTML 范围输入控件)覆盖在图片上,用它来控制上层图片的伸缩
<!DOCTYPE html>
<html>
<head>
<style>
.image-slider {
position: relative;
display: inline-block;
}
.image-slider > div {
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 50%;
overflow: hidden;
}
.image-slider img {
display: block;
user-select: none;
width: 300px;
height: 270px;
}
/*定位到图片之上,并让它与图片一样宽*/
.image-slider input {
position: absolute;
left: 0;
bottom: 10px;
width: 100%;
margin: 0;
}
</style>
</head>
<body>
<div class="image-slider">
<div class="img-box">
<img
src="http://csssecrets.io/images/adamcatlace-before.jpg"
alt="Before"
/>
</div>
<img src="http://csssecrets.io/images/tiger.jpg" />
<input type="range" class="control" />
</div>
</body>
<script>
function $$(selector, context) {
context = context || document;
var elements = context.querySelectorAll(selector);
return Array.prototype.slice.call(elements);
}
window.onload = function() {
$$(".control")[0].oninput = function() {
$$(".img-box")[0].style.width = this.value + "%";
};
};
</script>
</html>