于 CSS 陰影,之前已經有寫過一篇,box-shadow 與 filter:drop-shadow 詳解及奇技淫巧,介紹了一些關于 box-shadow 的用法。
最近一個新的項目,CSS-Inspiration,挖掘了其他很多有關 CSS 陰影的點子,是之前的文章沒有覆蓋到的新內容,而且有一些很有意思,遂打算再起一篇。
本文的題目是 CSS 陰影技巧與細節。CSS 陰影,卻不一定是 box-shadow 與 filter:drop-shadow,為啥?因為使用其他屬性也可以模擬陰影,而且是各種各樣的陰影。下面且聽我娓娓道來~
單側投影
先說單側投影,關于 box-shadow,大部分時候,我們使用它都是用來生成一個兩側的投影,或者一個四側的投影。如下:
OK,那如果要生成一個單側的投影呢?
我們來看看 box-shadow 的用法定義:
{ box-shadow: none | [inset? && [ <offset-x> <offset-y> <blur-radius>? <spread-radius>? <color>? ] ]#}
以 box-shadow: 1px 2px 3px 4px #333 為例,4 個數值的含義分別是,x 方向偏移值、y 方向偏移值 、模糊半徑、擴張半徑。
這里有一個小技巧,擴張半徑可以為負值。
繼續,如果陰影的模糊半徑,與負的擴張半徑一致,那么我們將看不到任何陰影,因為生成的陰影將被包含在原來的元素之下,除非給它設定一個方向的偏移量。所以這個時候,我們給定一個方向的偏移值,即可實現單側投影:
CodePen Demo — css單側投影(https://codepen.io/Chokcoco/pen/pergRb)
投影背景 / 背景動畫
接著上面的說。
很明顯,0 = -0,所以當 box-shadow 的模糊半徑和擴張半徑都為 0 的時候,我們也可以得到一個和元素大小一樣的陰影,只不過被元素本身遮擋住了,我們嘗試將其偏移出來。
CSS代碼如下:
div { width: 80px; height: 80px; border: 1px solid #333; box-sizing: border-box; box-shadow: 80px 80px 0 0 #000;}
得到如下結果:
有什么用呢?好像沒什么意義啊。
額,確實好像沒什么用。不過我們注意到,box-shadow 是可以設置多層的,也就是多層陰影,而且可以進行過渡變換動畫(補間動畫)。但是 background-image: linear-gradient(),也就是漸變背景是不能進行補間動畫的。
這又扯到哪里去了。好我們回來,利用上面的特性,我們可以利用 box-shadow 實現原本只能利用漸變才能實現的背景圖:
用 box-shadow,實現它的 CSS 代碼如下(可以更簡化):
.shadow { position: relative; width: 250px; height: 250px;}.shadow::before { content: ""; position: absolute; width: 50px; height: 50px; top: -50px; left: -50px; box-shadow: 50px 50px #000, 150px 50px #000, 250px 50px #000, 50px 100px #000, 150px 100px #000, 250px 100px #000, 50px 150px #000, 150px 150px #000, 250px 150px #000, 50px 200px #000, 150px 200px #000, 250px 200px #000, 50px 250px #000, 150px 250px #000, 250px 250px #000;}
用漸變來實現的話,只需要這樣:
.gradient { width: 250px; height: 250px; background-image: linear-gradient(90deg, #000 0%, #000 50%, #fff 50%, #fff 100%); background-size: 100px 100px;}
為什么選擇更為復雜的 box-shadow 呢?因為它可以進行補間動畫,像這樣,這是使用漸變做不到的:
CodePen Demo — box-shadow實現背景動畫(https://codepen.io/Chokcoco/pen/WaBYZL)
當然,這只是個示例 Demo,運用點想象力還有很多有意思的效果,再貼一個:
CodePen Demo — CSS Checker Illusion( By David Khourshid )(https://codepen.io/davidkpiano/pen/LVzxPV)
嗯,很有意思,就是實際用途可能不大。
立體投影
好,我們繼續。下一個主題是立體投影。
這個說法很奇怪,陰影的出現,本就是為了讓原本的元素看起來更加的立體,那這里所謂的立體投影,是個怎么立體法?
這里所謂的立體投影,并不一定是使用了 box-shadow、text-shadow 或者 drop-shadow,而是我們使用其他元素或者屬性模擬元素的陰影。而這樣做的目的,是為了能夠突破 box-shadow 這類元素的一些定位局限。讓陰影的位置、大小、模糊度可以更加的靈活。
OK,讓我們來看看,這樣一個元素,我們希望通過自定義陰影的位置,讓它更加立體:
上圖 div 只是帶了一個非常淺的 bos-shadow ,看上去和立體沒什么關系,接下來,我們通過 div 的偽元素,給它生成一個和原圖邊角形狀類似的圖形,再通過 transform 位移一下,可能是這樣
OK,最后對這個用偽元素生成的元素進行一些虛化效果(filter或者box-shadow都可以),就可以實現一個邊角看起來像被撕開的立體效果:
代碼非常簡單,偽 CSS 代碼示意如下:
div { position: relative; width: 600px; height: 100px; background: hsl(48, 100%, 50%); border-radius: 20px;}div::before { content: ""; position: absolute; top: 50%; left: 5%; right: 5%; bottom: 0; border-radius: 10px; background: hsl(48, 100%, 20%); transform: translate(0, -15%) rotate(-4deg); transform-origin: center center; box-shadow: 0 0 20px 15px hsl(48, 100%, 20%);}
所以總結一下:
還有其他很多場景:
CodePen Demo — 立體投影(https://codepen.io/Chokcoco/pen/LgdRKE?editors=1100)
文字立體投影 / 文字長陰影
上面的立體效果在文字上就完全不適用了,所以對待文字的立體陰影效果,還需要另辟蹊徑。
正常而言,我們使用 text-shadow 來生成文字陰影,像這樣:
<div> Txt Shadow</div>-----div { text-shadow: 6px 6px 3px hsla(14, 100%, 30%, 1);}
嗯,挺好的,就是不夠立體。那么要做到立體文字陰影,最常見的方法就是使用多層文字陰影疊加。
Tips:和 box-shadow 一樣,text-shadow 是可以疊加多層的!但是對于單個元素而言, drop-shadow的話就只能是一層。
好,上面的文字,我們試著疊加個 50 層文字陰影試一下。額,50 層手寫,其實很快的~
好吧,手寫真的太慢了,還容易出錯,所以這里我們需要借助一下 SASS/LESS 幫忙,寫一個生成 50 層陰影的 function 就好,我們每向右和向下偏移 1px,生成一層 text-shadow:
@function makeLongShadow($color) { $val: 0px 0px $color; @for $i from 1 through 50 { $val: #{$val}, #{$i}px #{$i}px #{$color}; } @return $val;} div { text-shadow: makeLongShadow(hsl(14, 100%, 30%));}
上面的 SCSS 代碼。經過編譯后,就會生成如下 CSS:
div { text-shadow: 0px 0px #992400, 1px 1px #992400, 2px 2px #992400, 3px 3px #992400, 4px 4px#992400, 5px 5px #992400, 6px 6px #992400, 7px 7px #992400, 8px 8px #992400, 9px 9px #992400, 10px10px #992400, 11px 11px #992400, 12px 12px #992400, 13px 13px #992400, 14px 14px #992400, 15px15px #992400, 16px 16px #992400, 17px 17px #992400, 18px 18px #992400, 19px 19px #992400, 20px20px #992400, 21px 21px #992400, 22px 22px #992400, 23px 23px #992400, 24px 24px #992400, 25px25px #992400, 26px 26px #992400, 27px 27px #992400, 28px 28px #992400, 29px 29px #992400, 30px30px #992400, 31px 31px #992400, 32px 32px #992400, 33px 33px #992400, 34px 34px #992400, 35px35px #992400, 36px 36px #992400, 37px 37px #992400, 38px 38px #992400, 39px 39px #992400, 40px40px #992400, 41px 41px #992400, 42px 42px #992400, 43px 43px #992400, 44px 44px #992400, 45px45px #992400, 46px 46px #992400, 47px 47px #992400, 48px 48px #992400, 49px 49px #992400, 50px50px #992400;}
看看效果:
額,很不錯,很立體。但是,就是丑,而且說不上來的奇怪。
問題出在哪里呢,陰影其實是存在明暗度和透明度的變化的,所以,對于漸進的每一層文字陰影,明暗度和透明度應該都是不斷變化的。這個需求,SASS 可以很好的實現,下面是兩個 SASS 顏色函數:
關于 SASS 顏色函數,可以看看這里:Sass基礎—顏色函數
我們使用上面兩個 SASS 顏色函數修改一下我們的 CSS 代碼,主要是修改上面的 makeLongShadow function 函數:
@function makelongrightshadow($color) { $val: 0px 0px $color; @for $i from 1 through 50 { $color: fade-out(desaturate($color, 1%), .02); $val: #{$val}, #{$i}px #{$i}px #{$color}; } @return $val;}
好,看看最終效果:
嗯,大功告成,這次順眼了很多~
CodePen Demo — 立體文字陰影(https://codepen.io/Chokcoco/pen/JmgNNa)
當然,使用 CSS 生成立體文字陰影的方法還有很多,下面再貼出一例,使用了透明色疊加底色的多重線性漸變實現的文字立體陰影,感興趣的同學可以去看看具體實現:
線性漸變配合陰影實現條紋立體陰影條紋字(https://codepen.io/Chokcoco/pen/XxQJEB?editors=1100)
長投影
上面提到了通過多層陰影疊加實現文字的立體陰影。運用在 div 這些容器上也是可以的。當然這里還有一種挺有意思的方法。假設我們,有一個矩形元素,希望給他添加一個長投影,像下面這樣:
要生成這種長投影,剛剛說的疊加多層陰影可以,再就是借助元素的兩個偽元素,其實上面的圖是這樣的:
關鍵點在于,我們通過對兩個偽元素的 transform: skew() 變換以及從實色到透明色的背景色變化,實現了長投影的效果:
CodePen Demo — 線性漸變模擬長陰影(https://codepen.io/Chokcoco/pen/qJvVGy)
彩色投影
通常而言,我們生成陰影的方式大多是 box-shadow 、filter: drop-shadow() 、text-shadow 。但是,使用它們生成的陰影通常只能是單色或者同色系的。
你這么說,難道還可以生成漸變色的陰影不成?
額,當然不行。
這個真不行,但是通過巧妙的利用 filter: blur 模糊濾鏡,我們可以假裝生成漸變色或者說是顏色豐富的陰影效果。
當然,關于 CSS 陰影還有很多有意思的技巧和細節,本文限于篇幅不再一一羅列。
寫響應式布局時,發現border所占據空間的問題讓人很頭疼。下面舉例說說遇到的問題和解決方法!
上例中的盒子box1和box2,因為寬度和剛好等于父元素盒子寬度,可以完美的排在同一行。
但我們給box2加一個邊框,就會發現,box2的寬度增加了,box3被擠到了下面一行去。雖然我們只是添加了1px的邊框,但它對布局的影響確實很大。在我們需要使用偽類顯示邊框時,突然出現的邊框常常會對我們的布局造成影響,嚴重拉低體驗。我嘗試了兩個方法消除邊框影響。一是outline代替border來展示邊框
以上的代碼,box2四周也會出現邊框,并且不會布局。但也會看到,box2部分邊的邊框線會被遮住而看不到,所以這種方法有局限性,不是很推薦,用在四周沒有緊貼的其他元素的情況下比較好。第二種方法是給box2設置屬性box-sizing:border-box;
可以看到,這次既顯示了邊框線,有沒有影響我們的布局,除了降低了內容區大小,這個方法接近完美。box-sizing是css3的屬性,它有三個值,content-box,border-box,inherit。content-box,寬度和高度分別應用到元素的內容框,在寬度和高度之外繪制元素的內邊距和邊框。這也是box-sizing的默認值。border-box,為元素設定的寬度和高度決定了元素的邊框盒,就是說,為元素指定的任何內邊距和邊框都將在已設定的寬度和高度內進行繪制,通過從已設定的寬度和高度分別減去邊框和內邊距才能得到內容的寬度和高度。inherit,規定應從父元素繼承 box-sizing 屬性的值。
文:https://blog.csdn.net/TriDiamond6/article/details/105222289
CSS是一個很獨特的語言。看起來非常簡單,但是某種特殊效果看似簡單,實現起來就頗有難度。這篇文章主要是給在學習前端的童鞋分享一些新的CSS技巧,一些在前端教程和培訓課堂中不會講到的知識。第二就是讓還在前端開發這條道路上的童鞋們,重新燃起對前端排版和特效的熱愛和熱情!
1、固定底部內容
這種是一個非常常見的布局方式,但是對于新手來說是比較常見的難題。
這種布局方式在后臺管理系統中比較常見,當我們內容不足瀏覽器窗口高度時,底部內容需要固定在底部。當內容超出了瀏覽器窗口高度,就會隨著內容往后推。
在有CSS3之前,實現這個效果是頗有難度的。瀏覽器窗口高度是會根據不同用戶打開瀏覽器的情況,屏幕大小的差異和瀏覽器的縮放比例而變。我們需要借助JavaScript來實時獲取瀏覽器高度進行運算才能實現。雖然說標題是說“固定”底部,但是我們想要的效果不是position: fixed。使用固定定位,在內容高于窗口高度時,就會擋住我們的內容。
隨著CSS3的來臨,最完美的實現方式是使用Flexbox。實現的關鍵就是使用不太被關注的flex-grow屬性,可以在我們的內容標簽元素(比如div)中使用。在我們下面的例子里使用了main標簽。
我來講解一下實現原理吧。
flew-grow是用來控制一個flex元素相對它同等級flex元素的自身可擴充的空間。如果我們使用flex-grow: 0,那這個flex元素就完全不會擴展了。所以我們需要把頭部和底部之間的內容標簽元素設置為flex-grow: 1或者flex-grow: auto,這樣內容部分就會自動填充滿頭部和底部之外的所有空間。
為了避免底部內容受內容部分擴充空間的影響,我們給footer底部元素flex-shrink: 0屬性。flex-shrink的作用與flex-grow是恰恰相反,用來控制flex元素收縮的空間,這里我們給了flex-shrink: 0就是為了底部footer的大小不受影響。
我們直接上HTML和CSS代碼看看是怎么實現的。
<div id="document">
<nav>
<h1>頭部內容</h1>
</nav>
<main>
<p>可以添加更多內容看看底部的變化哦!</p>
</main>
<footer>
<h1>底部內容</h1>
</footer>
</div>
CSS
#document {
height: 100vh;
display: flex;
flex-direction: column;
background: #202020;
font-family: microsoft yahei,wenquanyi micro hei,sans-serif !important;
}
nav, footer {
background: #494949;
display: flex;
justify-content: center;
}
main {
color: #bdbdbd;
flex: auto;
}
footer {
flex-shrink: 0;
}
* {
margin: 0;
}
h1,p {
padding: 15px;
}
nav > h1 {
color: #82FCFD;
text-shadow: 1px 1px 4px #00000080;
}
footer > h1 {
color: #82FCFD;
text-shadow: 1px 1px 4px #00000080;
}
知識點總結:
2. 懸停放大圖片特效
懸停放大圖片是一個特別吸引眼球的特效,比較常用于可點擊的圖片。當用戶懸停鼠標在圖片上,圖片會稍微的放大。
其實實現這個特效是非常簡單的。首先我們需要一個div包裹這img標簽,這個包裹層是用來遮擋住圖片,當圖片放大時不會出現圖片超出我們規定的寬高以外。
首先我們來講講div包裹的屬性,我們需要給它一個固定的width寬和height高。然后我們必須給予這個元素overflow: hidden屬性。讓圖片放大的時候不會超出這個div元素的寬高。有了這個包裹層,我們就可以編寫img的各種效果了。
我的例子里面用了transform: scale(1,1)作為懸停時的圖片特效,這個transform是用于改變任何元素的屬性的,然后scale是用于放大(整數就會放大)或者縮小(負數就會縮小)元素的。
上代碼讓大家看看:
html body中放入
<div class="img-wrapper">
<img src="https://img-blog.csdnimg.cn/2020032122230564.png"/>
</div>
CSS
.img-wrapper {
width: 400px;
height: 400px;
overflow: hidden;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
}
.img-wrapper img {
height: 400px;
-webkit-transition: 0.3s linear;
transition: 0.3s linear;
}
.img-wrapper img:hover {
transform: scale(1.1);
}
.img-wrapper {
display: inline-block;
box-sizing: border-box;
border: 3px solid #000;
}
如果你們想讓圖片更加炫酷可以加上圖片過濾屬性filter,讓圖片變灰或者變深褐色,然后懸停時候出現更加炫酷的顏色變幻。灰化的屬性是filter: grayscale(100%);,然后深褐色化的屬性是filter: sepia(100%)。其實圖片還有很多過濾屬性的,大家有興趣也可以去嘗試一下哦!
加入特殊效果的代碼如下:
HTML
<!-- 灰度過濾 -->
<div class="img-wrapper">
<img class="grayscale-img" src="https://img-blog.csdnimg.cn/2020032211021728.png" />
</div>
<!-- 深褐色過濾 -->
<div class="img-wrapper">
<img class="sepia-img" src="https://img-blog.csdnimg.cn/2020032122230564.png" />
</div>
CSS
/* ============== * 灰度過濾 * ==============*/
.grayscale-img {
-webkit-filter: grayscale(100%);
filter: grayscale(100%);
}
.grayscale-img:hover {
-webkit-filter: grayscale(0);
filter: grayscale(0);
}
/* ============== * 深褐色過濾* ==============*/
.sepia-img {
-webkit-filter: sepia(100%);
filter: sepia(100%);
}
.sepia-img:hover {
-webkit-filter: sepia(0);
filter: sepia(0);
}
3. 瞬間黑暗模式
最近微信也逃脫不了黑暗時代的到來,網頁也很多都做了黑暗模式的兼容和主題。如果我們在做的一個網站想瞬間實現黑暗模式可以怎么實現呢?
其實有一個很快的方式,我們可以使用invert和hue-rotate兩個CSS3過濾器來實現。
filter: invert() — 是從0到1的刻度,1是從白變黑。
filter: hue-rotate() — 用于改變你元素的顏色,同時或多或少保持原本相同的色系。這個屬性的值可以從0deg到360deg。
在我們頁面的body標簽上添加這兩個屬性,我們就可以快速嘗試把我們的網站變成"黑暗模式"。這里需要注意的是,如果body和html上沒有設置background背景顏色,這個過濾就會不起效了哦。
CSS的代碼如下:
html {
background: #fff;
}
body {
background: #fff; filter: invert(1) hue-rotate(270deg);
}
實現效果
這里我們會發現圖片的顏色會受影響,并不是很美觀,使用css過濾器是無法完美切換黑暗模式的。不過使用JavaScript輔助就可以完美的切換黑暗模式。
最近出了一個JavaScript輔助插件叫Darkmode.js。
Darkmode.js
其實Darkmode.js運用的也是css里面的一個特性叫mix-blend-mode — “CSS 屬性描述了元素的內容應該與元素的直系父元素的內容和元素的背景如何混合“。加上Javascript的輔助判斷哪些頁面上的元素需要黑化的,哪些是不需要黑化的。就會想我們之前那種做法,導致其他不需要黑化的元素,比如圖片,受到影響導致顏色出現問題。
使用Darkmode.js非常簡單,只要在腳本里面添加以下代碼就可以馬上加入一個插件,
<script src="https://cdn.jsdelivr.net/npm/darkmode-js@1.5.5/lib/darkmode-js.min.js">
</script>
<script>
// 這些是這個插件的可配置項:
var options = {
bottom: "32px", // 定位底部距離 - 默認: '32px'
right: "32px", // 定位右邊距離 - 默認: '32px'
left: "unset", // 定位左邊距離 - 默認: 'unset'
time: "0.5s", // 默認動畫時間: '0.3s'
mixColor: "#fff", // 需要改變的顏色 - 默認: '#fff'
backgroundColor: "#fff", // 背景顏色 - 默認: '#fff'
buttonColorDark: "#262728", // 黑暗模式下按鈕顏色 - 默認: '#100f2c'
buttonColorLight: "#fff", // 日間模式下按鈕顏色 - 默認: '#fff'
saveInCookies: true, // 是否在cookie保存當前模式 - 默認: true,
label: "", // 切換模式按鈕圖標 - 默認: ''
autoMatchOsTheme: true // 是否自動根據系統適應模式 - 默認: true
};
let darkmode = new Darkmode(options);
darkmode.showWidget();
</script>
如果你不希望用這個插件的默認按鈕,你可以在你的JavaScript代碼中自主控制。我們可以通過.toggle()方法來切換模式,同時可以使用.isActivated()來檢測是否已經進入黑暗模式。
const darkmode = new Darkmode();darkmode.toggle();
console.log(darkmode.isActivated())
// 如果已經進入黑暗模式會返回 true
知識總結
4. 自定義列表符號
ul,li的無序列表有默認的符號·,但是在很多情況下我們希望可以給這個符號加入自己的樣式和顏色,甚至是換成自定義的符號。默認的符號我們是無法做任何的樣式處理,而且默認的符號在CSS屬性里面只有幾個選擇可以使用,很多情況下都是無法滿足我們的設計。
其實自定義無序列表符號不難,我們只需要使用偽元素::before加content屬性就可以實現。
在我這個例子里面我做了兩個任務列表,一個是待處理任務,一個是已完成任務,各自給了不一樣的列表符號和顏色。
實現原理
一、首先我們禁用了ul的默認符號樣式list-style: none
二、在li的:before偽元素上給予content內容值,待處理任務使用,已完成任務li.completed:before使用?
三、為了展示效果更加好看我分別給了li和li .completed兩個不同的顏色
上代碼看看是怎么實現的吧:
HTML
<div>
<h2>待處理</h2>
<ul>
<li>待辦任務1</li>
<li>待辦任務2</li>
<li>待辦任務3</li>
<li>待辦任務4</li>
<li>待辦任務5</li>
</ul>
</div>
<div>
<h2>已完成</h2>
<ul>
<li class="completed">完成任務1</li>
<li class="completed">完成任務2</li>
<li class="completed">完成任務3</li>
</ul>
</div>
CSS
ul {
list-style: none; color: #fff;
font-size: 20px;
border: 3px solid #000;
padding: 1rem 2rem;
min-height: 200px;
margin: 15px 2rem 0 0;
background: #323232;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
border-radius: 8px;
}
li {
padding: 0.3rem 0;
}
li::before {
content: " ";
color: aqua;
}
li.completed::before {
content: "? ";
text-decoration: none;
color: greenyellow;
}
li.completed {
text-decoration: line-through;
color: #bdbdbd;
}
::before和::after偽元素加content屬性可以用來做很多特殊的效果,也是當代前端排版比較常用的“魔法”。說到偽元素的使用,我再給大家說一個比較常用的使用場景。
在管理后臺或者是文章展示中,我們經常可以見到的“面包屑導航”也是用偽元素來插入每個目錄中間的符號的。
實現邏輯
一、這個導航含有3個a標簽,首先給每個a標簽加入一個偽元素::after,然后在content屬性插入/符號。
二、然后使用a:first-child,這個偽類會選擇到第一個a標簽,然后使用content屬性加入?符號。
三、因為我們第一步在每個a標簽的后面插入了/符號, 所以我們需要在最后一個a標簽清除掉。這里我們使用:last-child選擇到最后一個a標簽,然后用content: " "屬性把偽元素的內容清楚掉。
HTML
<div class="breadcrumb">
<a>三鉆</a>
<a>前端</a>
<a>教程</a>
</div>
CSS
.breadcrumb {
font-size: 1.6rem;
color: #fff;
}
.breadcrumb a:first-child {
color: #82fcfd;
}
.breadcrumb a:first-child::before {
content: " ? ";
}
.breadcrumb a::after {
content: " /";
color: #ef6eae;
}
.breadcrumb a:last-child::after {
content: "";
}
知識總結
::before | ::after — 偽元素用于向某些選擇器添加特殊的效果。
content — CSS 屬性用于在元素的 ::before 和 ::after 偽元素中插入內容。使用content 屬性插入的內容都是匿名的可替換元素。
:first-child — CSS偽類表示在一組兄弟元素中的第一個元素。
:last-child — CSS偽類代表父元素的最后一個子元素。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。