示:文章尾部有全部源碼,大家可以CTRL + C直接拿走,不用謝我;當然,我還是建議大家都能通過學習自己手寫實現。
使用過CSS transition屬性的童鞋們應該都清楚,當元素在過渡開始或者結束時的高度為auto時,動畫是不生效的;那么如何才能實現元素高度的改變動畫效果呢?本篇文章將為大家提供一個基于Vue3的非常簡潔的解決方案。
要實現高度的改變動畫,我們需要在動畫進行之前為元素設置準確的高度。
當元素由可見變為隱藏狀態時,我們需要先獲取元素的計算高度,將其設置到style屬性上,然后執行一個觸發瀏覽器渲染引擎重繪的動作,然后再將高度設置為0,這樣高度的改變動畫就會正常進行。
當元素由隱藏變為可見狀態時,我們需要先將高度設置為auto,然后獲取元素的計算高度,再將高度設置為0,然后執行一個觸發瀏覽器渲染引擎重繪的動作,然后再將高度設置為計算高度,這樣高度的改變動畫就會正常進行。
現在,根據以上實現原理分析,我們創建一個高度的改變動畫通用組件CollapseTransition.vue。該組件非常簡單,僅需30多行代碼。我幾乎每行代碼都有注釋,大家應該能看懂吧?
<template>
<transition v-bind="listeners">
<!-- 當visible的值發生改變時,過渡組件的監聽器就會觸發 -->
<div v-show="visible" class="x-collapse-transition">
<slot />
</div>
</transition>
</template>
<script setup>
defineProps({ visible: Boolean })
const listeners = {
// 元素由隱藏變為可見
onEnter (/** @type {HTMLElement} */ el) {
el.style.height = 'auto' // 將高度設為auto,是為了獲取該元素的計算高度
const endHeight = window.getComputedStyle(el).height // 計算高度
el.style.height = '0px' // 將高度再設置為0
el.offsetHeight // 強制重繪,重繪后再改變高度才會產生動畫
el.style.height = endHeight // 設置為計算高度
},
onAfterEnter (/** @type {HTMLElement} */ el) {
el.style.height = null // 過渡進入之后,將高度恢復為null
},
// 元素由可見變為隱藏
onLeave (/** @type {HTMLElement} */ el) {
el.style.height = window.getComputedStyle(el).height // 計算高度
el.offsetHeight // 強制重繪,重繪后再改變高度才會產生動畫
el.style.height = '0px' // 將高度設置為0
},
onAfterLeave (/** @type {HTMLElement} */ el) {
el.style.height = null // 過渡離開之后,將高度恢復為null
}
}
</script>
<style lang="scss">
.x-collapse-transition {
overflow: hidden;
transition: height .22s ease-in-out;
}
</style>
以上就是實現高度的改變動畫的通用組件源碼,童鞋們理解了嗎?是不是非常簡單?現在,我們實現折疊面板組件。使用過element-ui這樣的UI庫的童鞋們應該都知道,折疊面板是由兩個組件折疊面板Collapse和折疊面板項CollapseItem組合而成;
現在,我們先實現CollapseItem.vue組件。為了節省篇幅,我將源碼中的空行全部去掉了,縮進比較規范,自認為可讀性還行;源碼如下,一共30多行,我直接在源碼中添加了注釋,就不過多解釋了。
<template>
<div :class="[cls, { 'is-active': isActive }]">
<div :class="`${cls}_header`" @click="onToggle">
<div :class="`${cls}_title`">
<slot name="title">{{ title }}</slot>
</div>
<i :class="['x-icon-arrow-right', `${cls}_arrow`, { 'is-active': isActive }]"></i>
</div>
<x-collapse-transition :visible="isActive">
<div :class="`${cls}_content`">
<slot />
</div>
</x-collapse-transition>
</div>
</template>
<script setup>
import { computed, inject } from 'vue'
import { COLLAPSE_INJECT_KEY } from '../../constants' // 當它是個字符串常量就行
import { N, S, B } from '../../types' // N: Number, S: String, B: Boolean
import { genKey } from '../../utils' // 生成唯一性的數值key,之前的文章中有源碼
import XCollapseTransition from './CollapseTransition.vue' // 折疊動畫組件
const props = defineProps({
name: [S, N],
title: S,
disabled: B
})
const collapse = inject(COLLAPSE_INJECT_KEY, '') // 注入折疊面板組件提供的一些屬性和方法
const cls = 'x-collapse-item'
const idKey = computed(() => props.name || genKey()) // 如果沒提供name,我們生成一個key
const isActive = computed(() => collapse.includes(idKey.value)) // 是否展開狀態
function onToggle () { // 內容可見時隱藏,隱藏時可見
collapse.updateModel(idKey.value)
}
</script>
這是CollapseItem.vue組件的樣式。
@import './common/var.scss';
.x-collapse-item {
font-size: 13px;
background-color: #fff;
color: $--color-text-primary;
border-bottom: 1px solid $--border-color-lighter;
&:first-child {
border-top: 1px solid $--border-color-lighter;
}
&_header {
display: flex;
align-items: center;
justify-content: space-between;
height: 48px;
cursor: pointer;
}
&_content {
line-height: 1.8;
padding-bottom: 25px;
}
&_arrow {
margin-right: 8px;
transition: transform .2s;
&.is-active {
transform: rotate(90deg);
}
}
}
現在,我們實現Collapse.vue組件。該組件仍然只有30多行,大家理解起來應該很輕松,我就直接在源碼里添加注釋作為講解了;
<template>
<div class="x-collapse">
<slot />
</div>
</template>
<script setup>
import { provide, reactive, ref, watch } from 'vue'
import { COLLAPSE_INJECT_KEY } from '../../constants' // 一個字符串常量
import { S, B, A } from '../../types' // 參看CollapseItem組件
const props = defineProps({
modelValue: [S, A], // Vue3使用modelValue取代了Vue2中的value
accordion: B // 是否手風琴模式,手風琴模式只能有1個面板項是展開狀態
})
const emit = defineEmits(['update:modelValue', 'change'])
function emitValue (v) {
emit('update:modelValue', v) // 與props.modelValue結合實現雙向數據綁定
emit('change', v)
}
const model = ref(props.modelValue)
watch(() => props.modelValue, v => model.value = v)
provide(COLLAPSE_INJECT_KEY, { // 提供2個方法用于注入子組件,給子組件調用
includes (v) { // 根據面板的key,判斷是否包含該面板項
return props.accordion ? model.value === v : (model.value || []).includes(v)
},
updateModel (v) { // 更新面板項的內容折疊和展開狀態
const { value } = model
if (props.accordion) {
model.value = value === v ? null : v
emitValue(model.value)
} else {
if (!value) model.value = []
const index = model.value.indexOf(v)
index > -1 ? model.value.splice(index, 1) : model.value.push(v)
emitValue(model.value)
}
}
})
</script>
以上就是折疊面板組件的實現。包括折疊動畫組件,一共僅需不到150行代碼,是不是非常簡單?童鞋們都理解了嗎?不管有什么疑問,童鞋們都可以問我。感謝閱讀!
講解CSS過渡和動畫 transition/animation:全方位深入實踐指南
**引言:賦予網頁動態生命力**
CSS過渡(Transition)與動畫(Animation)是現代Web前端開發中不可或缺的設計元素,它們使靜態網頁變得生動活潑,極大地提升了用戶體驗。本文旨在以全面且易于理解的方式講解CSS過渡與動畫的工作原理、應用場景及其具體實現方法,輔以實例代碼,幫助您更好地理解和掌握這一關鍵技術。
---
### **一、CSS過渡基礎概念**
**標題:走進CSS Transition的世界**
**1. 過渡是什么?**
CSS過渡是一種視覺效果,它能夠在CSS屬性值發生變化時平滑地過渡。例如,當鼠標懸停在一個元素上時,其背景顏色可以從白色逐漸過渡到黑色。
**2. 如何定義過渡?**
過渡由三個關鍵部分組成:**觸發器**(何時啟動過渡)、**持續時間**(過渡多久完成)以及**執行方式**(如何變化)。
```css
/* 基礎過渡設置 */
.example {
transition: property duration timing-function delay;
}
/* 示例 */
.box {
width: 100px;
height: 100px;
background-color: red;
transition: background-color 0.5s ease-in-out;
}
```
在此示例中,`.box`元素的背景色會在屬性值改變時,在0.5秒內平滑過渡。
---
### **二、過渡觸發方式**
**標題:觸發動畫的關鍵時刻**
過渡通常在CSS屬性值發生改變時自動觸發,常見的觸發方式有:
- **偽類觸發**(`:hover`, `:focus`, `:active`等)
- **JavaScript操作觸發**(通過更改DOM元素樣式)
```html
<!DOCTYPE html>
<html lang="en">
<head>
<style>
.box {
width: 100px;
height: 100px;
background-color: red;
transition: background-color 0.5s ease-in-out;
}
.box:hover {
background-color: blue;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
</html>
```
在這個例子中,當鼠標懸停在`.box`元素上時,背景顏色會通過過渡效果變藍。
---
### **三、CSS動畫進階詳解**
**標題:構建復雜的動畫效果**
CSS動畫比過渡更為靈活,允許開發者定義一系列關鍵幀(@keyframes),并在指定時間段內逐步變換樣式。
**1. 創建關鍵幀規則**
```css
@keyframes fadeInOut {
0% { opacity: 0; }
50% { opacity: 1; }
100% { opacity: 0; }
}
```
上述代碼定義了一個名為`fadeInOut`的動畫,元素將在動畫期間經歷透明度從0到1再到0的變化。
**2. 應用動畫**
```css
.box {
animation-name: fadeInOut;
animation-duration: 2s;
animation-iteration-count: infinite;
animation-direction: alternate;
}
```
通過`animation-*`系列屬性,我們將`fadeInOut`動畫應用于`.box`元素,使其無限循環交替播放,每次持續2秒。
---
### **四、動畫高級特性**
**標題:探索動畫的更多可能性**
- **動畫填充模式**(animation-fill-mode)控制動畫結束后元素的樣式狀態。
- **動畫延時**(animation-delay)決定動畫何時開始。
- **動畫播放次數**(animation-iteration-count)可設置動畫循環次數,甚至使用`infinite`無限循環。
- **動畫方向**(animation-direction)影響動畫是否逆序播放。
---
### **五、綜合案例分析**
**標題:實際項目中的CSS過渡與動畫運用**
此處可以結合實際項目需求,給出一個或多個包含復雜過渡和動畫交互的HTML+CSS示例,比如響應式導航菜單的展開收起動畫、輪播圖切換過渡效果等,以增強文章的實用性。
---
**結語:**
熟練掌握CSS過渡和動畫,能讓您的網頁設計更具表現力和吸引力。無論是微小的UI細節還是復雜的交互場景,善用過渡和動畫都能有效提升用戶體驗。記住,適時適度的動態效果才是錦上添花,過度則可能適得其反。希望通過這篇文章,您能夠洞悉CSS過渡與動畫的奧秘,并在實踐中游刃有余地運用這些強大的工具。
天我們學習的內容有:過渡,動畫,轉換,伸縮盒子。
可以說今天學習的內容都是重量級的大佬,學好了,使用css3做出酷炫的效果 So Easy!~~
1.過渡
在css3中,有一個屬性可以設置過渡效果。
它就是transition,所謂的過渡效果,指的就是以動畫的形式慢慢演化樣式屬性變化的過程。
A.案例:通過transition設置焦點過渡效果
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>div{width: 200px;height: 200px;margin:200px;background: url(girl.jpg);border-radius:50%;transition:all 1s linear 0.3s;cursor: pointer;}div:hover{box-shadow: 0px 0px 20px blue;}</style></head><body><div></div></body></html>
注意頁面中的代碼:
第一,我們給div添加了一個hover偽類樣式,當我們鼠標懸停在div上方的時候,會給div盒子添加一個藍色的盒子陰影。
第二,我們給div盒子添加了一個transition樣式,設置的值為:all 1s linear 0.3s;
這四個數據分別對應
transition-property(需要過渡的屬性):如果設置為all表示所有樣式屬性都需要過渡。
transition-duration(過渡的時間):以秒作為單位,設置過渡的時間
transition-timing-function(過渡的方式):常用的有linear(勻速),ease(先慢后快),ease-in,ease-out,ease-in-out等
transition-delay(延遲的時間):以秒作為單位進行延遲,延遲之后開始進行過渡效果。
所以,我們通過transition這個復合屬性設置的過渡效果為:
all:需要過渡所有的屬性
1s:過渡的時間為1秒
linear:勻速過渡
0.3s:在延遲0.3秒之后開始過渡動畫。
如果大家理解了上面的描述,那么也就不難理解咱們鼠標放到div上之后,為啥會慢慢出現藍色的光暈了,就是因為咱們添加了過渡,所以,慢慢的就會給盒子添加陰影效果。
2.動畫:
在學習完了過渡之后,發現咱們可以使用transition去以動畫的形式展示樣式的改變以及變化的過程,這可以幫助我們來實現一些過渡的動畫。
但是,有的時候,我們的需求會更加的復雜,要求會更加的多變,那么,transition可能就無法滿足我們的需要了,我們需要有更加炫酷,復雜的效果呈現。
那么,動畫animation就可以滿足我們的需要。
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>@keyframes moveAndChange{0%{left:0px;top:0px;}25%{left:200px;top:200px;background:green;border-radius: 0;}50%{left:400px;top:200px;background:blue;border-radius: 50%;}75%{left:400px;top:0px;background:#ccc;border-radius: 0;}100%{left:0px;top:0px;background:red;border-radius: 50%;}}div{margin:200px;width: 200px;height: 200px;position: absolute;background:red;border-radius:50%;animation: moveAndChange 5s linear 0.5s infinite normal;}</style></head><body><div></div></body></html>
代碼效果如下:
同樣,讓我們來關注編寫的代碼:
1.在樣式中,首先我們使用@keyframes 來定義了一個復雜的動畫,在css3中,新增了@keyframes可以來幫助我們添加動畫。代碼如下:
/*動畫的名字叫做moveAndChange*/
@keyframes moveAndChange{
/*動畫最初的時候,將left設置為0px,top設置為0px*/
0%{
left:0px;
top:0px;
}
/*當動畫進行到25%的時候,使用動畫將left過渡到200px,top過渡到200px,
背景顏色過渡為綠色,圓角過渡為0(無圓角)*/
25%{
left:200px;
top:200px;
background:green;
border-radius: 0;
}
/*當動畫進行到50%的時候,使用動畫將left過渡到400px,top過渡到200px,
背景顏色過渡為藍色,圓角過渡為50%(正圓)*/
50%{
left:400px;
top:200px;
background:blue;
border-radius: 50%;
}
/*當動畫進行到75%的時候,使用動畫將left過渡到400px,top過渡到0,
背景顏色過渡為灰色,圓角過渡為0(無圓角)*/
75%{
left:400px;
top:0px;
background:#ccc;
border-radius: 0;
}
/*當動畫結束的時候,使用動畫將left過渡到0x,top過渡到0px,
背景顏色過渡為紅色,圓角過渡為50%(正圓)*/
100%{
left:0px;
top:0px;
background:red;
border-radius: 50%;
}
}
這是一個比較復雜的動畫效果,可以發現,它通過百分比的形式將一個完整的動畫拆分成了5個部分,每個部分都有不同的樣式效果,而當我們采用該動畫的元素就會按照設置的順序和樣式效果進行動畫的過渡和展示。
2.上面我們只是通過@keyframes創建了一個動畫,我們還需要通過特定的語法來使用這個動畫。
就是下面這句代碼了:
animation: moveAndChange 5s linear 0.5s infinite normal;
它是一個復合屬性,設置了6個值,分別對應:
animation-name(設置動畫的名稱):用來設置動畫的名字,我們這里寫的是moveAndChange ,也就是說我們就是要使用我們剛剛創建的動畫。
animation-duration(設置整個動畫的時間):以秒作為單位,我們這里寫的是5s,表示整個動畫的時間為5秒
animation-timing-function(設置播放動畫的方式):播放動畫的方式,常用的有linear(勻速),ease(先慢后快),ease-in,ease-out,ease-in-out等,我們使用的是linear勻速播放動畫。
animation-delay(設置動畫的延遲):以秒作為單位,我們寫的是0.5s,表示延遲0.5秒之后開始播放動畫。
animation-iteration-count(設置動畫播放的次數):播放動畫的次數,我們這里寫的是infinite ,表示動畫將會被播放無限次,如果寫數字,那么就會播放數字對應的次數。
animation-direction(設置是否反向播放動畫):我們寫的是normal,表示正常播放動畫,如果寫的是
alternate則表示要反向播放動畫,大家也可以自己試一試這個效果。
最終,我們通過@keyframes創建動畫,通過animation設置動畫,成功完成了這個復雜的動畫效果。
3.轉換
在css3中,我們通過transform屬性可以設置元素的轉換效果,具體的效果如下:
A.平移
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>body{background:pink;}div{width: 200px;height: 200px;position: absolute;background: green;left:0px;top:0px;transform: translate(300px,300px);}</style></head><body><div></div></body></html>
代碼效果如下:
如上圖所示,本來div盒子的位置是left:0,top:0;
但是我們通過transform: translate(300px,300px);將盒子進行了偏移,所以,盒子的位置發生了改變。
B.旋轉
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>body {background: pink;}div {width: 200px;height: 200px;margin: 200px;position: absolute;background: green;left: 0px;top: 0px;transform: rotate(45deg);}</style></head><body><div></div></body></html>
代碼效果如下:
如上圖所示,本來div盒子應該是四四方方的。
但是,經過我們的代碼transform: rotate(45deg); //deg為單位,表示度數。
進行了45度的旋轉之后,呈現出來的就是一個菱形的盒子了,旋轉的正方向為順時針,負方向為逆時針。
C.縮放
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>body {background: pink;}div {width: 200px;height: 200px;margin: 200px;position: absolute;background: green;left: 0px;top: 0px;transform: scale(0.5,0.25);}</style></head><body><div></div></body></html>
代碼效果如下:
如上圖所示,本來盒子的寬高為200*200,而我們通過transform: scale(0.5,0.25);進行的縮放
scale的第一個參數為0.5,表示橫向縮小為0.5倍
scale的第二個參數為0.25,表示縱向縮小為0.25倍。
scale的參數如果為1,則表示不進行任何縮放,小于1就是做縮小,而大于1表示做放大。
小結:transform轉換中其實還包含了skew(傾斜),matrix(矩陣轉換),相對來說用到的不是特別多,所以在本文中我們便不再做介紹。
4.flex布局
Flex布局,可以簡便、完整、響應式地實現各種頁面布局。
Flex是Flexible Box的縮寫,翻譯成中文就是“彈性盒子”,用來為盒裝模型提供最大的靈活性。任何一個容器都可以指定為Flex布局。
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>div{box-sizing: border-box;}.parent {width: 600px;height: 200px;margin: 100px;position: absolute;background: green;left: 0px;top: 0px;display: flex;justify-content: flex-start}.parent div{width: 20%;border:1px solid #ccc;background:pink;}</style></head><body><div><div>1</div><div>2</div><div>3</div><div>4</div></div></body></html>
代碼效果如下:
如圖所示,咱們通過display:flex將.parent元素設置為了flex盒子,那么子元素將會按照justify-content設置的方式進行元素的排列,目前看來,和我們沒有設置flex盒子的效果是一致的。
接下來我們更改一下,將justify-content設置為flex-end,效果如下圖所示:
所以我們就應該發現,flex-start是讓所有的子元素從父元素的左側開始排列
而flex-end是讓所有的子元素從元素的右側開始排列。
我們再來更改一下,將justify-content設置為center,效果如下圖所示:
更厲害了,子元素在父盒子的中央位置排列顯示了。
然后,我們再將justify-content設置為space-around,效果如下圖所示:
它是平均分配的形式為每一個子元素設置了間距,但是看起來有點變扭。
所以我們推薦將justify-content設置為space-between,效果如下圖:
我們還可以通過flex-wrap來設置子元素是否換行顯示,以及flex-direction設置子元素排列的順序。
這兩個屬性可以設置的值如下:
flex-wrap: nowrap;//不換行,會自動收縮
flex-wrap: warp;//換行,會自動收縮
flex-wrap: warp-reverse;//反轉,從默認的從上到下排列反轉為從下到上。
flex-direction:row; //從左至右一行一行進行子元素的排列
flex-direction:column; //從上到下一列一列進行子元素的排列
flex-direction:row-reverse; //從右至左一行一行進行子元素的排列
flex-direction:column-reverse; //從下到上一列一列進行子元素的排列
案例代碼如下:
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>div{box-sizing: border-box;}.parent {width: 600px;height: 200px;margin: 100px;position: absolute;background: green;left: 0px;top: 0px;display: flex;justify-content: space-between;flex-wrap: nowrap;flex-direction: row-reverse;}.parent div{width: 20%;border:1px solid #ccc;background:pink;}</style></head><body><div><div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div></div></body></html>
我們設置了flex-wrap: nowrap;(不換行,壓縮所有的子元素在一行中顯示),以及flex-direction: row-reverse;(反向排列)
代碼效果如下:
如果設置為flex-wrap: warp(換行顯示無法在一行顯示的子元素),則效果如下:
如果將flex-direction: column;,則會縱向排列元素,效果如下圖:
除了上面的這些給伸縮盒子父元素設置的樣式之外,我們還可以可以伸縮盒子的子元素設置flex屬性,用來設置平均分配整個父盒子的空間。
代碼如下:
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>div{box-sizing: border-box;}.parent {width: 600px;height: 200px;margin: 100px;position: absolute;background: green;left: 0px;top: 0px;display: flex;justify-content: space-between;}.parent div{flex:1;width: 20%;border:1px solid #ccc;background:pink;}</style></head><body><div><div>1</div><div>2</div><div>3</div><div>4</div></div></body></html>
效果如下:
如上圖所示,每個盒子平均分配了父盒子的空間,原本寬度為20%,現在被拉伸了。
除此之外,咱們還可以使用flex屬性進行進一步的設置,代碼如下:
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>div{box-sizing: border-box;}.parent {width: 600px;height: 200px;margin: 100px;position: absolute;background: green;left: 0px;top: 0px;display: flex;justify-content: space-between;}.parent div:nth-of-type(1){flex:1;border:1px solid #ccc;background:red;}.parent div:nth-of-type(2){flex:2;border:1px solid #ccc;background:green;}.parent div:nth-of-type(3){flex:2;border:1px solid #ccc;background:blue;}.parent div:nth-of-type(4){flex:1;border:1px solid #ccc;background:pink;}</style></head><body><div><div>1</div><div>2</div><div>3</div><div>4</div></div></body></html>
效果如下圖:
我們分別給四個子盒子設置了flex:1 , flex:2, flex:2 ,flex:1.
這是什么意思呢?
四個flex加起來一共是6.那么第一個盒子就占據整個父盒子的1/6寬度。
同理,另外三個盒子分別占據2/6,2/6,1/6的寬度,所以就形成了我們現在看到的效果。
原文來源于:黑馬程序員社區
學習資源:
想學習css,可以關注:黑馬程序員頭條號,后臺回復:css
*請認真填寫需求信息,我們會在24小時內與您取得聯系。