目錄
- 理解 box-shadow
- 在陰影坐標(biāo)中運(yùn)用三角函數(shù)
- 三角函數(shù)
- 如何在 CSS 中使用三角函數(shù) sin/cos
- 控制顏色及初始方向
- 控制顏色
- 在 css-doodle 中使用
- 總結(jié)
理解 box-shadow
首先,回顧一下box-shadow這個(gè)屬性?;緦傩杂梅ň褪墙o元素創(chuàng)造一層陰影。
再簡(jiǎn)單提一下,本文會(huì)用到的關(guān)于陰影的第一個(gè)技巧:
使用陰影復(fù)制圖像/投影圖像
當(dāng) box-shadow 的第三、第四個(gè)參數(shù)模糊半徑和擴(kuò)張半徑都為 0 的時(shí)候,我們可以得到一個(gè)和元素大小一樣的陰影:
div {
width: 80px;
height: 80px;
border: 1px solid #333;
box-sizing: border-box;
box-shadow: 80px 80px 0 0 #000;
}
得到如下結(jié)果:
陰影可以是多重的
第二個(gè)技巧則是,box-shadow是允許多重陰影的,并且他們的坐標(biāo)是可以完全掌控的。
是的,我們可以像下面這樣給一個(gè)元素定義多重陰影,并且利用陰影的第一、第二個(gè)參數(shù)控制它相對(duì)于元素的坐標(biāo):
div {
width: 80px;
height: 80px;
border: 1px solid #333;
box-sizing: border-box;
box-shadow:
80px 80px 0 0 #000,
70px 70px 0 0 #000,
...
60px 60px 0 0 #000;
}
在陰影坐標(biāo)中運(yùn)用三角函數(shù)
繼續(xù)。接下來(lái),我們嘗試在陰影的坐標(biāo)中引入三角函數(shù)。
為啥是三角函數(shù),不是圓的標(biāo)準(zhǔn)方程或者橢圓的標(biāo)準(zhǔn)方程或者其他圖形函數(shù)呢?當(dāng)然也是可以的,只是這里借助三角函數(shù)的cos或sin可以實(shí)現(xiàn)直接使用 CSS 實(shí)現(xiàn)起來(lái)很困難的曲線。
帶著疑問(wèn),先繼續(xù)向下,假設(shè)我們要實(shí)現(xiàn)這樣一條曲線:
使用 CSS 的話,有什么辦法呢?
可能的一些辦法是clip-path,或者一些奇技淫巧,使用text-decoration里的波浪下劃線wavy,或者是使用漸變疊加。
當(dāng)然,還有一種辦法是本文將提到的使用box-shadow及 三角函數(shù)。
三角函數(shù)
咳咳,簡(jiǎn)單回顧下三角函數(shù)里面的 sin、cos 曲線圖像變換,還沒有全部還給老師。
如果我們有一個(gè) 1x1 的 div,它的多重陰影,能夠按照像正弦/余弦函數(shù)的圖像一樣進(jìn)行排布,連起來(lái)不就是一條曲線嗎?
如何在 CSS 中使用三角函數(shù) sin/cos
想法不錯(cuò),但是 CSS 本身并沒有提供三角函數(shù)。這里,我們需要借助 Sass 來(lái)在 CSS 中實(shí)現(xiàn)簡(jiǎn)單的三角函數(shù)。
還好,已經(jīng)有前人幫忙把這個(gè)工作做完了:
- trigonometry in sass
- 在Sass中實(shí)現(xiàn)三角函數(shù)計(jì)算
簡(jiǎn)單而言,就是借助三角函數(shù)的泰勒展開式,使用 Sass 函數(shù)模擬實(shí)現(xiàn)三角函數(shù)的 sin()、cos()、tan():
由于展開式是無(wú)限長(zhǎng)的,使用 Sass 函數(shù)模擬時(shí),不可能得到一個(gè)非常精確的值,但是在日常作圖下已經(jīng)完全夠用了,以下是使用 Sass 函數(shù)模擬實(shí)現(xiàn)三角函數(shù)的 sin()、cos()、tan():
@function fact($number) {
$value: 1;
@if $number>0 {
@for $i from 1 through $number {
$value: $value * $i;
}
}
@return $value;
}
@function pow($number, $exp) {
$value: 1;
@if $exp>0 {
@for $i from 1 through $exp {
$value: $value * $number;
}
}
@else if $exp 0 {
@for $i from 1 through -$exp {
$value: $value / $number;
}
}
@return $value;
}
@function rad($angle) {
$unit: unit($angle);
$unitless: $angle / ($angle * 0 + 1);
@if $unit==deg {
$unitless: $unitless / 180 * pi();
}
@return $unitless;
}
@function pi() {
@return 3.14159265359;
}
@function sin($angle) {
$sin: 0;
$angle: rad($angle);
// Iterate a bunch of times.
@for $i from 0 through 20 {
$sin: $sin + pow(-1, $i) * pow($angle, (2 * $i + 1)) / fact(2 * $i + 1);
}
@return $sin;
}
@function cos($angle) {
$cos: 0;
$angle: rad($angle);
// Iterate a bunch of times.
@for $i from 0 through 20 {
$cos: $cos + pow(-1, $i) * pow($angle, 2 * $i) / fact(2 * $i);
}
@return $cos;
}
@function tan($angle) {
@return sin($angle) / cos($angle);
}
由于上面最終計(jì)算 sin、cos 泰勒展開的時(shí)候,只使用了 20 層循環(huán),所以當(dāng)傳入的值太大的時(shí)候,則會(huì)產(chǎn)生較大誤差。經(jīng)測(cè)試,傳入數(shù)值在 [-20, 20] 以內(nèi),精度還是非常高的。
而以 sin 函數(shù)為例,x 取值在 [-π, π] 之間,已經(jīng)能覆蓋所有 sin(x) 的取值范圍,所以 [-20, 20] 這個(gè)范圍是完全夠用的,我們只需要盡量讓傳入的 x 值落在這個(gè)區(qū)域范圍內(nèi)即不會(huì)產(chǎn)生太大誤差。
好,鋪墊了那么多,接下來(lái)使用上述的 sin 函數(shù)試一下,假設(shè)我們有這樣一個(gè)結(jié)構(gòu):
div {
width: 1px;
height: 1px;
background: #000;
border-radius: 50%;
}
我們?cè)俳柚?Sass 實(shí)現(xiàn)一個(gè) 50 層的循環(huán),當(dāng)然其中陰影的 x 坐標(biāo)使用了 sin 函數(shù):
@function shadowSet($vx, $vy) {
$shadow : 0 0 0 0 #000;
@for $i from 0 through 50 {
$x: sin($i / 8) * $vx;
$y: $i * $vy;
$shadow: $shadow, #{$x} #{$y} 0 0 rgba(0, 0, 0, 1);
}
@return $shadow;
}
div {
width: 1px;
height: 1px;
background: #000;
border-radius: 50%;
box-shadow: shadowSet(4px, 1px);
}
上面sin($i / 8),這里除以 8 是為了讓整個(gè)sin(x) 傳入的作用域的取值范圍為 [0, 6.25],當(dāng)而 sin(x) 的作用域?yàn)?[0,2π] 時(shí)剛好可以畫一條完整的單次曲線。這個(gè) 8 是可以根據(jù)循環(huán)的次數(shù)不同而進(jìn)行調(diào)整的。
實(shí)際,我們得到的box-shadow如下:
{
box-shadow:
0 0 0 0 black, 0.4986989335px 1px 0 0 black, 0.989615837px 2px 0 0 black,
1.4650901163px 3px 0 0 black, 1.9177021544px 4px 0 0 black, 2.3403890918px 5px 0 0 black,
2.7265550401px 6px 0 0 black, 3.0701740089px 7px 0 0 black, 3.3658839392px 8px 0 0 black,
3.6090703764px 9px 0 0 black, 3.7959384774px 10px 0 0 black, 3.9235722281px 11px 0 0 black,
3.9899799464px 12px 0 0 black, 3.9941253622px 13px 0 0 black, 3.9359437875px 14px 0 0 black,
3.8163431264px 15px 0 0 black, 3.6371897073px 16px 0 0 black, 3.4012791593px 17px 0 0 black,
3.1122927876px 18px 0 0 black, 2.7747401278px 19px 0 0 black, 2.3938885764px 20px 0 0 black,
1.9756811944px 21px 0 0 black, 1.5266439682px 22px 0 0 black, 1.0537839735px 23px 0 0 black,
0.5644800322px 24px 0 0 black, 0.0663675689px 25px 0 0 black, -0.4327805381px 26px 0 0 black,
-0.9251752496px 27px 0 0 black, -1.4031329108px 28px 0 0 black, -1.8591951521px 29px 0 0 black,
-2.286245275px 30px 0 0 black, -2.677619305px 31px 0 0 black, -3.0272099812px 32px 0 0 black,
-3.3295620582px 33px 0 0 black, -3.5799574329px 34px 0 0 black, -3.7744887692px 35px 0 0 black,
-3.9101204707px 36px 0 0 black, -3.9847360499px 37px 0 0 black, -3.9971711559px 38px 0 0 black,
-3.9472317429px 39px 0 0 black, -3.8356970987px 40px 0 0 black, -3.6643076841px 41px 0 0 black,
-3.4357379737px 42px 0 0 black, -3.1535547213px 43px 0 0 black, -2.8221613023px 44px 0 0 black,
-2.446729px 45px 0 0 black, -2.03311631px 46px 0 0 black, -1.58777752px 47px 0 0 black,
-1.1176619928px 48px 0 0 black, -0.630105724px 49px 0 0 black, -0.1327168662px 50px 0 0 black;
}
實(shí)際得到的圖像如下:
控制顏色及初始方向
看看上面 Sass 實(shí)現(xiàn)的這個(gè)方法@function shadowSet($vx, $vy),其中$vx,$vy用于控制圖像的振幅及松散程度,我們?cè)偬砑右粋€(gè)控制初始方向的$direction,控制陰影層數(shù)的 $count, 控制顏色的 $color:
@function shadowSet($vx, $vy, $direction, $count, $color) {
$shadow : 0 0 0 0 $color;
@for $i from 0 through $count {
$x: sin($i / 8) * $vx * $direction;
$y: $i * $vy;
$shadow: $shadow, #{$x} #{$y} 0 0 $color;
}
@return $shadow;
}
.line {
width: 1px;
height: 1px;
margin: 10vh auto;
background: #000;
border-radius: 50%;
box-shadow: shadowSet(4px, 1px, 1, 50, #000);
}
.reverseline {
width: 1px;
height: 1px;
margin: 10vh auto;
background: #000;
border-radius: 50%;
box-shadow: shadowSet(8px, 2px, -1, 100, red);
}
控制顏色
再進(jìn)一步,我們可以借助 Sass 的各種顏色函數(shù),實(shí)現(xiàn)顏色的變化:
@function shadowSetColor($vx, $vy, $direction, $count, $color) {
$shadow : 0 0 0 0 $color;
@for $i from 0 through $count {
$color: lighten($color, .5);
$x: sin($i / 8) * $vx * $direction;
$y: $i * $vy;
$shadow: $shadow, #{$x} #{$y} 0 0 $color;
}
@return $shadow;
}
.colorline {
width: 5px;
height: 5px;
margin: 10vh auto;
background: green;
border-radius: 50%;
box-shadow: shadowSetColor(8px, 2px, -1, 100, green);
}
上面,借助了lighten這個(gè)函數(shù),通過(guò)改變顏色的亮度值,讓顏色變亮,創(chuàng)建一個(gè)新的顏色。
當(dāng)然,Sass 中還有很多其他顏色函數(shù):
- adjust-hue($color,$degrees):通過(guò)改變一個(gè)顏色的色相值,創(chuàng)建一個(gè)新的顏色;
- lighten($color,$amount):通過(guò)改變顏色的亮度值,讓顏色變亮,創(chuàng)建一個(gè)新的顏色;
- darken($color,$amount):通過(guò)改變顏色的亮度值,讓顏色變暗,創(chuàng)建一個(gè)新的顏色;
- saturate($color,$amount):通過(guò)改變顏色的飽和度值,讓顏色更飽和,從而創(chuàng)建一個(gè)新的顏色
- desaturate($color,$amount):通過(guò)改變顏色的飽和度值,讓顏色更少的飽和,從而創(chuàng)建出一個(gè)新的顏色;
OK,看看這次的效果:
@function fact($number) {
$value: 1;
@if $number>0 {
@for $i from 1 through $number {
$value: $value * $i;
}
}
@return $value;
}
在 css-doodle 中使用
OK,前面所有的鋪墊都是為了在實(shí)際的一些創(chuàng)意想法中去使用它。
在 css-doodle 中,由于是利用 Web Component 特性。在需要三角函數(shù)的時(shí)候,可以直接使用 JavaScript 提供的 Math 函數(shù),會(huì)更加的方便。
Web Components 是一套不同的 Web 技術(shù),允許您創(chuàng)建可重用的定制元素(它們的功能封裝在您的代碼之外)并且在您的web應(yīng)用中使用它們。
袁川老師,也就是 css-doodle 庫(kù)的作者,在他的 Codepen 首頁(yè)背景板中,使用的就是使用上述技巧實(shí)現(xiàn)的一副純 CSS 畫作:
html, body {
height: 100%;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
background: #000;
}
style>
css-doodle {
--color: @p(#010059, #52437b, #ff7a8a, #fcf594)@p([2-9a-d])@lp();
--rule: (
:doodle {
@grid: 8 / 120vmin 80vmin;
max-width: 100vw;
background: linear-gradient(#ff7a8a, #fcf594);
filter: hue-rotate(-22deg);
overflow: hidden;
}
@size: @r(4vmin, 15vmin);
mix-blend-mode: multiply;
transform: translate(@m2(@r(-80%, 100%)));
border-radius: 50%;
--n: @p(-1, 1);
--c: var(--color);
box-shadow: @m100(
calc(@sin(@n() / 10) * 1.8vmin * @var(--n))
calc(@n() * 1vmin) 0
@var(--c)
);
background: @m(@p(0, @ri(500)), (
radial-gradient(var(--color) 50%, transparent 0)
@r(100%) @r(100%) / @r(1px, 3px) @lr()
no-repeat
));
background-color: var(--color);
);
}
/style>
css-doodle use="var(--rule)" click-to-update>/css-doodle>
我也嘗試使用這個(gè)技巧,做了一副
總結(jié)
有幾點(diǎn),有必要提一下的。
1、為什么一定要使用box-shadow,直接堆疊 div 不行么?
可以,使用多重box-shadow只是因?yàn)檫@樣可以更省標(biāo)簽,一個(gè) div 搞定。更甚,愿意折騰,使用多重漸變也是可以的。
2、上述兩個(gè) Demo 都是純 CSS 畫出來(lái)的嗎?
是的。雖然借助了 css-doodle 庫(kù),但是本質(zhì)都是 CSS 代碼,只是這個(gè)庫(kù)封裝好了很多拿來(lái)即用的函數(shù)。css-doodle
3、有什么用?
額,有沒有用是一個(gè)哲學(xué)問(wèn)題。至少我覺得還是挺有意思的。
以上就是如何在CSS中繪制曲線圖形及展示動(dòng)畫的詳細(xì)內(nèi)容,更多關(guān)于在CSS中繪制曲線圖形及展示動(dòng)畫的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
您可能感興趣的文章:- js css3實(shí)現(xiàn)圖片拖拽效果
- 原生js和css實(shí)現(xiàn)圖片輪播效果
- 利用CSS、JavaScript及Ajax實(shí)現(xiàn)圖片預(yù)加載的三大方法
- BootStrap 圖片樣式、輔助類樣式和CSS組件的實(shí)例詳解
- 利用CSS、JavaScript及Ajax實(shí)現(xiàn)圖片預(yù)加載的方法
- 基于cssSlidy.js插件實(shí)現(xiàn)響應(yīng)式手機(jī)圖片輪播效果
- 詳解CSS不定寬溢出文本適配滾動(dòng)
- 詳解盒子端CSS動(dòng)畫性能提升
- 詳解CSS玩轉(zhuǎn)圖片Base64編碼