按鈕多種的 CSS hover 效果
這篇教學會使用 CSS 的變形、背景色、漸層色、自訂屬性、動畫等多種樣式屬性,實作多種不同類型的按鈕 hover 效果。
快速導覽:
基本 hover 效果
下方列出幾種 CSS hover
的基本效果,這些基本效果通常都使用一兩行程式就能完成,僅需注意如果容器的 box-sizing: border-box
時 padding
無法撐開容器,其他都只是很常見的寫法。
<!-- HTML 程式碼 -->
<div class="btn a">變寬</div>
<div class="btn b">圓角</div>
<div class="btn c">字變大</div>
<div class="btn d">變色</div>
<div class="btn e">陰影</div>
<div class="btn f">位置改變</div>
<div class="btn g">邊框樣式</div>
<div class="btn h">旋轉</div>
<div class="btn i">放大</div>
<!-- CSS 程式碼 -->
<style>
:root {font-size: 20px;} /* 讓之後使用 rem 的參考值 */
.btn {
position: relative; /* 讓元素可使用 top 定位 */
box-sizing: border-box; /* 避免 padding 數值影響寬度 */
top: 0;
width: 150px;
padding: 10px;
margin: 10px;
text-align: center;
font-size: 1rem;
line-height: 2rem;
border: 1px solid #000;
background: #fff;
float: left;
cursor: pointer; /* 手形指標 */
transition: .3s; /* 轉場持續時間 */
}
.a:hover {
width: 170px; /* 寬度變大,搭配縮減左右 margin,避免影響別的元素 */
margin: 10px 0;
}
.b:hover {border-radius: 20px;}
.c:hover {font-size: 40px;} /* 字體變大,但超過範圍的字體仍然會影響寬高 */
.d:hover {background: #f99;}
.e:hover {box-shadow: #0006 5px 5px 10px;}
.f:hover {top: -10px;} /* 往上移動,但如果滑鼠在移動後的空間,會造成閃動的狀況 */
.g:hover {
border-width: 10px; /* 改變邊框寬度,需要搭配縮減 padding 數值才不會影響寬高 */
padding: 1px;
}
.h:hover {transform: rotateZ(-15deg);}
.i:hover {transform: scale(1.15);}
</style>
使用虛擬元素的 hover 效果
下方列出幾種使用 CSS 虛擬元素選擇器所設計的 hover
效果,這些效果通常都是讓虛擬元素的位置或尺寸發生變化,進而產生不同顏色背景或造型的效果。
<!-- HTML 程式碼 -->
<div class="btn a">顏色左側展開</div>
<div class="btn b">顏色下方展開</div>
<div class="btn c" text="下方展開雙色字"></div>
<div class="btn d" text="斜向展開雙色字"></div>
<div class="btn e">部分顯露</div>
<div class="btn f">圓形背景移動</div>
<div class="btn g">底線左側展開</div>
<div class="btn h">底線中間內縮</div>
<div class="btn i">底線中間展開</div>
<div class="btn j">出現粗底線</div>
<!-- CSS 程式碼 -->
<style>
:root {font-size: 20px;}
.btn {
position: relative; /* 讓虛擬元素定位參考 */
box-sizing: border-box; /* 避免 padding 影響寬度 */
width: 200px;
padding: 10px;
margin: 10px;
text-align: center;
font-size: 1rem;
line-height: 2rem;
border: 1px solid #000;
float: left;
cursor: pointer; /* 手形指標 */
transition: .3s;
}
/* 虛擬元素共用設定,後續會按照需求覆蓋樣式調整 */
.btn::before, .btn::after {
position: absolute; /* 絕對定位 */
box-sizing: border-box; /* 避免 padding 影響寬度 */
content: "";
top: 0;
left: 0;
width: 100%; /* 尺寸和父元素相同 */
height: 100%;
z-index: -1;
transition: .3s;
}
/* 顏色左側展開,運用定位和寬度 */
.a::before {background: #fff;}
.a::after {
background: #f90;
width: 0;
}
.a:hover::after {width: 100%;}
/* 顏色下方展開,運用定位和高度 */
.b::before {background: #fff; }
.b::after {
background: #f90;
top: auto;
bottom: 0;
height: 0;
}
.b:hover::after {height: 100%;}
/* 下方展開雙色字,使用元素屬性替代文字,搭配 clip-path 裁切產生雙色效果 */
.c::before, .c::after {
font-size: 1rem;
line-height: 2rem;
content: attr(text);
}
.c::before {position: relative;} /* 改讓虛擬元素撐開內容 */
.c::after {
padding: 10px;
color: #fff;
background: #f90;
clip-path: polygon(0 100%, 100% 100%, 100% 100%, 0 100%);
}
.c:hover::after {
clip-path: polygon(0 50%, 100% 50%, 100% 100%, 0 100%);
}
/* 斜向展開雙色字,使用元素屬性替代文字,搭配 clip-path 裁切產生雙色效果 */
.d::before, .d::after {
font-size: 1rem;
line-height: 2rem;
content: attr(text);
}
.d::before {position: relative;} /* 改讓虛擬元素撐開內容 */
.d::after {
padding: 10px;
color: #fff;
background: #f90;
clip-path: polygon(0 100%, 100% 100%, 100% 100%, 0 100%);
}
.d:hover::after {
clip-path: polygon(0 0%, 100% 100%, 100% 100%, 0 100%);
}
/* 部分顯露,運用定位,讓虛擬元素移動到不同的位置 */
.e {background: #fff;}
.e::before, .e::after {
background: #f90;
}
.e:hover::before {
top: -10px;
left: -10px;
}
.e:hover::after {
top: 9px;
left: 9px;
}
/* 圓形背景移動,運用定位搭配元素本身的 overflow:hidden,讓虛擬元素移動到不同的位置 */
.f{overflow: hidden;}
.f::before {
border-radius: 0 20% 20% 0 / 0 50% 50% 0;
background: #f90;
left: -100%;
}
.f::after {
left: 100%;
background: #f90;
border-radius: 20% 0 0 20% / 50% 0 0 50%;
}
.f:hover::before {left: -85%;}
.f:hover::after {left: 85%;}
/* 底線左側展開,將虛擬元素定位到底線位置模擬底線,改變寬度展開,注意寬度要扣除 padding 數值 */
.g{
box-sizing: padding-box;
padding: 10px 20px;
width: max-content;
border: none;
}
.g::before {
width: 0;
height: 5px;
top: auto;
bottom: 15%;
left: 20px;
background: #f90;
}
.g:hover::before {width: calc(100% - 40px);}
/* 底線中間內縮,將虛擬元素定位到底線位置模擬底線,改變寬度產生內縮效果,注意寬度要扣除 padding 數值 */
.h{
box-sizing: padding-box;
padding: 10px 20px;
width: max-content;
border: none;
}
.h::before, .h::after {
width: 0;
height: 5px;
top: auto;
bottom: 15%;
background: #f90;
}
.h::before{left: 20px;}
.h::after{
left: auto;
right: 20px;
}
.h:hover::before {width: calc(50% - 20px);}
.h:hover::after {width: calc(50% - 20px); }
/* 底線中間展開,將虛擬元素定位到底線位置模擬底線,改變寬度產生展開效果,注意寬度要扣除 padding 數值 */
.i{
box-sizing: padding-box;
padding: 10px 20px;
width: max-content;
border: none;
}
.i::before, .i::after {
width: 0;
height: 5px;
top: auto;
bottom: 15%;
background: #f90;
}
.i::before{
left: auto;
right: 50%;
}
.i::after{left: 50%;}
.i:hover::before {width: calc(50% - 20px);}
.i:hover::after {width: calc(50% - 20px);}
/* 出現粗底線,將虛擬元素定位到底線位置模擬底線,改變高度產生粗底線效果,注意寬度要扣除 padding 數值 */
.j{
box-sizing: padding-box;
padding: 10px 20px;
width: max-content;
border: none;
}
.j::before {
width: calc(100% - 40px);
height: 0;
top: auto;
bottom: 15%;
left: 20px;
background: #f90;
}
.j:hover::before{height: 8px;}
</style>
使用漸層色的 hover 效果
使用漸層色需要搭配「自訂元素 @property
」,並額外設定 transition
才能讓漸層色具有轉場的補間動畫,下方範例會呈現使用漸層色的 hover
效果。
<!-- HTML 程式碼 -->
<div class="btn a">漸層色變化</div>
<div class="btn b">漸層色上下移動</div>
<div class="btn c">漸層色左右移動</div>
<div class="btn d">漸層色斜向移動</div>
<div class="btn e">漸層色旋轉</div>
<div class="btn f">漸層色旋轉變色</div>
<!-- CSS 程式碼 -->
<style>
:root {font-size: 20px;}
.btn {
position: relative;
box-sizing: border-box;
width: 200px;
padding: 10px;
margin: 10px;
text-align: center;
font-size: 1rem;
line-height: 2rem;
border: 1px solid #000;
float: left;
cursor: pointer;
}
/* 漸層色變化,單純改變漸層色的顏色 */
@property --a1 {
syntax: "<color>";
inherits: true;
initial-value: red;
}
@property --a2 {
syntax: "<color>";
inherits: true;
initial-value: white;
}
.a {
background: linear-gradient(var(--a1), var(--a2));
transition: --a1 .5s, --a2 .5s;
}
.a:hover {
--a1: yellow;
--a2: orange;
}
/* 漸層色上下移動,改變漸層色中兩種顏色交會的位置 */
@property --b1 {
syntax: "<percentage>";
inherits: true;
initial-value: 0%;
}
@property --b2 {
syntax: "<percentage>";
inherits: true;
initial-value: 0%;
}
.b {
background: linear-gradient(to top, #09c var(--b1), #fff var(--b2));
transition: .5s, --b1 .5s, --b2 .5s;
}
.b:hover {
color: #fff;
--b1: 100%;
--b2: 100%;
}
/* 漸層色左右移動,改變漸層色中兩種顏色交會的位置 */
@property --c1 {
syntax: "<percentage>";
inherits: true;
initial-value: 0%;
}
@property --c2 {
syntax: "<percentage>";
inherits: true;
initial-value: 0%;
}
.c {
background: linear-gradient(to right, #09c var(--c1), #fff var(--c2));
transition: .5s, --c1 .5s, --c2 .5s;
}
.c:hover {
color: #fff;
--c1: 100%;
--c2: 100%;
}
/* 漸層色斜向移動,改變漸層色中的角度,搭配兩種顏色交會的位置 */
@property --d1 {
syntax: "<percentage>";
inherits: true;
initial-value: 0%;
}
@property --d2 {
syntax: "<percentage>";
inherits: true;
initial-value: 0%;
}
.d {
background: linear-gradient(30deg, #09c var(--d1), #fff var(--d2));
transition: .5s, --d1 .5s, --d2 .5s;
}
.d:hover {
color: #fff;
--d1: 100%;
--d2: 100%;
}
/* 漸層色旋轉,改變漸層色中的角度 */
@property --e {
syntax: "<angle>";
inherits: true;
initial-value: 0deg;
}
.e {
background: linear-gradient(var(--e), #fa0 50%, #fff 50%);
transition: .5s, --e .5s;
}
.e:hover {
--e: 180deg;
}
/* 漸層色旋轉變色,搭配漸層色顏色改變 */
@property --f {
syntax: "<angle>";
inherits: true;
initial-value: 0deg;
}
@property --f1 {
syntax: "<color>";
inherits: true;
initial-value: #fa0;
}
@property --f2 {
syntax: "<color>";
inherits: true;
initial-value: white;
}
.f {
background: linear-gradient(var(--f), var(--f1) 50%, var(--f2) 50%);
transition: .5s, --f .5s, --f1 .5s, --f2 .5s;
}
.f:hover {
color: #fff;
--f: 180deg;
--f1: #09d;
--f2: #000;
}
/* 漸層色圓心放大,使用放射漸層,改變顏色交會位置 */
@property --g1 {
syntax: "<percentage>";
inherits: true;
initial-value: 0%;
}
@property --g2 {
syntax: "<percentage>";
inherits: true;
initial-value: 0%;
}
.g {
background: radial-gradient(circle, #f99 var(--g1), #fff var(--g1));
transition: .5s, --g1 .5s, --g2 .5s;
}
.g:hover {
--g1: 100%;
--g2: 100%;
}
/* 漸層色圓心內縮,使用放射漸層,改變顏色交會位置 */
@property --h1 {
syntax: "<percentage>";
inherits: true;
initial-value: 100%;
}
@property --h2 {
syntax: "<percentage>";
inherits: true;
initial-value: 100%;
}
.h {
background: radial-gradient(circle, #fff var(--h1), #f99 var(--h1));
transition: .5s, --h1 .5s, --h2 .5s;
}
.h:hover {
--h1: 0%;
--h2: 0%;
}
</style>
使用 3D 變形的 hover 效果
3D 變形的 hover
效果會將元素本身當作「攝影機」,將虛擬元素當作「內容主體」,透過設定視角的方式,產生變形的透視感,下方範例會呈現幾種 3D 變形的 hover
效果,特別注意有些 HTML 元素是透過設定屬性值的方式設定內容,如果不希望用這種方式,也可以額外在 div
裡添加子元素取代虛擬元素 ( 做法完全相同 )。
<!-- HTML 程式碼 -->
<div class="btn a" text="上下翻轉"></div>
<div class="btn b" text="左右翻轉"></div>
<div class="btn c" text="背景翻轉變色 1"></div>
<div class="btn d">背景翻轉變色 2</div>
<div class="btn e"><div text-b="翻頁效果" text-a="翻轉囉"></div></div>
<!-- CSS 程式碼 -->
<style>
:root {font-size: 20px;}
.btn {
position: relative; /* 讓虛擬元素定位參考 */
box-sizing: border-box;
width: 200px;
margin: 10px;
text-align: center;
font-size: 1rem;
line-height: 2rem;
float: left;
cursor: pointer;
}
/* 設定元素視角,將其當作攝影機 */
.btn {perspective: 200px;}
/* 虛擬元素共用設定,將虛擬元素當作邊框使用 */
.btn::before, .btn::after {
display: block;
content: "";
box-sizing: border-box;
width: 100%;
padding: 10px;
border: 1px solid #000;
transition: .5s;
}
/* before 虛擬元素取得 HTML 元素屬性內容 */
.btn::before {content: attr(text);}
/* after 虛擬元素作為輔助使用,先隱藏備用 */
.btn::after {
display: none;
position: absolute;
top: 0;
left: 0;
height: 100%;
}
/* 上下翻轉,繞著 X 軸翻轉 */
.a::before {transform: rotateX(0);}
.a:hover::before {transform: rotateX(45deg);}
/* 左右翻轉,繞著 Y 軸翻轉 */
.b::before {transform: rotateY(0);}
.b:hover::before {transform: rotateY(-30deg);}
/* 背景翻轉變色 1,固定 before 不動,翻轉 after 180deg */
.c::before {border: none;}
.c::after {
display: block;
transform: rotateX(0);
z-index: -1;
}
.c:hover::before {color: #fff;}
.c:hover::after {
background: #09c;
transform: rotateX(180deg);
}
/* 背景翻轉變色 2,讓元素本身為內容主體,兩個虛擬元素變成兩種顏色,翻轉時改變 z-index 產生正反面效果 */
.d {padding: 10px;}
.d::before, .d::after {
position: absolute;
content: "";
display: block;
top: 0;
left: 0;
padding: 0;
width: 100%;
height: 100%;
transform: rotateX(0);
z-index: -2;
}
.d::before {background: #fa0;}
.d::after {background: #fff;}
.d:hover::before {
color: #fff;
z-index: -1; /* 翻轉時改變 z-index 避免被遮住 */
}
.d:hover::after, .d:hover::before {
transform: rotateX(180deg);
}
/* 翻頁效果,額外使用一個 div 翻轉兩面 */
.e:before, .e::after {display: none;} /* 隱藏原本的虛擬元素 */
.e div {
transform-style: preserve-3d;
transition: .5s;
}
.e div::before, .e div::after {
position: absolute;
top: 0;
left: 0;
display: block;
content: "";
box-sizing: border-box;
width: 100%;
padding: 10px;
border: 1px solid #000;
background: #fff;
}
.e div::before {
content: attr(text-b);
z-index: 2;
}
.e div::after {
background: #09c;
color: #fff;
content: attr(text-a);
z-index: 1;
transform-origin: 0 0 0;
transform: rotateX(-90deg);
}
.e:hover div {
transform: rotateX(90deg);
}
</style>
使用 CSS 動畫的 hover 效果
如果已經熟悉前面幾種 hover
方式,就可以嘗試用 CSS 動畫組合這些效果,做出更生動有趣的 hover
特效。
<!-- HTML 程式碼 -->
<div class="btn a">縮放晃動</div>
<div class="btn b">左搖右晃</div>
<div class="btn c">不斷變色</div>
<div class="btn d">漸層色不斷變色</div>
<div class="btn e">漸層色角度變換</div>
<div class="btn f">漸層移動</div>
<div class="btn g">邊框環繞</div>
<div class="btn h">波浪背景</div>
<!-- CSS 程式碼 -->
<style>
:root {font-size: 20px;}
.btn {
position: relative; /* 虛擬元素定位 */
box-sizing: border-box;
width: 200px;
padding: 10px;
margin: 10px;
text-align: center;
font-size: 1rem;
line-height: 2rem;
float: left;
cursor: pointer;
border: 1px solid #000;
}
/* 縮放晃動 */
.a:hover {animation: oxxo-a 0.2s infinite alternate;}
@keyframes oxxo-a {
0% {scale: 1;}
100% {scale: 1.1;}
}
/* 左搖右晃 */
.b:hover {animation: oxxo-b 0.2s infinite;}
@keyframes oxxo-b {
0%, 100% {transform: rotateZ(0);}
25% {transform: rotateZ(-5deg);}
75% {transform: rotateZ(5deg);}
}
/* 不斷變色 */
.c {background: #fff;}
.c:hover {animation: oxxo-c 1s infinite alternate;}
@keyframes oxxo-c {
0% {background: #fff;}
20% {background: #f00;}
40% {background: #f90;}
60% {background: #ff0;}
80% {background: #9f0;}
100% {background: #0f0;}
}
/* 漸層色不斷變色,使用自訂屬性 */
@property --d1 {
syntax: "<color>";
inherits: true;
initial-value: #f00;
}
@property --d2 {
syntax: "<color>";
inherits: true;
initial-value: #ff0;
}
.d {background: linear-gradient(30deg, var(--d1), var(--d2));}
.d:hover {animation: oxxo-d .5s infinite alternate;}
@keyframes oxxo-d {
0% {
--d1: #f00;
--d2: #ff0;
}
100% {
--d1: #0cf;
--d2: #fff;
}
}
/* 漸層色角度變換,使用自訂屬性 */
@property --e {
syntax: "<angle>";
inherits: true;
initial-value: 20deg;
}
.e {background: linear-gradient(var(--e), #09c 30%, #fff 30%);}
.e:hover {animation: oxxo-e .5s infinite alternate;}
@keyframes oxxo-e {
0% {--e: 20deg;}
100% {--e: -20deg;}
}
/* 漸層移動,使用自訂屬性 */
@property --f1 {
syntax: "<percentage>";
inherits: true;
initial-value: 0%;
}
@property --f2 {
syntax: "<percentage>";
inherits: true;
initial-value: 10%;
}
@property --f3 {
syntax: "<percentage>";
inherits: true;
initial-value: 20%;
}
.f {background: repeating-linear-gradient(60deg, #fc0 var(--f1), #fc0 var(--f2), #fff var(--f2) , #fff var(--f3));}
.f:hover {animation: oxxo-f .5s infinite forwards linear;}
@keyframes oxxo-f {
0% {
--f1: 0%;
--f2: 10%;
--f3: 20%;
}
100% {
--f1: 20%;
--f2: 30%;
--f3: 40%;
}
}
/* 邊框環繞,使用虛擬元素定位和尺寸 */
.g {border: 5px solid #000;}
.g::before {
position: absolute;
content: "";
display: block;
background: #fff;
z-index: 2;
width: 20px;
height: 5px;
top : -5px;
left: calc(100% - 15px);
}
.g:hover:before {animation: oxxo-g 1s infinite linear; }
@keyframes oxxo-g {
0%, 100% {
width: 20px;
height: 5px;
top : -5px;
left: -5px;
}
30% {
width: 20px;
height: 5px;
top : -5px;
left: calc(100% - 15px);
}
32% {
width: 5px;
height: 5px;
top : -5px;
left: 100%;
}
34% {
width: 5px;
height: 20px;
top : -5px;
left: 100%;
}
50% {
width: 5px;
height: 20px;
top : calc(100% - 15px);
left: 100%;
}
52% {
width: 5px;
height: 5px;
top : 100%;
left: 100%;
}
54% {
width: 20px;
height: 5px;
top : 100%;
left: calc(100% - 15px);
}
80% {
width: 20px;
height: 5px;
top : 100%;
left: -5px;
}
82% {
width: 5px;
height: 5px;
top : 100%;
left: -5px;
}
84% {
width: 5px;
height: 20px;
top : calc(100% - 15px);
left: -5px;
}
}
/* 波浪背景,使用 clip-path */
.h::before {
position: absolute;
content: "";
top: 0;
left: 0;
width: 100%;
height: 100%;
display: block;
background: #0cf;
clip-path: polygon(0% 55%,
5% 59.88%,
10% 64.05%,
15% 66.96%,
20% 68.27%,
25% 67.50%,
30% 64.28%,
35% 58.77%,
40% 51.23%,
45% 43.72%,
50% 40.95%,
55% 42.50%,
60% 45.72%,
65% 51.23%,
70% 58.77%,
75% 64.28%,
80% 67.50%,
85% 68.27%,
90% 66.96%,
95% 64.05%,
100% 59.88%,
100% 100%,
0 100%);
z-index: -1;
}
.h:hover:before {animation: oxxo-h 1s infinite linear alternate;}
@keyframes oxxo-h {
0% {clip-path: polygon(0% 55%,
5% 59.88%,
10% 64.05%,
15% 66.96%,
20% 68.27%,
25% 67.50%,
30% 64.28%,
35% 58.77%,
40% 51.23%,
45% 43.72%,
50% 40.95%,
55% 42.50%,
60% 45.72%,
65% 51.23%,
70% 58.77%,
75% 64.28%,
80% 67.50%,
85% 68.27%,
90% 66.96%,
95% 64.05%,
100% 59.88%,
100% 100%,
0 100%);
}
100% {clip-path: polygon(
0% 68.27%,
5% 67.50%,
10% 64.28%,
15% 58.77%,
20% 51.23%,
25% 43.72%,
30% 40.95%,
35% 42.50%,
40% 45.72%,
45% 51.23%,
50% 58.77%,
55% 64.28%,
60% 67.50%,
65% 68.27%,
70% 66.96%,
75% 64.05%,
80% 62.88%,
85% 59.88%,
90% 55%,
95% 52.05%,
100% 50.96%,
100% 100%,
0 100%);
}
}
</style>
小結
其實只要將上述的各種特效排列組合,或者使用自己喜歡的效果,就能作出千變萬化的按鈕 hover 效果囉。
意見回饋
如果有任何建議或問題,可傳送「意見表單」給我,謝謝~