chokcoco

chokcoco 查看完整檔案

深圳編輯  |  填寫畢業院校深圳騰訊公司  |  切圖仔 編輯 github.com/chokcoco 編輯
編輯

坎坷切圖仔

個人動態

chokcoco 發布了文章 · 3月3日

巧用 -webkit-box-reflect 倒影實現各類動效

在很久之前的一篇文章,有講到 -webkit-box-reflect 這個屬性 -- 從倒影說起,談談 CSS 繼承 inherit

-webkit-box-reflect 是一個非常有意思的屬性,它讓 CSS 有能力像鏡子一樣,反射我們元素原本繪制的內容。

上一次寫它,它的兼容性還非常非常的慘淡,但是到今天,雖然還是一個 Non-standard 的語法,但是兼容性已經大有改觀,并且利用它,我們可以實現非常多有意思的效果。

截止至 2021-02-19,它的兼容性已經達到了 91.02%,看看 CANIUSE -webkit-box-reflect

image

接下來進入正文。

-webkit-box-reflect 基本用法

-webkit-box-reflect 的語法非常簡單,最基本的用法像是這樣:

div {
    -webkit-box-reflect: below;
}

其中,below 可以是 below | above | left | right 代表下上左右,也就是有 4 個方向可以選。

假設我們有如下一張圖片:

<div></div>
div {
    background-image: url('https://images.pokemontcg.io/xy2/12_hires.png');
}

image

加上 -webkit-box-reflect: right,也就是右側的倒影:

div {
    background-image: url('https://images.pokemontcg.io/xy2/12_hires.png');
    -webkit-box-reflect: right;
}

效果如下,生成了一個元素右側的鏡像元素:

image

設置倒影距離

在方向后面,還可以接一個具體的數值大小,表示倒影與原元素間的距離。

div {
    background-image: url('https://images.pokemontcg.io/xy2/12_hires.png');
    -webkit-box-reflect: right 10px;
}

加上 10px 之后,倒影與原元素間將間隔 10px

image

設置倒影虛實

還有一個非常重要的功能,就是方位后面,還能再設置一個漸變值,利用這個漸變值,可以實現倒影的一個虛化效果,這一點非常重要。

div {
    background-image: url('https://images.pokemontcg.io/xy2/12_hires.png');
    -webkit-box-reflect: below 2px linear-gradient(transparent, rgba(0, 0, 0, .5));
}

看看效果,有了虛實變化之后,這樣就更像是一個倒影.

其實,這里的漸變就是給倒影的圖片添加了一個 MASK 屬性,MASK 屬性的 transparent 部分,圖片將變得透明,而實色部分,則保持原圖。

關于 CSS MASK 屬性,如果你還有什么疑問,建議看看這篇文章:奇妙的 CSS MASK

image

CodePen Demo -- -webkit-box-reflect Demo

使用 -webkit-box-reflect 實現一些有意思的動效

掌握了基本的語法后,我們就可以利用其實現一些有意思的動效,下面簡單羅列一下。

我發現這個屬性特別適合運用在一些暗黑系風格的頁面中。能夠讓很多動效看起來高大上很多。(個人審美)

在按鈕中運用 -webkit-box-reflect

配合一些動態邊框動畫的按鈕,能夠營造一種很科幻的效果:

感興趣的可以自行戳源碼了解了解:

CodePen demo -webkit-box-reflect Neon Button Hover Effect

在文字中運用 -webkit-box-reflect

在暗黑系的標題文字中,運用上 -webkit-box-reflect ,瞬間高大上了不少。

image

CodePen demo - Font & -webkit-box-reflect

在 3D 中運用 -webkit-box-reflect

嘿嘿,接下來,我們甚至可以把 -webkit-box-reflect 運用中 3D 效果中,完全不一樣的觀感體驗。

我們給一個 3D 照片墻,加上倒影效果:

CodePen demo - 3DView & -webkit-box-reflect

使用 -webkit-box-reflect 創造藝術圖案

有趣的 CSS 藝術,它又來了。

在袁川老師的這篇文章中 -- Chinese Window Lattice And CSS,介紹了利用 -webkit-box-reflect 生成剪紙藝術這樣一種思路。

由于 -webkit-box-reflect 可以生成倒影,那么我們利用它進行不斷的套娃,一層疊一層,那么只需要生成一個基本的元素,就可以利用倒影產生出各種不同的效果。

假設,我們有如下結構:

<div class="g-wrap1">
    <div class="g-wrap2">
        <div class="g-wrap3">
            <div class="g-wrap4"></div>
        </div>
    </div>
</div>

我們只需要給 .g-wrap4 實現一個圖形,例如這樣:

.g-wrap4 {
    background: 
        radial-gradient(circle at 0 0, #000 30%, transparent 30%, transparent 40%, #000 40%, #000 50%, transparent 50%),
        radial-gradient(circle at 100% 100%, #000 10%, transparent 10%, transparent 30%, #000 30%, #000 40%, transparent 40%);
}

image

然后就是 4 層套娃, 首先給 .g-wrap4 加上一層倒影 -webkit-box-reflect

.g-wrap4 {
    -webkit-box-reflect: right 0px;
}

得到:

image

繼續套娃,給 .g-wrap3 加上一層倒影 -webkit-box-reflect

.g-wrap4 {
    -webkit-box-reflect: right 0px;
}
.g-wrap3 {
    -webkit-box-reflect: below 0px;
}

image

繼續,給 .g-wrap2 加上一層倒影 -webkit-box-reflect

.g-wrap4 {
    -webkit-box-reflect: right 0px;
}
.g-wrap3 {
    -webkit-box-reflect: below 0px;
}
.g-wrap2 {
    -webkit-box-reflect: left 0px;
}

image

最后,給 .g-wrap1 加上一層倒影 -webkit-box-reflect

.g-wrap4 {
    -webkit-box-reflect: right 0px;
}
.g-wrap3 {
    -webkit-box-reflect: below 0px;
}
.g-wrap2 {
    -webkit-box-reflect: left 0px;
}
.g-wrap1 {
    -webkit-box-reflect: above 0px;
}

就可以得到一個通過 4 層倒影得到的圖形:

image

這樣,通過不同的基礎圖形,發揮我們的想象力,就可以生成各式各樣的剪紙對稱圖形:

image

完整的代碼,可以戳這里:

CodePen Demo -- -webkit-box-reflect artist

最后

本文到此結束,希望對你有幫助 :),本文介紹了 webkit-box-reflect 的一些有意思的用法,可能業務中不太實用,但是非常有趣。

想 Get 到最有意思的 CSS 資訊,千萬不要錯過我的公眾號 -- iCSS前端趣聞 ??

image.png

更多精彩 CSS 技術文章匯總在我的 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。

如果還有什么疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

查看原文

贊 9 收藏 2 評論 1

chokcoco 發布了文章 · 2月24日

前端優秀實踐不完全指南

本文其實應該叫,Web 用戶體驗設計提升指南。

一個 Web 頁面,一個 APP,想讓別人用的爽,也就是所謂的良好的用戶體驗,我覺得他可能包括但不限于:

  • 急速的打開速度
  • 眼前一亮的 UI 設計
  • 酷炫的動畫效果
  • 豐富的個性化設置
  • 便捷的操作b
  • 貼心的細節
  • 關注殘障人士,良好的可訪問性
  • ...

所謂的用戶體驗設計,其實是一個比較虛的概念,是秉承著以用戶為中心的思想的一種設計手段,以用戶需求為目標而進行的設計。設計過程注重以用戶為中心,用戶體驗的概念從開發的最早期就開始進入整個流程,并貫穿始終。

良好的用戶體驗設計,是產品每一個環節共同努力的結果。

除去一些很難一蹴而就的,本文將就頁面展示、交互細節、可訪問性三個方面入手,羅列一些在實際的開發過程中,積攢的一些有益的經驗。通過本文,你將能收獲到:

  1. 了解到一些小細節是如何影響用戶體驗的
  2. 了解到如何在盡量小的開發改動下,提升頁面的用戶體驗
  3. 了解到一些優秀的交互設計細節
  4. 了解基本的無障礙功能及頁面可訪問性的含義
  5. 了解基本的提升頁面可訪問性的方法

頁面展示

就整個頁面的展示,頁面內容的呈現而言,有一些小細節是需要我們注意的。

整體布局

先來看看一些布局相關的問題。

對于大部分 PC 端的項目,我們首先需要考慮的肯定是最外層的一層包裹。假設就是 .g-app-wrapper。

<div class="g-app-wrapper">
    <!-- 內部內容 -->
</div>

首先,對于 .g-app-wrapper,有幾點,是我們在項目開發前必須弄清楚的:

  1. 項目是全屏布局還是定寬布局?
  2. 對于全屏布局,需要適配的最小的寬度是多少?

對于定寬布局,就比較方便了,假設定寬為 1200px,那么:

.g-app-wrapper {
    width: 1200px;
    margin: 0 auto;
}

利用 margin: 0 auto 實現布局的水平居中。在屏幕寬度大于 1200px 時,兩側留白,當然屏幕寬度小于 1200px 時,則出現滾動條,保證內部內容不亂。

layout1

對于現代布局,更多的是全屏布局。其實現在也更提倡這種布局,即使用可隨用戶設備的尺寸和能力而變化的自適應布局。

通常而言是左右兩欄,左側定寬,右側自適應剩余寬度,當然,會有一個最小的寬度。那么,它的布局應該是這樣:

<div class="g-app-wrapper">
    <div class="g-sidebar"></div>
    <div class="g-main"></div>
</div>
.g-app-wrapper {
    display: flex;
    min-width: 1200px;
}
.g-sidebar {
    flex-basis: 250px;
    margin-right: 10px;
}
.g-main {
    flex-grow: 1;
}

layout2

利用了 flex 布局下的 flex-grow: 1,讓 .main 進行伸縮,占滿剩余空間,利用 min-width 保證了整個容器的最小寬度。

當然,這是最基本的自適應布局。對于現代布局,我們應該盡可能的考慮更多的場景。做到:

image

底部 footer

下面一種情形也是非常常見的一個情景。

頁面存在一個 footer 頁腳部分,如果整個頁面的內容高度小于視窗的高度,則 footer 固定在視窗底部,如果整個頁面的內容高度大于視窗的高度,則 footer 正常流排布(也就是需要滾動到底部才能看到 footer)。

看看效果:

margintopauto

嗯,這個需求如果能夠使用 flex 的話,使用 justify-content: space-between 可以很好的解決,同理使用 margin-top: auto 也非常容易完成:

<div class="g-container">
    <div class="g-real-box">
        ...
    </div>
    <div class="g-footer"></div>
</div>
.g-container {
    height: 100vh;
    display: flex;
    flex-direction: column;
}

.g-footer {
    margin-top: auto;
    flex-shrink: 0;
    height: 30px;
    background: deeppink;
}

Codepen Demo -- sticky footer by flex margin auto

當然,實現它的方法有很多,這里僅給出一種推薦的解法。

處理動態內容 - 文本超長

對于所有接收后端接口字段的文本展示類的界面。都需要考慮全面(防御性編程:所有的外部數據都是不可信的),正常情況如下,是沒有問題的。

image

但是我們是否考慮到了文本會超長?超長了會折行還是換行?

image

對于單行文本,使用單行省略:

{
    width: 200px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

image

當然,目前對于多行文本的超長省略,兼容性也已經非常好了:

{
    width: 200px;
    overflow : hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

image

處理動態內容 - 保護邊界

對于一些動態內容,我們經常使用 min/max-widthmin/max-height 對容器的高寬限度進行合理的控制。

在使用它們的時候,也有一些細節需要考慮到。

譬如經常會使用 min-width 控制按鈕的最小寬度:

.btn {
    ...
    min-width: 120px;
}

image

當內容比較少的時候是沒問題的,但是當內容比較長,就容易出現問題。使用了 min-width 卻沒考慮到按鈕的過長的情況:

image

這里就需要配合 padding 一起:

.btn {
    ...
    min-width: 88px;
    padding: 0 16px
}

借用Min and Max Width/Height in CSS中一張非常好的圖,作為釋義:

min-width-2

0 內容展示

這個也是一個常常被忽略的地方。

頁面經常會有列表搜索,列表展示。那么,既然存在有數據的正常情況,當然也會存在搜索不到結果或者列表無內容可展示的情形。

對于這種情況,一定要注意 0 結果頁面的設計,同時也要知道,這也是引導用戶的好地方。對于 0 結果頁面,分清楚:

  • 數據為空:其中又可能包括了用戶無權限、搜索無結果、篩選無結果、頁面無數據
  • 異常狀態:其中又可能包括了網絡異常、服務器異常、加載失敗等待

不同的情況可能對應不同的 0 結果頁面,附帶不同的操作引導。

譬如網絡異常:

image

或者確實是 0 結果:

image

關于 0 結果頁面設計,可以詳細看看這篇文章:如何設計產品的空白頁面?

小小總結一下,上述比較長的篇幅一直都在闡述一個道理,開發時,不能僅僅關注正?,F象,要多考慮各種異常情況,思考全面。做好各種可能情況的處理。

圖片相關

圖片在我們的業務中應該是非常的常見了。有一些小細節是需要注意的。

給圖片同時設置高寬

有的時候和產品、設計會商定,只能使用固定尺寸大小的圖片,我們的布局可能是這樣:

image

對應的布局:

<ul class="g-container">
    <li>
        <img data-original="http://placehold.it/150x100">
        <p>圖片描述</p>
    </li>
</ul>
ul li img {
    width: 150px;
}

當然,萬一假設后端接口出現一張非正常大小的圖片,上述不加保護的布局就會出問題:

image

所以對于圖片,我們總是建議同時寫上高和寬,避免因為圖片尺寸錯誤帶來的布局問題:

ul li img {
    width: 150px;
    height: 100px;
}

同時,給 <img> 標簽同時寫上高寬,可以在圖片未加載之前提前占住位置,避免圖片從未加載狀態到渲染完成狀態高寬變化引起的重排問題。

object-fit

當然,限制高寬也會出現問題,譬如圖片被拉伸了,非常的難看:

image

這個時候,我們可以借助 object-fit,它能夠指定可替換元素的內容(也就是圖片)該如何適應它的父容器的高寬。

ul li img {
    width: 150px;
    height: 100px;
    object-fit: cover;
}

利用 object-fit: cover,使圖片內容在保持其寬高比的同時填充元素的整個內容框。

image

object-fit 還有一個配套屬性 object-position,它可以控制圖片在其內容框中的位置。(類似于 background-position),m默認是 object-position: 50% 50%,如果你不希望圖片居中展示,可以使用它去改變圖片實際展示的 position 。

ul li img {
    width: 150px;
    height: 100px;
    object-fit: cover;
    object-position: 50% 100%;
}

image

像是這樣,object-position: 100% 50% 指明從底部開始展示圖片。這里有一個很好的 Demo 可以幫助你理解 object-position。

CodePen Demo -- Object position

考慮屏幕 dpr -- 響應式圖片

正常情況下,圖片的展示應該沒有什么問題了。但是對于有圖片可展示的情況下,我們還可以做的更好。

在移動端或者一些高清的 PC 屏幕(蘋果的 MAC Book),屏幕的 dpr 可能大于 1。這種時候,我們可能還需要考慮利用多倍圖去適配不同 dpr 的屏幕。

正好,<img> 標簽是有提供相應的屬性 srcset 讓我們進行操作的。

<img data-original='photo@1x.png'
   srcset='photo@1x.png 1x,
           photo@2x.png 2x,
           photo@3x.png 3x' 
/>

當然,這是比較舊的寫法,srcset 新增了新的 w 寬度描述符,需要配合 sizes 一起使用,所以更好的寫法是:

<img 
        src = "photo.png" 
        sizes = “(min-width: 600px) 600px, 300px" 
        srcset = “photo@1x.png 300w,
                       photo@2x.png 600w,
                       photo@3x.png 1200w,
>

利用 srcset,我們可以給不同 dpr 的屏幕,提供最適合的圖片。

上述出現了一些概念,dpr,圖片的 srcset ,sizes 屬性,,不太了解的可以移步 前端基礎知識概述

圖片丟失

好了,當圖片鏈接沒問題時,已經處理好了。接下來還需要考慮,當圖片鏈接掛了,應該如何處理。

處理的方式有很多種。最好的處理方式,是我最近在張鑫旭老師的這篇文章中 -- 圖片加載失敗后CSS樣式處理最佳實踐 看到的。這里簡單講下:

  1. 利用圖片加載失敗,觸發 <img> 元素的 onerror 事件,給加載失敗的 <img> 元素新增一個樣式類
  2. 利用新增的樣式類,配合 <img> 元素的偽元素,展示默認兜底圖的同時,還能一起展示 <img> 元素的 alt 信息
<img data-original="test.png" alt="圖片描述" onerror="this.classList.add('error');">
img.error {
    position: relative;
    display: inline-block;
}

img.error::before {
    content: "";
    /** 定位代碼 **/
    background: url(error-default.png);
}

img.error::after {
    content: attr(alt);
    /** 定位代碼 **/
}

我們利用偽元素 before ,加載默認錯誤兜底圖,利用偽元素 after,展示圖片的 alt 信息:

image

OK,到此,完整的對圖片的處理就算完成了,完整的 Demo 你可以戳這里看看:

CodePen Demo -- 圖片處理

交互設計優化

接下來一個大環節是關于一些交互的細節。對于交互設計,一些比較通用的準則:

  • Don’t make me think
  • 符合用戶的習慣與預期
  • 操作便利
  • 做適當的提醒
  • 不強迫用戶

過渡與動畫

在我們的交互過程中,適當的增加過渡與動畫,能夠很好的讓用戶感知到頁面的變化。

譬如我們頁面上隨處可見 loading 效果,其實就是這樣一種作用,讓用戶感知頁面正在加載,或者正在處理某些事務。

滾動優化

滾動也是操作網頁中非常重要的一環??纯从心男┛梢詢灮狞c:

滾動平滑:使用 scroll-behavior: smooth 讓滾動絲滑

使用 scroll-behavior: smooth,可以讓滾動框實現平穩的滾動,而不是突兀的跳動??纯葱Ч?,假設如下結構:

<div class="g-container">
  <nav>
    <a href="#1">1</a>
    <a href="#2">2</a>
    <a href="#3">3</a>
  </nav>
  <div class="scrolling-box">
    <section id="1">First section</section>
    <section id="2">Second section</section>
    <section id="3">Third section</section>
  </div>
</div>

不使用 scroll-behavior: smooth,是突兀的跳動切換:

scrol

給可滾動容器添加 scroll-behavior: smooth,實現平滑滾動:

{
    scroll-behavior: smooth;
}

scroll2

使用 scroll-snap-type 優化滾動效果

sroll-snap-type 可能算得上是新的滾動規范里面最核心的一個屬性樣式。

scroll-snap-type:屬性定義在滾動容器中的一個臨時點(snap point)如何被嚴格的執行。

光看定義有點難理解,簡單而言,這個屬性規定了一個容器是否對內部滾動動作進行捕捉,并且規定了如何去處理滾動結束狀態。讓滾動操作結束后,元素停止在適合的位置。

看個簡單示例:

當然,scroll-snap-type 用法非常多,可控制優化的點很多,限于篇幅無法一一展開,具體更詳細的用法可以看看我的另外一篇文章 -- 使用 sroll-snap-type 優化滾動

控制滾動層級,避免頁面大量重排

這個優化可能稍微有一點難理解。需要了解 CSS 渲染優化的相關知識。

先說結論,控制滾動層級的意思是盡量讓需要進行 CSS 動畫(可以是元素的動畫,也可以是容器的滾動)的元素的 z-index 保持在頁面最上方,避免瀏覽器創建不必要的圖形層(GraphicsLayer),能夠很好的提升渲染性能。

這一點怎么理解呢,一個元素觸發創建一個 Graphics Layer 層的其中一個因素是:

  • 元素有一個 z-index 較低且包含一個復合層的兄弟元素

根據上述這點,我們對滾動性能進行優化的時候,需要注意兩點:

  1. 通過生成獨立的 GraphicsLayer,利用 GPU 加速,提升滾動的性能
  2. 如果本身滾動沒有性能問題,不需要獨立的 GraphicsLayer,也要注意滾動容器的層級,避免因為層級過高而被其他創建了 GraphicsLayer 的元素合并,被動的生成一個 Graphics Layer ,影響頁面整體的渲染性能

如果你對這點還有點懵,可以看看這篇文章 -- 你所不知道的 CSS 動畫技巧與細節

點擊交互優化

在用戶點擊交互方面,也有一些有意思的小細節。

優化手勢 -- 不同場景應用不同 cursor

對于不同的內容,最好給與不同的 cursor 樣式,CSS 原生提供非常多種常用的手勢。

在不同的場景使用不同的鼠標手勢,符合用戶的習慣與預期,可以很好的提升用戶的交互體驗。

首先對于按鈕,就至少會有 3 種不同的 cursor,分別是可點擊,不可點擊,等待中:

{
    cursor: pointer;    // 可點擊
    cursor: not-allowed;    // 不可點擊
    cursor: wait;    // loading
}

image

除此之外,還有一些常見的,對于一些可輸入的 Input 框,使用 cursor: text,對于提示 Tips 類使用 cursor: help,放大縮小圖片 zoom-in、zoom-out 等等:

image

一些常用的簡單列一列:

  • 按鈕可點擊: cursor: pointer
  • 按鈕禁止點擊:cursor: not-allowed
  • 等待 Loading 狀態:cursor: wait
  • 輸入框:cursor: text;
  • 圖片查看器可放大可縮?。?code>cursor: zoom-in/ zoom-out
  • 提示:cursor: help;

當然,實際 cursor 還支持非常多種,可以在 MDN 或者下面這個 CodePen Demo 中查看這里看完整的列表:

CodePen Demo -- Cursor Demo

點擊區域優化 -- 偽元素擴大點擊區域

按鈕是我們網頁設計中十分重要的一環,而按鈕的設計也與用戶體驗息息相關。

考慮這樣一個場景,在搖晃的車廂上或者是單手操作著屏幕,有的時候一個按鈕,死活也點不到。

讓用戶更容易的點擊到按鈕無疑能很好的增加用戶體驗及可提升頁面的訪問性,尤其是在移動端,按鈕通常都很小,但是受限于設計稿或者整體 UI 風格,我們不能直接去改變按鈕元素的高寬。

那么這個時候有什么辦法在不改變按鈕原本大小的情況下去增加他的點擊熱區呢?

這里,偽元素也是可以代表其宿主元素來響應的鼠標交互事件的。借助偽元素可以輕松幫我們實現,我們可以這樣寫:

.btn::before{
  content:"";
  position:absolute;
  top:-10px;
  right:-10px;
  bottom:-10px;
  left:-10px;
}

當然,在 PC 端下這樣子看起來有點奇怪,但是合理的用在點擊區域較小的移動端則能取到十分好的效果,效果如下:

608782-20160527112625428-906375003

在按鈕的偽元素沒有其它用途的時候,這個方法確實是個很好的提升用戶體驗的點。

快速選擇優化 -- user-select: all

操作系統或者瀏覽器通常會提供一些快速選取文本的功能,看看下面的示意圖:

layout3

快速單擊兩次,可以選中單個單詞,快速單擊三次,可以選中一整行內容。但是如果有的時候我們的核心內容,被分隔符分割,或者潛藏在一整行中的一部分,這個時候選取起來就比較麻煩。

利用 user-select: all,可以將需要一次選中的內容進行包裹,用戶只需要點擊一次,就可以選中該段信息:

.g-select-all {
    user-select: all
}

給需要一次選中的信息,加上這個樣式后的效果,這個細節作用在一些需要復制粘貼的場景,非常好用:

layout4

CodePen -- user-select: all 示例

選中樣式優化 -- ::selection

當然,如果你想更進一步,CSS 還有提供一個 ::selection 偽類,可以控制選中的文本的樣式(只能控制color, background, text-shadow),進一步加深效果。

layout5

CodePen -- user-select: all && ::selection 控制選中樣式

添加禁止選擇 -- user-select: none

有快速選擇,也就會有它的對立面 -- 禁止選擇。

對于一些可能頻繁操作的按鈕,可能出現如下尷尬的場景:

  • 文本按鈕的快速點擊,觸發了瀏覽器的雙擊快速選擇,導致文本被選中:

btn-click

  • 翻頁按鈕的快速點擊,觸發了瀏覽器的雙擊快速選擇:

img-click

對于這種場景,我們需要把不可被選中元素設置為不可被選中,利用 CSS 可以快速的實現這一點:

{
    -webkit-user-select: none; /* Safari */
    -ms-user-select: none; /* IE 10 and IE 11 */
    user-select: none; /* Standard syntax */
}

這樣,無論點擊的頻率多快,都不會出現尷尬的內容選中:

btn-click-unselect

跳轉優化

現階段,單頁應用(Single Page Application)的應用非常廣泛,Vue 、React 等框架大行其道。但是一些常見的寫法,也容易衍生一些小問題。

譬如,點擊按鈕、文本進行路由跳轉。譬如,經常會出現這種代碼:

<template>
    ...
    <button @click="gotoDetail">
        Detail
    </button>
    ...
<template>
...
gotoDetail() {
    this.$router.push({
      name: 'xxxxx',
    });
}

大致邏輯就是給按鈕添加一個事件,點擊之后,跳轉到另外一個路由。當然,本身這個功能是沒有任何問題的,但是沒有考慮到用戶實際使用的場景。

實際使用的時候,由于是一個頁面跳轉,很多時候,用戶希望能夠保留當前頁面的內容,同時打開一個新的窗口,這個時候,他會嘗試下的鼠標右鍵,選擇在新標簽頁中打開頁面,遺憾的是,上述的寫法是不支持鼠標右鍵打開新頁面的。

原因在于瀏覽器是通過讀取 <a> 標簽的 href 屬性,來展示類似在新標簽頁中打開頁面這種選項,對于上述的寫法,瀏覽器是無法識別它是一個可以跳轉的鏈接。簡單的示意圖如下:

image

所以,對于所有路由跳轉按鈕,建議都使用 <a> 標簽,并且內置 href 屬性,填寫跳轉的路由地址。實際渲染出來的 DOM 可能是需要類似這樣:

<a href="/xx/detail">Detail</a>

易用性

易用性也是交互設計中需要考慮的一個非常重要的環節,能做的有非常多。簡單的羅列一下:

  • 注意界面元素的一致性,降低用戶學習成本
  • 延續用戶日常的使用習慣,而不是重新創造
  • 給下拉框增加一些預設值,降低用戶填寫成本
  • 同類的操作合并在一起,降低用戶的認知成本
  • 任何操作之后都要給出反饋,讓用戶知道操作已經生效

先探索,后表態

這一點非常的有意思,什么叫先探索后表態呢?就是我們不要一上來就強迫用戶去做一些事情,譬如登錄。

想一想一些常用網站的例子:

  • 類似虎牙、Bilibili 等視頻網站,可以先藍光體驗,一定觀看時間后才會要求登錄
  • 電商網站,只有到付款的時候,才需要登錄

上述易用性先探索,后表態的內容,部分來源于:Learn From What Leading Companies A/B Test,可以好好讀一讀。

字體優化

字體的選擇與使用其實是非常有講究的。

如果網站沒有強制必須使用某些字體。最新的規范建議我們更多的去使用系統默認字體。也就是 CSS Fonts Module Level 4 -- Generic font families 中新增的 font-family: system-ui 關鍵字。

font-family: system-ui 能夠自動選擇本操作系統下的默認系統字體。

默認使用特定操作系統的系統字體可以提高性能,因為瀏覽器或者 webview 不必去下載任何字體文件,而是使用已有的字體文件。 font-family: system-ui 字體設置的優勢之處在于它與當前操作系統使用的字體相匹配,對于文本內容而言,它可以得到最恰當的展示。

舉兩個例子,天貓的字體定義與 Github 的字體定義:

  • 天貓font-family: "PingFang SC",miui,system-ui,-apple-system,BlinkMacSystemFont,Helvetica Neue,Helvetica,sans-serif;
  • Githubfont-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;

簡單而言,它們總體遵循了這樣一個基本原則:

1、盡量使用系統默認字體

使用系統默認字體的主要原因是性能,并且系統字體的優點在于它與當前操作系統使用的相匹配,因此它的文本展示必然也是一個讓人舒適展示效果。

2、兼顧中西,西文在前,中文在后

中文或者西文(英文)都要考慮到。由于大部分中文字體也是帶有英文部分的,但是英文部分又不怎么好看,但是英文字體中大多不包含中文。通常會先進行英文字體的聲明,選擇最優的英文字體,這樣不會影響到中文字體的選擇,中文字體聲明則緊隨其次。

3、兼顧多操作系統

選擇字體的時候要考慮多操作系統。例如 MAC OS 下的很多中文字體在 Windows 都沒有預裝,為了保證 MAC 用戶的體驗,在定義中文字體的時候,先定義 MAC 用戶的中文字體,再定義 Windows 用戶的中文字體;

4、兼顧舊操作系統,以字體族系列?serif?和?sans-serif?結尾

當使用一些非常新的字體時,要考慮向下兼容,兼顧到一些極舊的操作系統,使用字體族系列?serif?和?sans-serif?結尾總歸是不錯的選擇。

對于上述的一些字體可能會有些懵,譬如 -apple-system, BlinkMacSystemFont,這是因為不同瀏覽器廠商對規范的實現有所不同,對于字體定義更多的相關細節,可以再看看這篇文章 -- Web 字體 font-family 再探秘

可訪問性(A11Y)

可訪問性,在我們的網站中,屬于非常重要的一環,但是大部分前端(其實應該是設計、前端、產品)同學都會忽視它。

我潛伏在一個叫無障礙設計小組的群里,其中包含了很多無障礙設計師以及患有一定程度視覺、聽力、行動障礙的用戶,他們在群里經常會表達出一個觀點,就是國內的大部分 Web 網站及 APP 基本沒有考慮過殘障人士的使用(或者可訪問性做的非常差),非常的令人揪心。

尤其在我們一些重交互、重邏輯的網站中,我們需要考慮用戶的使用習慣、使用場景,從高可訪問性的角度考慮,譬如假設用戶沒有鼠標,僅僅使用鍵盤,能否順暢的使用我們的網站?

假設用戶沒有鼠標,這個真不一定是針對殘障人士,很多情況下,用戶拿鼠標的手可能在干其他事情,比如在吃東西,又或者在 TO B 類的業務,如超市收銀、倉庫收貨,很可能用戶拿鼠標的手操作著其他設備(掃碼槍)等等。

本文不會專門闡述無障礙設計的方方面面,只是從一些我覺得前端工程師需要關注的,并且僅需要花費少量代價就能做好的一些無障礙設計細節。記住,無障礙設計對所有人都更友善。

色彩對比度

顏色,也是我們天天需要打交道的屬性。對于大部分視覺正常的用戶,可能對頁面的顏色敏感度還沒那么高。但是對于一小部分色弱、色盲用戶,他們對于網站的顏色會更加敏感,不好的設計會給他們訪問網站帶來極大的不便。

什么是色彩對比度

是否曾關心過頁面內容的展示,使用的顏色是否恰當?色弱、色盲用戶能否正??辞鍍热??良好的色彩使用,在任何時候都是有益的,而且不僅僅局限于對于色弱、色盲用戶。在戶外用手機、陽光很強看不清,符合無障礙標準的高清晰度、高對比度文字就更容易閱讀。

這里就有一個概念 -- 顏色對比度,簡單地說,描述就是兩種顏色在亮度(Brightness)上的差別。運用到我們的頁面上,大多數的情況就是背景色(background-color)與內容顏色(color)的對比差異。

最權威的互聯網無障礙規范 —— WCAG AA規范規定,所有重要內容的色彩對比度需要達到 4.5:1 或以上(字號大于18號時達到 3:1 或以上),才算擁有較好的可讀性。

借用一張圖 -- 知乎 -- 助你輕松做好無障礙的15個UI設計工具推薦

很明顯,上述最后一個例子,文字已經非常的不清晰了,正常用戶都已經很難看得清了。

檢查色彩對比度的工具

Chrome 瀏覽器從很早開始,就已經支持檢查元素的色彩對比度了。以我當前正在寫作的頁面為例子,Github Issues 編輯頁面的兩個按鈕:

image

審查元素,分別可以看到兩個按鈕的色彩對比度:

image

可以看到,綠底白字按鈕的色彩對比度是沒有達到標準的,也被用黃色的嘆號標識了出來。

除此之外,在審查元素的 Style 界面的取色器,改變顏色,也能直觀的看到當前的色彩對比度:

image

焦點響應

類似百度、谷歌的首頁,進入頁面后會默認讓輸入框獲得焦點:

image

并非所有的有輸入框的頁面,都需要進入頁面后進行聚焦,但是焦點能夠讓用戶非常明確的知道,當前自己在哪,需要做些什么。尤其是對于無法操作鼠標的用戶。

頁面上可以聚焦的元素,稱為可聚焦元素,獲得焦點的元素,則會觸發該元素的 focus 事件,對應的,也就會觸發該元素的 :focus 偽類。

瀏覽器通常會使用元素的 :focus 偽類,給元素添加一層邊框,告訴用戶,當前的獲焦元素在哪里。

我們可以通過鍵盤的 Tab 鍵,進行焦點的切換,而獲焦元素則可以通過元素的 :focus 偽類的樣式,告訴用戶當前焦點位置。

當然,除了 Tab 鍵之外,對于一些多輸入框、選擇框的表單頁面,我們也應該想著如何簡化用戶的操作,譬如用戶按回車鍵時自動前進到下一字段。一般而言,用戶必須執行的觸按越少,體驗越佳。

下面的截圖,完全由鍵盤操作完成

a11y

通過元素的 :focus 偽類以及鍵盤 Tab 鍵切換焦點,用戶可以非常順暢的在脫離鼠標的情況下,對頁面的焦點切換及操作。

然而,在許多 reset.css 中,經常能看到這樣一句 CSS 樣式代碼,為了樣式的統一,消除了可聚焦元素的 :focus 偽類:

:focus {
    outline: 0;
}

我們給上述操作的代碼。也加上這樣一句代碼,全程再用鍵盤操作一下

a11y2

除了在 input 框有光標提示,當使用 Tab 進行焦點切換到 select 或者到 button 時,由于沒有了 :focus 樣式,用戶將完全懵逼,不知道頁面的焦點現在處于何處。

保證非鼠標用戶體驗,合理運用 :focus-visible

當然,造成上述結果很重要的一個原因在于。:focus 偽類不論用戶在使用鼠標還是使用鍵盤,只要元素獲焦,就會觸發。

而其本身的默認樣式又不太能被產品或者設計接受,導致了很多人會在焦點元素觸發 :focus 偽類時,通過改變 border 的顏色或者其他一些方式替代或者直接禁用。而這樣做,從可訪問性的角度來看,對于非鼠標用戶,無疑是災難性的。

基于此,在W3 CSS selectors-4 規范 中,新增了一個非常有意思的 :focus-visible 偽類。

:focus-visible:這個選擇器可以有效地根據用戶的輸入方式(鼠標 vs 鍵盤)展示不同形式的焦點。

有了這個偽類,就可以做到,當用戶使用鼠標操作可聚焦元素時,不展示 :focus 樣式或者讓其表現較弱,而當用戶使用鍵盤操作焦點時,利用 :focus-visible,讓可獲焦元素獲得一個較強的表現樣式。

看個簡單的 Demo:

<button>Test 1</button>
button:active {
  background: #eee;
}
button:focus {
  outline: 2px solid red;
}

使用鼠標點擊:

a11y3

可以看到,使用鼠標點擊的時候,觸發了元素的 :active 偽類,也觸發了 :focus偽類,不太美觀。但是如果設置了 outline: none 又會使鍵盤用戶的體驗非常糟糕。嘗試使用 :focus-visible 偽類改造一下:

button:active {
  background: #eee;
}
button:focus {
  outline: 2px solid red;
}
button:focus:not(:focus-visible) {
  outline: none;
}

看看效果,分別是在鼠標點擊 Button 和使用鍵盤控制焦點點擊 Button:

a11y4

CodePen Demo -- :focus-visible example

可以看到,使用鼠標點擊,不會觸發 :foucs,只有當鍵盤操作聚焦元素,使用 Tab 切換焦點時,outline: 2px solid red 這段代碼才會生效。

這樣,我們就既保證了正常用戶的點擊體驗,也保證了一批無法使用鼠標的用戶的焦點管理體驗。

值得注意的是,有同學會疑惑,這里為什么使用了 :not 這么繞的寫法而不是直接這樣寫呢:

button:focus {
  outline: unset;
}
button:focus-visible {
  outline: 2px solid red;
}

為的是兼容不支持 :focus-visible 的瀏覽器,當 :focus-visible 不兼容時,還是需要有 :focus 偽類的存在。

使用 WAI-ARIA 規范增強語義 -- div 等非可獲焦元素模擬獲焦元素

還有一個非常需要注意的點。

現在很多前端同學在前端開發的過程中,喜歡使用非可獲焦元素模擬獲焦元素,譬如:

  • 使用 div 模擬 button 元素
  • 使用 ul 模擬下拉列表 select 等等

當下很多組件庫都是這樣做的,譬如 element-ui 和 ant-design。

在使用非可獲焦元素模擬獲焦元素的時候,一定要注意,不僅僅只是外觀長得像就完事了,其行為表現也需要符合原本的 button、select 等可聚焦元素的性質,能夠體現元素的語義,能夠被聚焦,能夠通過 Tab 切換等等。

基于大量類似的場景,有了 WAI-ARIA 標準,WAI-ARIA是一個為殘疾人士等提供無障礙訪問動態、可交互Web內容的技術規范。

簡單來說,它提供了一些屬性,增強標簽的語義及行為:

  • 可以使用 tabindex 屬性控制元素是否可以聚焦,以及它是否/在何處參與順序鍵盤導航
  • 可以使用 role 屬性,來標識元素的語義及作用,譬如使用 <div id="saveChanges" tabindex="0" role="button">Save</div> 來模擬一個按鈕
  • 還有大量的 aria-* 屬性,表示元素的屬性或狀態,幫助我們進一步地識別以及實現元素的語義化,優化無障礙體驗

使用工具查看標簽的語義

我們來看看 Github 頁面是如何定義一個按鈕的,以 Github Issues 頁面的 Edit 按鈕為例子:

image

這一塊,清晰的描述了這個按鈕在可訪問性相關的一些特性,譬如 Contrast 色彩對比度,按鈕的描述,也就是 Name,是給屏幕閱讀器看到的,Role 標識是這個元素的屬性,它是一個按鈕,Keyboard focusable 則表明他能否被鍵盤的 Tab 按鈕給捕獲。

分析使用非可聚焦元素模擬的按鈕

這里,我隨便選取了我們業務中一個使用 span 模擬按鈕的場景,是一個面包屑導航,點擊可進行跳轉,發現慘不忍睹:

image

HTML 代碼:

<span class="ssc-breadcrumb-item-link"> Inbound </span>

image

基本上可訪問性為 0,作為一個按鈕,它不可被聚焦,無法被鍵盤用戶選中,沒有具體的語義,色彩對比度太低,可能視障用戶無法看清。并且,作為一個能進行頁面跳轉的按鈕,它沒有不是 a 標簽,沒有 href 屬性。

即便對于面包屑導航,我們可以不將它改造成 <a> 標簽,也需要做到最基本的一些可訪問性改造:

<span role="button" aria-label="goto inbound page" tabindex="0" class="ssc-breadcrumb-item-link"> Inbound </span>

不要忘了再改一下顏色,達到最低色彩對比度以上,再看看:

image

OK,這樣,一個最最最基本的,滿足最低可訪問性需求的按鈕算是勉強達標,當然,這個按鈕可以再更進一步進行改造,涉及了更深入的可訪問性知識,本文不深入展開。

分析組件庫的 A11Y

最后,在我們比較常用的 Vue - element-ui、React - ant-design 中,我們來看看 ant-design 在提升可訪問性相關的一些功能。

以 Select 選擇框組件為例,ant-design 利用了大量的 WAI-ARIA 屬性,使得用 div 模擬的下拉框不僅僅在表現上符合一個下拉框,在語義、行為上都符合一個下拉框,簡單的一個例子:

image

看看使用 div 模擬下拉框的 DOM 部分:

image

再看看在交互體驗上:

a11y5

上述操作全是在鍵盤下完成,看著平平無奇,實際上組件庫在正常響應可獲焦元素切換的同時,給用 div 模擬的 select 加了很多鍵盤事件的響應,可以利用回車,上下鍵等對可選項進行選擇。其實是下了很多功夫。

對于 A11Y 相關的內容,篇幅及內容非常之多,本文無法一一展開,感興趣的可以通讀下下列文章:

總結一下

本文從頁面展示、交互細節、可訪問性三個大方面入手,羅列一些在實際的開發過程中,積攢的一些有益的經驗。雖然不夠全面,不過從一開始也就沒想著大而全,主要是一些可能有用但是容易被忽視的點,也算是一個不錯的查缺補漏小指南。

當然,很多都是我個人的觀點想法,可能有一些理解存在一些問題,一些概念沒有解讀到位,也希望大家幫忙指出。

最后

本文到此結束,希望對你有幫助 :)

想 Get 到最有意思的 CSS 資訊,千萬不要錯過我的公眾號 -- iCSS前端趣聞 ??

gzh_small.png

更多精彩 CSS 技術文章匯總在我的 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。

如果還有什么疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

查看原文

贊 52 收藏 35 評論 7

chokcoco 發布了文章 · 2月20日

使用 mask 實現視頻彈幕人物遮罩過濾

經??匆恍?LOL 比賽直播的小伙伴,肯定都知道,在一些彈幕網站(Bilibili、虎牙)中,當人物與彈幕出現在一起的時候,彈幕會“巧妙”的躲到人物的下面,看著非常的智能。

簡單的一個截圖例子:

image

其實,這里是運用了 CSS 中的 MASK 屬性實現的。

mask 簡單用法介紹

之前在多篇文章都提到了 mask,比較詳細的一篇是 -- 奇妙的 CSS MASK,本文不對 mask 的基本概念做過多講解,向下閱讀時,如果對一些 mask 的用法感到疑惑,可以再去看看。

這里只簡單介紹下 mask 的基本用法:

最基本,使用 mask 的方式是借助圖片,類似這樣:

{
    /* Image values */
    mask: url(mask.png);                       /* 使用位圖來做遮罩 */
    mask: url(masks.svg#star);                 /* 使用 SVG 圖形中的形狀來做遮罩 */
}

當然,使用圖片的方式后文會再講。借助圖片的方式其實比較繁瑣,因為我們首先還得準備相應的圖片素材,除了圖片,mask 還可以接受一個類似 background 的參數,也就是漸變。

類似如下使用方法:

{
    mask: linear-gradient(#000, transparent)                      /* 使用漸變來做遮罩 */
}

那該具體怎么使用呢?一個非常簡單的例子,上述我們創造了一個從黑色到透明漸變色,我們將它運用到實際中,代碼類似這樣:

下面這樣一張圖片,疊加上一個從透明到黑色的漸變,

{
    background: url(image.png) ;
    mask: linear-gradient(90deg, transparent, #fff);
}

image

應用了 mask 之后,就會變成這樣:

image

這個 DEMO,可以先簡單了解到 mask 的基本用法。

這里得到了使用 mask 最重要結論:添加了 mask 屬性的元素,其內容會與 mask 表示的漸變的 transparent 的重疊部分,并且重疊部分將會變得透明。

值得注意的是,上面的漸變使用的是 linear-gradient(90deg, transparent, #fff),這里的 #fff 純色部分其實換成任意顏色都可以,不影響效果。

CodePen Demo -- 使用 MASK 的基本使用

使用 mask 實現人物遮罩過濾

了解了 mask 的用法后,接下來,我們運用 mask,簡單實現視頻彈幕中,彈幕碰到人物,自動被隱藏過濾的例子。

首先,我簡單的模擬了一個召喚師峽谷,以及一些基本的彈幕:

mask1

方便示意,這里使用了一張靜態圖,表示了召喚師峽谷的地圖,并非真的視頻,而彈幕則是一條一條的 <p> 元素,和實際情況一致。偽代碼大概是這樣:

<!-- 地圖 -->
<div class="g-map"></div>
<!-- 包裹所有彈幕的容器 -->
<div class="g-barrage-container">
    <!-- 所有彈幕 -->
    <div class="g-barrage">6666</div>
    ...
    <div class="g-barrage">6666</div>
</div>

為了模擬實際情況,我們再用一個 div 添加一個實際的人物,如果不做任何處理,其實就是我們看視頻打開彈幕的感受,人物被視頻所遮擋:

mask2

注意,這里我添加了一個人物亞索,并且用 animation 模擬了簡單的運動,在運動的過程中,人物是被彈幕給遮擋住的。

接下來,就可以請出 mask 了。

我們利用 mask 制作一個 radial-gradient ,使得人物附近為 transparent,并且根據人物運動的 animation,給 mask 的 mask-position 也添加上相同的 animation 即可。最終可以得到這樣的效果:

.g-barrage-container {
    position: absolute;
    mask: radial-gradient(circle at 100px 100px, transparent 60px, #fff 80px, #fff 100%);
    animation: mask 10s infinite alternate;
}

@keyframes mask {
    100% {
        mask-position: 85vw 0;
    }
}

mask3

實際上就是給放置彈幕的容器,添加一個 mask 屬性,把人物所在的位置標識出來,并且根據人物的運動不斷的去變換這個 mask 即可。我們把 mask 換成 background,原理一看就懂。

  • 把 mask 替換成 background 示意圖:

mask4

background 透明的地方,即 mask 中為 transparent 的部分,實際就是彈幕會被隱藏遮罩的部分,而其他白色部分,彈幕不會被隱藏,正是完美的利用了 mask 的特性。

其實這項技術和視頻本身是無關的,我們只需要根據視頻計算需要屏蔽掉彈幕的位置,得到相應的 mask 參數即可。如果去掉背景和運動的人物,只保留彈幕和 mask,是這樣的:

mask6

需要明確的是,使用 mask,不是將彈幕部分給遮擋住,而是利用 mask,指定彈幕容器之下,哪些部分正常展示,哪些部分透明隱藏。

最后,完整的 Demo 你可以戳這里:

CodePen Demo -- mask 實現彈幕人物遮罩過濾

實際生產環境中的運用

當然,上面我們簡單的還原了利用 mask 實現彈幕遮罩過濾的效果。但是實際情況比上述的場景復雜的多,因為人物英雄的位置是不確定的,每一刻都在變化。所以在實際生產環境中,mask 圖片的參數,其實是由后端實時對視頻進行處理計算出來的,然后傳給前端,前端再進行渲染。

對于運用了這項技術的直播網站,我們可以審查元素,看到包裹彈幕的容器的 mask 屬性,每時每刻都在發生變化:

mask5

返回回來的其實是一個 SVG 圖片,大概長這個樣子:

image

這樣,根據視頻人物的實時位置變化,不斷計算新的 mask,再實時作用于彈幕容器之上,實現遮罩過濾。

最后

本文到此結束,希望對你有幫助 :),本文介紹了 CSS mask 的一個實際生產環境中,非常有意義的一次實踐,也表明很多新的 CSS 技術,運用得當,還是能給業務帶來非常有益的幫助的。

想 Get 到最有意思的 CSS 資訊,千萬不要錯過我的公眾號 -- iCSS前端趣聞 ??

gzh_small.png

更多精彩 CSS 技術文章匯總在我的 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。

如果還有什么疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

查看原文

贊 46 收藏 23 評論 7

chokcoco 發布了文章 · 2月5日

CSS奇思妙想 -- 使用 background 創造各種美妙的背景

本文屬于 CSS 繪圖技巧其中一篇,系列文章:

將介紹一些利用 CSS 中的 background、mix-blend-mode、mask 及一些相關屬性,制作一些稍微復雜、酷炫的背景。

通過本文,你將會了解到 CSS background 中更為強大的一些用法,并且學會利用 background 相關的一些屬性,采用不同的方式,去創造更復雜的背景圖案。在這個過程中,你會更好的掌握不同的漸變技巧,更深層次的理解各種不同的漸變。

同時,借助強大的 CSS-Doodle,你將學會如何運用一套規則,快速創建大量不同的隨機圖案,感受 CSS 的強大,走進 CSS 的美。

背景基礎知識

我們都知道,CSS 中的 background 是非常強大的。

首先,復習一下基礎,在日常中,我們使用最多的應該就是下面 4 種:

  • 純色背景 background: #000

  • 線性漸變 background: linear-gradient(#fff, #000) :

  • 徑向漸變 background: radial-gradient(#fff, #000) :

  • 角向漸變 background: conic-gradient(#fff, #000) :

背景進階

當然。掌握了基本的漸變之后,我們開始向更復雜的背景圖案進發。我最早是在《CSS Secret》一書中接觸學習到使用漸變去實現各種背景圖案的。然后就是不斷的摸索嘗試,總結出了一些經驗。

在嘗試使用漸變去制作更復雜的背景之前,列出一些比較重要的技巧點:

  • 漸變不僅僅只能是單個的 linear-gradient 或者單個的 radial-gradient,對于 background 而言,它是支持多重漸變的疊加的,一點非常重要;
  • 靈活使用 repeating-linear-gradeintrepeating-radial-gradeint),它能減少很多代碼量
  • transparent 透明無處不在
  • 嘗試 mix-blend-modemask,創建復雜圖案的靈魂
  • 使用隨機變量,它能讓一個 idea 變成無數美麗的圖案

接下來,開始組合之旅。

使用 mix-blend-mode

mix-blend-mode ,混合模式。最常見于 photoshop 中,是 PS 中十分強大的功能之一。在 CSS 中,我們可以利用混合模式將多個圖層混合得到一個新的效果。

關于混合模式的一些基礎用法,你可以參考我的這幾篇文章:

然后,我們來嘗試第一個圖案,先簡單體會一下 mix-blend-mode 的作用。

我們使用 repeating-linear-gradient 重復線性漸變,制作兩個角度相反的背景條紋圖。正常而言,不使用混合模式,將兩個圖案疊加在一起,看看會發生什么。

額,會發生什么就有鬼了 。顯而易見,由于圖案不是透明的,疊加在一起之后,由于層疊的關系,只能看到其中一張圖。

好,在這個基礎上,我們給最上層的圖案,添加 mix-blend-mode: multiply,再來一次,看看這次會發生什么。

可以看到,添加了混合模式之后,兩張背景圖通過某種算法疊加在了一起,展現出了非常漂亮的圖案效果,也正是我們想要的效果。

CodePen Demo - Repeating-linear-gradient background & mix-blend-mode

嘗試不同的 mix-blend-mode

那為什么上面使用的是 mix-blend-mode: multiply 呢?用其他混合模式可以不可以?

當然可以。這里僅僅只是一個示例,mix-blend-mode: multiply 在 PS 中意為正片疊底,屬于圖層混合模式的變暗模式組之一。

我們使用上面的 DEMO,嘗試其他的混合模式,可以得到不同的效果。

可以看到,不同的混合模式的疊加,效果相差非常之大。當然,運用不同的混合模式,我們也就可以創造出效果各異的圖案。

CodePen Demo - Repeating-linear-gradient background & mix-blend-mode

借助 CSS-Doodle 隨機生成圖案

到這,就不得不引出一個寫 CSS 的神器 -- CSS-Doodle,我在其他非常多文章中也多次提到過 CSS-doodle,簡單而言,它是一個基于 Web-Component 的庫。允許我們快速的創建基于 CSS Grid 布局的頁面,并且提供各種便捷的指令及函數(隨機、循環等等),讓我們能通過一套規則,得到不同 CSS 效果。

還是以上面的 DEMO 作為示例,我們將 repeating-linear-gradient 生成的重復條紋背景的顏色、粗細、角度隨機化、采用的混合模式也是隨機選取,然后利用 CSS-Doodle,快速隨機的創建各種基于此規則的圖案:

可以點進去嘗試一下,點擊鼠標即可隨機生成不同的效果:

CodePen Demo -- CSS Doodle - CSS MIX-BLEND-MODE Background

嘗試使用徑向漸變

當然,上面使用的是線性漸變,同樣,我們也可以使用徑向漸變運用同樣的套路。

我們可以使用徑向漸變,生成多重的徑向漸變。像是這樣:

給圖片應用上 background-size,它就會像是這樣:

像上文一樣,我們稍微對這個圖形變形一下,然后疊加兩個圖層,給最上層的圖形,添加 CSS 樣式 mix-blend-mode: darken

CodePen Demo -- radial-gradient & mix-blend-mode Demo

借助 CSS-Doodle 隨機生成圖案

再來一次,我們使用 CSS-Doodle,運用上述的規則在徑向漸變,也可以得到一系列有意思的背景圖。

可以點進去嘗試一下,點擊鼠標即可隨機生成不同的效果:

CodePen Demo -- CSS Doodle - CSS MIX-BLEND-MODE Background 2

當然,上述的疊加都是非常簡單的圖案的疊加,但是掌握了這個原理之后,就可以自己嘗試,去創造更復雜的融合。

上述的疊加效果是基于大片大片的實色的疊加,當然 mix-blend-mode 還能和真正的漸變碰撞出更多的火花。

在不同的漸變背景中運用混合模式

在不同的漸變背景中運用混合模式?那會產生什么樣美妙的效果呢?

運用得當,它可能會像是這樣:

umm,與上面的條紋圖案完全不一樣的風格。

你可以戳進 gradienta.io 來看看,這里全是使用 CSS 創建的漸變疊加的背景圖案庫。

使用混合模式疊加不同的漸變圖案

下面,我們也來實現一個。

首先,我們使用線性漸變或者徑向漸變,隨意創建幾個漸變圖案,如下所示:

接著,我們兩兩之間,從第二層開始,使用一個混合模式進行疊加,一共需要設定 5 個混合模式,這里我使用了 overlay, multiply, difference, difference, overlay??纯疮B加之后的效果,非常的 Nice:

CodePen Demo -- Graideint background mix

由于上面動圖 GIF 的壓縮率非常高,所以看上去鋸齒很明顯圖像很模糊,你可以點進上面的鏈接看看。

然后,我們可以再給疊加后的圖像再加上一個 filter: hue-rotate(),讓他動起來,放大一點點看看效果,絢麗奪目的光影效果:

CodePen Demo -- Graideint background mix 2

借助 CSS-Doodle 隨機生成圖案

噔噔噔,沒錯,這里我們又可以繼續把 CSS-Doodle 搬出來了。

隨機的漸變,隨機的混合模式,疊加在一起,燥起來吧。

使用 CSS-Doodle 隨機創建不同的漸變,在隨機使用不同的混合模式,讓他們疊加在一起,看看效果:

當然,由于是完全隨機生成的效果,所以部分時候生成出來的不算太好看或者直接是純色的。不過大部分還是挺不錯的

CodePen Demo -- CSS Doodle Mix Gradient


感謝堅持,看到這里。上述上半部分主要使用的混合模式,接下來,下半部分,將主要使用 mask,精彩繼續。


使用 mask

除去混合模式,與背景相關的,還有一個非常有意思的屬性 -- MASK。

mask 譯為遮罩。在 CSS 中,mask 屬性允許使用者通過遮罩或者裁切特定區域的圖片的方式來隱藏一個元素的部分或者全部可見區域。

對 mask 的一些基礎用法還不太熟悉的,可以先看看我的這篇文章 -- 奇妙的 CSS MASK。

簡單而言,mask 可以讓圖片我們可以靈活的控制圖片,設定一部分展示出來,另外剩余部分的隱藏。

使用 mask 對圖案進行切割

舉個例子。假設我們使用 repeating-linear-gradient 漸變制作這樣一個漸變圖案:

它的 CSS 代碼大概是這樣:

:root {
    $colorMain: #673ab7;
}
{
    background: 
        repeating-linear-gradient(0, $colorSub 0, $colorSub 3px, transparent 3px, transparent 10px),
        repeating-linear-gradient(60deg, $colorSub 0, $colorSub 3px, transparent 3px, transparent 10px),
        repeating-linear-gradient(-60deg, $colorSub 0, $colorSub 3px, transparent 3px, transparent 10px);
}

如果我們給這個圖案,疊加一個這樣的 mask :

{
    mask: conic-gradient(from -135deg, transparent 50%, #000);
}

上述 mask 如果是使用 background 表示的話,是這樣 background: conic-gradient(from -135deg, transparent 50%, #000), 圖案是這樣:

兩者疊加在一起,按照 mask 的作用,背景與 mask 生成的漸變的 transparent 的重疊部分,將會變得透明。將會得到這樣一種效果:

CodePen Demo -- mask & background Demo

我們就完成了 background 與 mask 的結合。運用 mask 切割 background 的效果,我們就能制作出非常多有意思的背景圖案:

CodePen Demo -- mask & background Demo

mask-composite OR -webkit-mask-composite

接下來,在運用 mask 切割圖片的同時,我們會再運用到 -webkit-mask-composite 屬性。這個是非常有意思的元素,非常類似于 mix-blend-mode / background-blend-mode。

-webkit-mask-composite: 屬性指定了將應用于同一元素的多個蒙版圖像相互合成的方式。

通俗點來說,他的作用就是,當一個元素存在多重 mask 時,我們就可以運用 -webkit-mask-composite 進行效果疊加。

注意,這里的一個前提,就是當 mask 是多重 mask 的時候(類似于 background,mask 也是可以存著多重 mask),-webkit-mask-composite 才會生效。這也就元素的 mask 可以指定多個,逗號分隔。

假設我們有這樣一張背景圖:

:root {
    $colorMain: #673ab7;
    $colorSub: #00bcd4;
}
div {
    background: linear-gradient(-60deg, $colorMain, $colorSub);
}

我們的 mask 如下:

{
    mask: 
            repeating-linear-gradient(30deg, #000 0, #000 10px, transparent 10px, transparent 45px),
            repeating-linear-gradient(60deg, #000 0, #000 10px, transparent 10px, transparent 45px),
            repeating-linear-gradient(90deg, #000 0, #000 10px, transparent 10px, transparent 45px);
}

mask 表述成 background 的話大概是這樣:

如果,不添加任何 -webkit-mask-composite,疊加融合之后的效果是這樣:

如果添加一個 -webkit-mask-composite: xor,則會變成這樣:

可以看到,線條的交匯疊加處,有了不一樣的效果。

CodePen Demo -- background & -webkit-mask-composite

借助 CSS-Doodle 隨機生成圖案

了解了基本原理之后,上 CSS-Doodle,我們利用多重 mask 和 -webkit-mask-composite,便可以創造出各式各樣的美妙背景圖案:

是不是很類似萬花筒?

借助了 CSS-Doodle,我們只設定大致的規則,輔以隨機的參數,隨機的大小。接著就是一幅幅美妙的背景圖應運而生。

下面是運用上述規則的嘗試的一些圖案:

CodePen Demo -- CSS Doodle - CSS MASK Background

當然,可以嘗試變換外形,譬如讓它長得像個手機殼。

下面兩個 DEMO 也是綜合運用了上述的一些技巧的示例,仿佛一個個手機殼的圖案。

CodePen Demo -- CSS Doodle - CSS MASK Background 2

CodePen Demo -- CSS Doodle - CSS MASK Background 3

總結一下

背景 background 不僅僅只是純色、線性漸變、徑向漸變、角向漸變?;旌夏J?、濾鏡、遮罩也并不孤獨。

background 配合混合模式 mix-blend-mode,background-blend-mode、濾鏡 filter、以及遮罩 mask 的時候,它們就可以組合變幻出各種不同的效果。

到目前為止,CSS 已經越來越強大,它不僅僅可以用于寫業務,也可以創造很多有美感的事物,只要我們愿意去多加嘗試,便可以創造出美妙的圖案。

最后

好了,本文到此結束,看到這里,你是不是也躍躍欲試?想自己親手嘗試一下?

想 Get 到最有意思的 CSS 資訊,千萬不要錯過我的公眾號 -- iCSS前端趣聞 ??

更多精彩 CSS 技術文章匯總在我的 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。

如果還有什么疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

查看原文

贊 22 收藏 14 評論 2

chokcoco 發布了文章 · 2月1日

你可能不知道的 transition 技巧與細節

CSS 中,transition 屬性用于指定為一個或多個 CSS 屬性添加過渡效果。

最為常見的用法,也就是給元素添加一個 transition,讓其某個屬性從狀態 A 變化到狀態 B 時,不再是非常直接突兀,而是帶有一個補間動畫。

舉個例子:

<div></div>
div {
    width: 140px;
    height: 64px;
    transition: .8s transform linear;
}
div:hover {
    transform: translate(120px, 0);
}

當然,除了上述基本的用法,其實 CSS transition 還有一些非常有意思的細節和有趣的用法。下面讓我一一娓娓道來。

并非所有屬性都支持 transition

并非所有屬性都支持 transition。和 animation 類似,這里有一個列表,列出了所有支持 transition 的屬性 -- CSS animated properties

當然,有的時候,還有更例外的。某些支持 transition 的屬性在某些特定狀態下,也是不支持 transition 的。非常典型的就是 height: autowidth: auto。

CSS 奇技淫巧:動態高度過渡動畫 一文中,提到了這樣一個場景:

元素的動態高度過渡動畫失效,偽代碼大概是這樣:

{
    height: unset;
    transition: height 0.3s linear;

    &.up {
        height: 0;
    }
    &.down {
        height: unset;
    }
}

明明給 height 屬性設置了 transition,但是過渡動畫沒有觸發,而是直接一步到位展開:

原因在于, CSS transtion 不支持元素的高度或者寬度為 auto 的變化。

對于這種場景,我們可以使用 max-height 進行 hack。

這里有一個非常有意思的小技巧。既然不支持 height: auto,那我們就另辟蹊徑,利用 max-height 的特性來做到動態高度的伸縮,譬如:

{
    max-height: 0;
    transition: max-height 0.3s linear;

    &.up {
        max-height: 0;
    }
    &.down {
        max-height: 1000px;
    }
}

具體的詳情你可以看看 -- CSS 奇技淫巧:動態高度過渡動畫。

transition 可以精細化控制每一個屬性

繼續。在 transition 中,我們可以使用 transition: all 1s linear 這樣,統一給元素下面的所有支持過渡的屬性添加過渡效果(時間及緩動函數)。

同時,我們也可以分別精細化控制每一個屬性:

{
    // 可以這樣
    transition: all 1s linear;

    // 也可以這樣
    transition: height 1s linear, transform 0.5s ease-in, color 2s ease-in-out;
}

并且,和動畫類似,每一個過渡都是支持延遲觸發的:

div {
    // 延遲 1s 觸發過渡,過渡動畫的時間為 0.8 秒
    transition: .8s transform 1s linear;
}
div:hover {
    transform: translate(120px, 0);
}

可以看到不管是過渡觸發,還是過渡復位,都會等待 1 秒再觸發。

利用這個技巧,我們就可以實現一些過渡效果的結合。首先我們實現這樣一個寬高變化的過渡動畫:

<div></div>
div {
    position: relative;
    width: 200px;
    height: 64px;
    box-shadow: inset 0 0 0 3px #ddd;
}
div::before {
    content: "";
    position: absolute;
    width: 0;
    height: 0;
    top: 0; left: 0; width: 0; height: 0;
    box-sizing: border-box;
    transition: width .25s, height .25s, border-bottom-color;
    transition-delay: .25s, 0s, .25s;
}
div:hover::before {
    width: 200px;
    height: 64px;
    border-left: 3px solid #00e2ff;
    border-bottom: 3px solid #00e2ff;
}

我們分別控制元素的偽元素的高度、寬度、及下邊框的變化,并且給寬度過渡動畫和下邊框的顏色動畫設置了 0.25 秒的延遲,這樣元素的高度會先進行過渡,由于整體的過渡動畫世界時間也是 0.25s,所以高度過渡動畫結束后,才會開始寬度過渡動畫,下邊框也才會出現顏色變化。

這樣就能把他們的過渡動畫銜接在一起,體現到元素的 border 之上,看看效果:

利用同樣的原理,我們再把元素的另外一個偽元素也利用上,但是他們的動畫世界,整體需要再全部加上 0.5 秒,等到上述的過渡動畫執行完畢后才執行:

div::after {
    right: 0;
    bottom: 0;
}
div:hover::after{
    transition: height .25s, width .25s, border-top-color .25s;
    transition-delay: 0.5s, 0.75s, 0.75s;
    width: 200px;
    height: 64px;
    border-top: 3px solid #00e2ff;
    border-right: 3px solid #00e2ff;
}

這樣,我們可以把兩個偽元素的過渡動畫合并,得到一個完整的 border 動畫如下:

完整的 Demo 你可以戳這里:CodePen Demo -- 借助 transition-delay 實現按鈕 border 動畫效果

所以,合理控制每一個屬性,就能組合得到各種有趣的效果。

動態改變 transition-duration

還有一個非常有意思的技巧,我們可以利用元素的一些偽類,動態的去改變元素的 transition-duration。

舉個例子:

div {
    width: 140px;
    height: 64px;
    border: 2px solid red;
    transition: 3s all linear;
}
div:hover {
    transition-duration: .5s; 
    border: 2px solid blue;
}

當鼠標 hover 元素時,將元素的過渡動畫的持續時間 transition-duration 從 3s 改成 0.5s,這樣可以做到元素 hover 的時候,過渡動畫持續的時間是 0.5s,但是過渡復位的持續時間卻是 3s:

利用這個小技巧,我們嘗試制作一些有意思的效果。

純 CSS 實現的簽名板

利用上述的,小技巧,我們可以實現一個純 CSS 的簽名板。

首先,在高寬都為 500px 的容器中,實現一個 100x100 的 HTML 網格布局,利用 flex、grid 都行,這里為了方便,我借助了 Pug 模板引擎。

div.g-box
    -for(var i=0; i<100; i++)
        div.g-row
            -for(var j=0; j<100; j++)
                div.g-item

為了方便示意,我把每個格子加了個 border,實際上,背景和格子都是白色的:

為了實現簽名的效果,我們給每個格子 g-item 加上 hover 事件,hover 時改變當前格子背景色。同時,最重要的是,**在正常狀態設置一個非常大的 transition-duration,而在 hover 的時候,設置一個非常小的 transition-duration,偽代碼如下:

.g-item {
    transition: 999999s;
}
.g-item:hover {
    background: #000;
    transition: 0s;
}

看看效果:

這樣就實現了,鼠標 hover 上去的時候,因為 transition: 0s 的緣故,背景色被快速的改變,而當 hover 效果離開, transition: 999999s 重新生效,黑色則會以一個非常非常慢的速度失效,以至于慢到感受不到它在發生變化。

當然,要實現簽名的話,目前來看還欠缺點什么,我們需要實現鼠標 hover 到畫板上不會立即開始出發元素的背景色變化,只有鼠標按下時(保持 :active 狀態),才開始遵循鼠標軌跡改變顏色。當鼠標停止點擊,則停止畫畫。

這個有個巧妙的方法可以實現,我們在畫布上,再疊加一層 div,層級 z-index 比畫布更高,當鼠標 hover 到畫布上,其實是 hover 到這個遮罩層上,當鼠標按下,觸發 :active 事件時,給元素添加一個 :activce 事件,將遮罩層移除即可。

偽代碼如下:

div.g-wrap
div.g-box
    -for(var i=0; i<100; i++)
        div.g-row
            -for(var j=0; j<100; j++)
                div.g-item
.g-wrap {
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    z-index: 10;

    &:active {
        display: none;
    }
}

這樣,一個完整的簽名板,或者說是畫板就實現了:

完整的代碼實現,并且利用 CSS 添加上了 reset 功能,你可以戳這里:CodePen Demo -- Pure CSS signature

利用這個技巧,其實就可以用 CSS 實現追隨鼠標軌跡的功能(雖然很雞肋>_<),我們再可以和其他很多屬性混合起來,譬如混合模式和濾鏡。

像是這樣,來自好友 alphardex 的一個效果,利用了上述技巧,疊加了混合模式和濾鏡實現:

CodePen Demo -- Snow Scratch

最后

本文到此結束,希望對你有幫助 :),想 Get 到最有意思的 CSS 資訊,千萬不要錯過我的公眾號 -- iCSS前端趣聞 ??

更多精彩 CSS 技術文章匯總在我的 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。

如果還有什么疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

查看原文

贊 20 收藏 10 評論 0

chokcoco 發布了文章 · 1月27日

CSS奇思妙想 -- 使用 CSS 創造藝術

本文屬于 CSS 繪圖技巧其中一篇。之前有過一篇:在 CSS 中使用三角函數繪制曲線圖形及展示動畫

想寫一篇關于 CSS 創造藝術的文章已久,本文主要介紹如何借助 CSS-doodle ,利用 CSS 快速創造美妙的 CSS 圖形。

中心布局

本文的所有技巧都會圍繞這個布局展開,屬于一類技巧。

首先,我們需要這樣一種中心布局。簡單的 HTML 結構如下:

<div class="g-container">
    <div class="g-box"></div>
    <div class="g-box"></div>
    <div class="g-box"></div>
    <div class="g-box"></div>
    <div class="g-box"></div>
</div>
.g-container {
    position: relative;
    width: 300px;
    height: 300px;
}
.g-box {
    position: absolute;
    top:50%;
    left: 50%;
    margin-left: -150px;
    margin-top: -150px;
    width: 100%;
    height: 100%;
    border: 1px solid #000;
}

利用絕對定位和 margin,將元素全部水平垂直居中疊在一起(因為后面會用到 transform,所以選取了這種水平垂直居中的方式),結果如下:

好吧,看著平平無奇,但是基于這種布局,我們可以衍生出非常多有意思的圖案。

改變元素大小

最簡單的,就是我們可以改變元素的大小。

CSS 代碼寫著太累,所以我們簡單的借助 pug HTML 模板引擎和 SASS。

div.g-container
    -for(var i=0; i<10; i++)
        div.g-box  
$count: 10;
@for $i from 1 to $count + 1 {
    .g-box:nth-child(#{$i}) {
        --width: #{$i * 30}px;
        width: var(--width);
        height: var(--width);
        margin-left: calc(var(--width) / -2);
        margin-top: calc(var(--width) / -2);
    }
}

容器下包含 10 個子元素,每個子元素大小逐漸遞增,很容易得到如下結果:

改變元素顏色

接著,我們繼續改變元素的顏色,讓它呈現漸變顏色逐級遞進,可以是邊框顏色

@for $i from 1 to $count + 1 {
    .g-box:nth-child(#{$i}) {
         ...
         border-color: hsla(
            calc(#{$i * 25}),
            50%,
            65%,
            1
        );
    }
}

得到這樣的效果:

也可以是改變背景 background 的顏色:

@for $i from 1 to $count + 1{
    .g-box:nth-child(#{$i}) {
        ...
        background: hsla(
            calc(#{$i * 25}),
            50%,
            65%,
            1
        );
        z-index: #{$count - $i};
    }
}

改變元素角度

好,接下來,就可以開始變換角度了,我們利用 transform,將元素旋轉不同的角度:

@for $i from 1 to $count + 1{
    .g-box:nth-child(#{$i}) {
        ....
        transform: rotate(#{$i * 7}deg);
    }
}

效果如下:

CodePen Demo -- CSS Pattern

OK,到這里,基本的一些概念就引入的差不多了,總而言之,利用多元素居中布局,改變元素的大小、顏色、透明度、角度、陰影、濾鏡、混合模式等等等等,只要你能想到的,都可以。

接下來,我們再引入本文的另外一個主角 -- CSS-doodle 。

CSS-doodle 是一個基于 Web-Component 的庫。允許我們快速的創建基于 CSS Grid 布局的頁面,以實現各種 CSS 效果(或許可以稱之為 CSS 藝術)。

其最終效果的代碼,本質是都還是 CSS。具體的一些概念可以點擊主頁看看,一看就懂。

使用 CSS-doole 實現多元素水平垂直居中布局

我們將上面的布局利用 CSS-doodle 再實現一次,要實現 50個元素的居中對齊,只需要如下簡單的聲明即可:

<css-doodle>
    :doodle {
        @grid: 1x50 / 100vmin;
    }
    @place-cell: center;
</css-doodle>

上面的意思大概是,在 100vmin x 100vmin 大小的容器下,聲明一個 1x50 的 grid 網格布局,利用 @place-cell: center 將它們全部水平垂直居中,也就是會疊加在一起。

這樣可能看不出效果,我們再給每個元素設置不同的大小,給它們都加上一個簡單的 border

<css-doodle>
    :doodle {
        @grid: 1x50 / 100vmin;
    }
    @place-cell: center;
    @size: calc(100% - @calc(@index() - 1) * 2%);
    border: 1px solid #000;
</css-doodle>
  • @size: calc(100% - @calc(@index() - 1) * 2%) 表示每個子元素寬高的大?。ㄒ部梢詥为氃O置高寬),@index 是個變量,表示當前元素的序號,從 1 - 50,表示沒個元素分別為容器的 2% 高寬、4% 高寬一直到 100% 高寬。
  • border: 1px solid #000 就是正常的 CSS 代碼,里面沒有變量,作用于每一個元素

效果如下:

Oh No,眼睛開始花了。這樣,我們就快速的實現了前面鋪墊時候利用 HTML 代碼和繁瑣的 CSS 生成的圖形效果。

CSS 藝術

接下來,就開始美妙的 CSS 藝術。

改變元素的旋轉角度及邊框顏色

我們利用上述代碼繼續往下,為了更好的展示效果,首先整體容器的底色改為黑色,接著改變元素的旋轉角度。每個元素旋轉 30deg x @index。

代碼非常的短,大概是這樣:

<css-doodle>
    :doodle {
        @grid: 1x100 / 100vmin;
    }
    @place-cell: center;
    @size: calc(100% - @calc(@index() - 1) * 1%);
    transform: rotate(calc(@index() * 30deg));
    border: 1px solid #fff;
</css-doodle>

不太好看,接著,我們試著給每個元素,漸進的設置不同的 border 顏色,并且透明度 opacity 逐漸降低,,這里我們會用到 hsla 顏色表示法:

<css-doodle>
    :doodle {
        @grid: 1x100 / 100vmin;
    }
    @place-cell: center;
    @size: calc(100% - @calc(@index() - 1) * 1%);
    transform: rotate(calc(@index() * 30deg));
    border: 1px solid hsla(
        calc(calc(100 - @index()) * 2.55), 
        calc(@index() * 1%), 
        50%,
        calc(@index() / 100)
    );
</css-doodle>

再看看效果:

所有貼圖都存在一定色差,可以點進 Demo 里看看~

Wow,第一幅看上去還不錯的作品出現了。

當然,每一個不同的角度,都能產生不一樣的效果,通過 CSS-doodle,可以快速生成不同隨機值,隨機產生不同的效果。我們稍微改變一下上述代碼,將 transform 那一行改一下,引入了一個隨機值:

<css-doodle>
    :doodle {
        --rotate: @r(0, 360)deg;
    }
    transform: rotate(calc(@index() * var(--rotate)));
</css-doodle>
  • 利用 @r(0, 360)deg,能隨機生成一個介于 0 到 360 之間的隨機數,后面可以直接跟上單位,也就變成了一個隨機角度值
  • transform: rotate(calc(@index() * var(--rotate))),利用 calc 規則引入隨機生成的 CSS 變量,當然,再不刷新頁面的前提下,每一次這個值都是固定的

這樣,我們每次刷新頁面,就可以得到不同的效果了(當然,CSS-doodle 做了優化,添加短短幾行代碼就可以通過點擊頁面刷新效果),改造后的效果,我們每次點擊都可以得到一個新的效果:

CodePen Demo -- CSS Doodle - CSS Magic Pattern

強烈建議你點進 Demo,自己點點鼠標感受一下 :)

background 顏色奇偶不同

好,我們再換個思路,這次不改變 border 的顏色,而是通過選擇器控制奇數序號的元素和偶數序號的元素,分別給予它們不一樣的背景色:

<css-doodle>
    :doodle {
        @grid: 1x100 / 100vmin;
    }
    @place-cell: center;
    @size: calc(100% - @calc(@index() - 1) * 1%);
    transform: rotate(calc(@index() * 60deg));

    background: rgba(0, 0, 0, calc((@index * 0.01)));
    @even {
        background: rgba(255, 255, 255, calc((@index * 0.01)));
    }
</css-doodle>

利用 @even {} 可以快速選中偶數序號的元素,然后給他賦予白色底色,而奇數元素則賦予黑色底色,看看效果:

還是一樣的思路,我們可以將隨機值賦予 transform 的旋轉角度,利用黑白疊加,看看再不同角度下,都會有什么效果:

CodePen Demo -- CSS Doodle - CSS Magic Pattern

當然,在隨機的過程中,你也可以選取自己喜歡的,將它們保留下來。

CSS-doodle 支持多種方式的引入,在一頁中展示多個圖形,不在話下,像是這樣:

CodePen Demo -- CSS-doodle Pure CSS Pattern

規律總結

小小總結一下,想要生成不同的圖案,其實只需要找到能夠生成不同線條,或者造型圖案圖形,將它們按照不同的大小,不同的旋轉角度,不同顏色及透明度疊加在一起即可。

這樣的話,一些可能的 idea:

  • 只利用單向的 border 會是怎么樣的呢?
  • 出現的 border 都是 solid,如果換成是虛線 dashed 呢?或許可以再加上 border-radius
  • text-decoration 也支持一些各式的下劃線,我們也可以利用它們試試

OK,將上述想法付諸實踐,我們就可以得到利用各式線條繪制出來的各式圖形。它們可能是這樣:

當然,每次的效果都可以做到隨機,只要我們合理利用好隨機的參數即可,你可以戳進下面的 Demo 感受一下:

CodePen Demo -- CSS-doodle Pure CSS Pattern

Clip-pathdrop-shadow

嘿,說到創造不同的線條與圖案,就不得不提 CSS 里另外兩個有意思是屬性。Clip-pathfitler: drop-shadow()。

嗯哼?什么意思呢。我們來個簡單的 Demo,利用 Clip-path ,我們可以裁剪出不同的元素造型。譬如實現一個簡單的多邊形:

div {
    width: 300px;
    height: 300px;
    clip-path: polygon(50% 0%, 90% 20%, 100% 60%, 75% 100%, 25% 100%, 0% 60%, 10% 20%);
    background: #333;
}

效果如下:

那么利用這個思路,我們就可以嘗試利用 clip-path 裁剪出各種不同的造型進行疊加。

CSS-doodle Shapes 中,內置了非常多的 clip-path 圖形供我們選擇:

我們隨機選取一個:

套用上述的規則,嘗試著實現一個圖形:

<css-doodle>
    :doodle {
        @grid: 1x100 / 100vmin;
    }
    @place-cell: center;
    @size: calc(100% - @calc(@index() - 1) * 1%);
    background: hsla(
        calc(calc(100 - @index()) * 2.55), 
        calc(@index() * 1%), 
        65%,
        calc(@index() / 100)
    );
    clip-path: @shape(
        fill-rule: evenodd;
        split: 200;
        scale: .45;
        x: cos(2t) + cos(π - 5t);
        y: sin(2t) + sin(π - 5t);
    );
</css-doodle>

這次沒有旋轉不同的角度,只是給每一層賦予不同的背景底色,能夠得到這樣的效果:

CodePen Demo -- CSS Doodle - CSS Magic Pattern

Clip-pathdrop-shadow 創造不同線條

OK,上述是利用 Clip-path 創造了不同的圖案,那不同的線條怎么得來呢?

別急。這就需要請出我們另外一個屬性 drop-shadow,利用 drop-shadow,可以給 Clip-path 裁剪出來的圖形創造不同的陰影,當然有一些結構上的限制,大概的偽代碼如下:

div {
    position: relative;
    width: 300px;
    height: 300px;
    filter: drop-shadow(0px 0px 1px black);

    &::after {
        content: "";
        position: absolute;
        width: 100%;
        height: 100%;
        left: 0;
        right: 0;
        background: #fff;
        clip-path: polygon(50% 0%, 90% 20%, 100% 60%, 75% 100%, 25% 100%, 0% 60%, 10% 20%);
    }
}

我們需要將 filter: drop-shadow(0px 0px 2px black) 作用在利用了 clip-path 的元素的父元素之上,并且,利用了 clip-path: 的元素必須帶有 background,才能給裁剪元素附上陰影效果。

上述的代碼如下:

OK,完美,這樣一來,我們就極大極大的豐富了我們的線條庫,再運用會上述的線條規則,一大波新的圖案應運而生。

CodePen Demo -- CSS-doodle Pure CSS Pattern - clip-path - drop-shadow

OK,限于篇幅,就不一一展開了,感興趣可以點進上述 Demo Fork 一份自己嘗試。還有非常多有意思的圖案等待挖掘生成。

最后,再來欣賞一下 CSS-doodle 作者,袁川袁老師利用上述技巧的作品:

CodePen Demo -- css doodle art

最后

本文到此結束,希望對你有幫助 :),想 Get 到最有意思的 CSS 資訊,千萬不要錯過我的公眾號 -- iCSS前端趣聞 ??

更多精彩 CSS 技術文章匯總在我的 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。

如果還有什么疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

查看原文

贊 13 收藏 7 評論 1

chokcoco 發布了文章 · 1月25日

生僻標簽 fieldset 與 legend 的妙用

談到 <fieldset><legend>,大部分人肯定會比較陌生,在 HTML 標簽中,屬于比較少用的那一批。

我最早知道這兩個標簽,是在早年學習 reset.css 或者 normalize.css 時,在這些重置統一代碼默認樣式的 CSS 中看到的。最近因為研究邊框,遇到了這兩個標簽,發現它們還是很有意思的,遂起一篇,將整理的一些知識點分享給大家。

了解 <fieldset><legend>

通常而言,<fieldset><legend> 比較常用在表單當中。

  • <fieldset>:HTML <fieldset> 元素用于對表單中的控制元素進行分組
  • <legend>:在 <fieldset> 中內置了一個 <legend> 元素作為 fieldset 的標題

簡單而言,fieldset 可以單獨使用,對表單的元素進行分組,而 legend 則需要和 fieldset 配套使用,成對出現,作為分組的標題。

看個簡單的例子,簡單的 HTML 及結構如下:

<fieldset>
    <legend>Form</legend>
    <div>
        <label>Name :</label><input type="text" placeholder="input Name" />
    </div>
    <div>
        <label>Password :</label><input type="text" placeholder="input Name" />
    </div>
</fieldset>
fieldset {
    border: 1px solid#ddd;
    padding: 12px;
}

legend {
    font-size: 18px;
    padding: 0 10px;
}

效果如下:

CodePen Demo -- fieldset & legend Demo

比較有意思的點在于,如果給 fieldset 設置了 border 邊框,則 legend 元素內的內容則會作為分組的標題,嵌入 border 內。

控制 legend 的位置及樣式

對于 legend 的位置和樣式,是可以進行控制的。

對于位置,我們可以通過 margin 和 父元素的 padding 進行控制,如果父元素 fieldset 不設置 padding ,legend 不設置 margin ,則 legend 默認定位在最左側。

fieldset {
    border: 1px solid#ddd;
    // padding: 12px;
}

legend {
    font-size: 18px;
}

效果圖:

通過改變 legendmargin 或者父元素的 padding-left ,可以控制標題的初始位置:

fieldset {
    border: 1px groove #ddd;
}

legend {
    animation: marginMove 10s infinite alternate;
}

@keyframes marginMove {
    100% {
        margin-left: 100px;
    }
}

效果圖:

通過控制 legendpadding,可以增加周圍元素的區域,讓留白更多一點。

應用場景 -- 標題兩側橫線

了解了上述基本知識后,我們就可以稍微開始深入,想一想,上述 <fieldset><legend> 的一些有意思的應用場景。

最適合的場景我覺得應該就是標題兩側帶橫線的布局了。類似這樣:

當然,這個布局的解決方式有很多,通常會使用偽元素來生成左右兩側的橫線,或者是通過絕對定位局部進行覆蓋疊加。

這里,使用 <fieldset><legend> 非??焖俚耐瓿桑?/p>

<div class="g-container">
    <fieldset><legend>排行榜</legend></fieldset>
</div>
fieldset {
    width: 300px; 
    height: 24px; 
    border: 1px solid transparent; 
    border-top-color: #000; 
}

legend{
    margin: auto; 
    padding: 0 10px; 
} 

fieldset 只設置上邊框,通過 margin: auto 將標題定位到中間, 通過 padding 控制兩側的留白。非常的完美。

CodePen Demo -- fieldset & legend Demo 2

邊框嵌套文字

在這篇文章中 -- How to Add Text in Borders Using Basic HTML Elements,還介紹了一種非常有意思的使用場景,在邊框中嵌套文字。

想象一下,一個 <fieldset> 元素配合一個 <legend> 元素,可以生成一個邊框嵌文字的效果,那么,將多組組合,再進行定位排布,就可以生成多邊邊框嵌套文字的效果了。

偽代碼如下:

<div class="g-container">
    <fieldset><legend>CSS fieldset</legend></fieldset>
    <fieldset><legend>HTML element</legend></fieldset>
    <fieldset><legend>JavaScript</legend></fieldset>
    <fieldset><legend>TypeScript</legend></fieldset>
</div>
.g-container {
    position: relative;
    width: 300px; 
    height: 300px; 
}
fieldset{
    position: absolute;
    width: 300px; 
    height: 300px; 
    border: 10px solid transparent; 
    border-top-color: #000; 
}
legend{
    padding: 0 10px; 
} 

fieldset:nth-of-type(2){ transform: rotate(90deg); }
fieldset:nth-of-type(3){ transform: rotate(180deg); }
fieldset:nth-of-type(3)>legend{ transform: rotate(180deg); } 
fieldset:nth-of-type(4){ transform: rotate(-90deg); }

效果圖如下:

通過多個 <fieldset><legend> 的組合,我們可以拼出一個容器的 4 個邊,組成一個非常好看的邊框嵌文字效果。

通過給 legend 加上 animation,讓文字動起來

legend{
    animation: move 3s infinite linear alternate;
} 
@keyframes move {
    100% {
        margin-left: 70px;
    }
}

CodePen Demo -- Border Text Design using HTML fieldset and legend

好,基于這個,我們就可以去生成各種 N 邊形邊框嵌文字的邊框了。下面是簡單的嘗試 幾種多邊形邊框。

CodePen Demo -- fieldset and legend generate polygon

最后

本文到此結束,希望對你有幫助 :),想 Get 到最有意思的 CSS 資訊,千萬不要錯過我的公眾號 -- iCSS前端趣聞 ??

更多精彩 CSS 技術文章匯總在我的 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。

如果還有什么疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

查看原文

贊 12 收藏 7 評論 0

chokcoco 發布了文章 · 1月18日

CSS 奇思妙想邊框動畫

今天逛博客網站 -- shoptalkshow,看到這樣一個界面,非常有意思:

覺得它的風格很獨特,尤其是其中一些邊框。

嘿嘿,所以來一篇邊框特輯,看看運用 CSS,可以在邊框上整些什么花樣。

border 屬性

談到邊框,首先會想到 border,我們最常用的莫過于 solid,dashed,上圖中便出現了 dashed。

除了最常見的 solid,dashed,CSS border 還支持 none,hidden, dotted, double, groove, ridge, inset, outset 等樣式。除去 none,hidden,看看所有原生支持的 border 的樣式:

基礎的就這些,如果希望實現一個其他樣式的邊框,或者給邊框加上動畫,那就需要配合一些其他屬性,或是腦洞大開。OK,一起來看看一些額外的有意思的邊框。

邊框長度變化

先來個比較簡單的,實現一個類似這樣的邊框效果:

這里其實是借用了元素的兩個偽元素。兩個偽元素分別只設置上、左邊框,下、右邊框,通過 hover 時改變兩個偽元素的高寬即可。非常好理解。

div {
    position: relative;
    border: 1px solid #03A9F3;
    
    &::before,
    &::after {
        content: "";
        position: absolute;
        width: 20px;
        height: 20px;
    }
    
    &::before {
        top: -5px;
        left: -5px;
        border-top: 1px solid var(--borderColor);
        border-left: 1px solid var(--borderColor);
    }
    
    &::after {
        right: -5px;
        bottom: -5px;
        border-bottom: 1px solid var(--borderColor);
        border-right: 1px solid var(--borderColor);
    }
    
    &:hover::before,
    &:hover::after {
        width: calc(100% + 9px);
        height: calc(100% + 9px);
    }
}

CodePen Demo -- width border animation

接下來,會開始加深一些難度。

虛線邊框動畫

使用 dashed 關鍵字,可以方便的創建虛線邊框。


div {
    border: 1px dashed #333;
}

當然,我們的目的是讓邊框能夠動起來。使用 dashed 關鍵字是沒有辦法的。但是實現虛線的方式在 CSS 中有很多種,譬如漸變就是一種很好的方式:

div {
    background: linear-gradient(90deg, #333 50%, transparent 0) repeat-x;
    background-size: 4px 1px;
    background-position: 0 0;
}

看看,使用漸變模擬的虛線如下:

好,漸變支持多重漸變,我們把容器的 4 個邊都用漸變表示即可:

div {
    background: 
        linear-gradient(90deg, #333 50%, transparent 0) repeat-x,
        linear-gradient(90deg, #333 50%, transparent 0) repeat-x,
        linear-gradient(0deg, #333 50%, transparent 0) repeat-y,
        linear-gradient(0deg, #333 50%, transparent 0) repeat-y;
    background-size: 4px 1px, 4px 1px, 1px 4px, 1px 4px;
    background-position: 0 0, 0 100%, 0 0, 100% 0;
}

效果如下:

OK,至此,我們的虛線邊框動畫其實算是完成了一大半了。雖然 border-style: dashed 不支持動畫,但是漸變支持呀。我們給上述 div 再加上一個 hover 效果,hover 的時候新增一個 animation 動畫,改變元素的 background-position 即可。

div:hover {
    animation: linearGradientMove .3s infinite linear;
}

@keyframes linearGradientMove {
    100% {
        background-position: 4px 0, -4px 100%, 0 -4px, 100% 4px;
    }
}

OK,看看效果,hover 上去的時候,邊框就能動起來,因為整個動畫是首尾相連的,無限循環的動畫看起來就像是虛線邊框在一直運動,這算是一個小小的障眼法或者小技巧:

這里還有另外一個小技巧,如果我們希望虛線邊框動畫是從其他邊框,過渡到虛線邊框,再行進動畫。完全由漸變來模擬也是可以的,如果想節省一些代碼,使用 border 會更快一些,譬如這樣:

div {
    border: 1px solid #333;
    
    &:hover {
        border: none;
        background: 
            linear-gradient(90deg, #333 50%, transparent 0) repeat-x,
            linear-gradient(90deg, #333 50%, transparent 0) repeat-x,
            linear-gradient(0deg, #333 50%, transparent 0) repeat-y,
            linear-gradient(0deg, #333 50%, transparent 0) repeat-y;
        background-size: 4px 1px, 4px 1px, 1px 4px, 1px 4px;
        background-position: 0 0, 0 100%, 0 0, 100% 0;
    }
}

由于 border 和 background 在盒子模型上位置的差異,視覺上會有一個很明顯的錯位的感覺:

要想解決這個問題,我們可以把 border 替換成 outline,因為 outline 可以設置 outline-offset。便能完美解決這個問題:

div {
    outline: 1px solid #333;
    outline-offset: -1px;
    
    &:hover {
        outline: none;
    }
}

最后看看運用到實際按鈕上的效果:

上述 Demo 完整代碼如下:

CodePen Demo -- dashed border animation

其實由于背景和邊框的特殊關系,使用 border 的時候,通過修改 background-position 也是可以解決的,就是比較繞。關于背景和邊框的填充關系,可以看這篇文章:條紋邊框的多種實現方式

漸變的其他妙用

利用漸變,不僅僅只是能完成上述的效果。

我們繼續深挖漸變,利用漸變實現這樣一個背景:

div {
    position: relative;

    &::after {
        content: '';
        position: absolute;
        left: -50%;
        top: -50%;
        width: 200%;
        height: 200%;
        background-repeat: no-repeat;
        background-size: 50% 50%, 50% 50%;
        background-position: 0 0, 100% 0, 100% 100%, 0 100%;
        background-image: linear-gradient(#399953, #399953), linear-gradient(#fbb300, #fbb300), linear-gradient(#d53e33, #d53e33), linear-gradient(#377af5, #377af5);
    }
}

注意,這里運用了元素的偽元素生成的這個圖形,并且,寬高都是父元素的 200%,超出則 overflow: hidden。

接下來,給它加上旋轉:

div {
    animation: rotate 4s linear infinite;
}

@keyframes rotate {
    100% {
        transform: rotate(1turn);
    }
}

看看效果:

最后,再利用一個偽元素,將中間遮罩起來,一個 Nice 的邊框動畫就出來了 (動畫會出現半透明元素,方便示意看懂原理):

上述 Demo 完整代碼如下,這個效果我最早見于這位作者 -- Jesse B

CodePen Demo -- gradient border animation

改變漸變的顏色

掌握了上述的基本技巧之后,我們可以再對漸變的顏色做一些調整,我們將 4 種顏色變成 1 種顏色:

div::after {
    content: '';
    position: absolute;
    left: -50%;
    top: -50%;
    width: 200%;
    height: 200%;
    background-color: #fff;
    background-repeat: no-repeat;
    background-size: 50% 50%;
    background-position: 0 0;
    background-image: linear-gradient(#399953, #399953);
}

得到這樣一個圖形:

同樣的,讓它旋轉一起,一個單色追逐的邊框動畫就出來了:

CodePen Demo -- gradient border animation 2

Wow,很不錯的樣子。不過如果是單線條,有個很明顯的缺陷,就是邊框的末尾是一個小三角而不是垂直的,可能有些場景不適用或者 PM 接受不了。

那有沒有什么辦法能夠消除掉這些小三角呢?有的,在下文中我們再介紹一種方法,利用 clip-path ,消除掉這些小三角。

conic-gradient 的妙用

再介紹 clip-path 之前,先講講角向漸變。

上述主要用到了的是線性漸變 linear-gradient 。我們使用角向漸變 conic-gradient 其實完全也可以實現一模一樣的效果。

我們試著使用 conic-gradient 也實現一次,這次換一種暗黑風格。核心代碼如下:

.conic {
    position: relative;
    
    &::before {
        content: '';
        position: absolute;
        left: -50%;
        top: -50%;
        width: 200%;
        height: 200%;
        background: conic-gradient(transparent, rgba(168, 239, 255, 1), transparent 30%);
        animation: rotate 4s linear infinite;
    }
}
@keyframes rotate {
    100% {
        transform: rotate(1turn);
    }
}

效果圖和示意圖如下,旋轉一個部分角向漸變的圖形,中間的部分使用另外一個偽元素進行遮罩,只漏出線條部分即可:

CodePen Demo -- Rotating border 3

clip-path 的妙用

又是老朋友 clip-path,有意思的事情它總不會缺席。

clip-path 本身是可以進行坐標點的動畫的,從一個裁剪形狀變換到另外一個裁剪形狀。

利用這個特點,我們可以巧妙的實現這樣一種 border 跟隨效果。偽代碼如下:

div {
    position: relative;

    &::before {
        content: "";
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        border: 2px solid gold;
        animation: clippath 3s infinite linear;
    }
}

@keyframes clippath {
    0%,
    100% {
        clip-path: inset(0 0 95% 0);
    }
    25% {
        clip-path: inset(0 95% 0 0);
    }
    50% {
        clip-path: inset(95% 0 0 0);
    }
    75% {
        clip-path: inset(0 0 0 95%);
    }
}

效果圖與示意圖一起:

CodePen - clip-path border animation

這里,因為會裁剪元素,借用偽元素作為背景進行裁剪并動畫即可,使用 clip-path 的優點了,切割出來的邊框不會產生小三角。同時,這種方法,也是支持圓角 border-radius 的。

如果我們把另外一個偽元素也用上,實際實現一個按鈕樣式,可以得到這樣的效果:

CodePen - clip-path border animation 2

overflow 的妙用

下面這個技巧利用 overflow 實現。實現這樣一個邊框動畫:

為何說是利用 overflow 實現?

貼個示意圖:

CodePen Demo -- 巧用overflow及transform實現線條hover效果

兩個核心點:

  1. 我們利用 overflow: hidden,把原本在容器外的一整個元素隱藏了起來
  2. 利用了 transform-origin,控制了元素的旋轉中心

發現沒,其實幾乎大部分的有意思的 CSS 效果,都是運用了類似技巧:

簡單的說就是,我們看到的動畫只是原本現象的一小部分,通過特定的裁剪、透明度的變化、遮罩等,讓我們最后只看到了原本現象的一部分。

border-image 的妙用

利用 border-image,我們也可以實現一些有意思的邊框動畫。關于 border-image,有一篇非常好的講解文章 -- border-image 的正確用法,本文不對基本定義做過多的講解。

如果我們有這樣一張圖:

便可以利用 border-image-sliceborder-image-repeat 的特性,得到類似的邊框圖案:

div {
  width: 200px;
  height: 120px;
  border: 24px solid;
  border-image: url(image-url);
  border-image-slice: 32;
  border-image-repeat: round;
}

在這個基礎上,可以隨便改變元素的高寬,如此便能擴展到任意大小的容器邊框中:

CodePen Demo -- border-image Demo

接著,在這篇文章 -- How to Animate a SVG with border-image 中,還講解了一種利用 border-image 的邊框動畫,非常的酷炫。

與上面例子不一樣的是,我們只需要讓我們的圖案,動起來,就是我們需要這樣一個背景圖(掘金不支持 SVG 動圖,原圖地址):

那么,我們也就能得到運動的邊框圖,代碼完全一樣,但是,邊框是運動的:

CodePen Demo -- Dancing Skull Border

border-image 使用漸變

border-image 除了貼圖引用 url 之外,也是可以直接填充顏色或者是漸變的。

之前也有一篇關于 border-image 的文章 -- 巧妙實現帶圓角的漸變邊框

我們可以利用 border-image + filter + clip-path 實現漸變變換的圓角邊框:

.border-image-clip-path {
    width: 200px;
    height: 100px;
    border: 10px solid;
    border-image: linear-gradient(45deg, gold, deeppink) 1;
    clip-path: inset(0px round 10px);
    animation: huerotate 6s infinite linear;
    filter: hue-rotate(360deg);
}

@keyframes huerotate {
    0% {
        filter: hue-rotate(0deg);
    }
    100% {
        filter: hue-rotate(360deg);
    }
}

CodePen Demo -- clip-path、border-image 加 filter 實現圓角漸變邊框

最后

本文介紹了一些我認為比較有意思的邊框動畫小技巧,當然 CSS 產生還有非常多有意思的效果,限于篇幅,不一一展開。

本文到此結束,希望對你有幫助 :),想 Get 到最有意思的 CSS 資訊,千萬不要錯過我的 iCSS 公眾號 -- iCSS前端趣聞 ??

更多精彩 CSS 技術文章匯總在我的 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。

如果還有什么疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

查看原文

贊 28 收藏 24 評論 0

chokcoco 發布了文章 · 1月13日

如何不使用 overflow: hidden 實現 overflow: hidden?

一個很有意思的題目。如何不使用 overflow: hidden 實現 overflow: hidden?

CSS 中 overflow 定義當一個元素的內容太大而無法適應塊級格式化上下文時候該做什么。而 overflow: hidden 則會將超出容器范圍內的內容剪裁。

控制 overflow: hidden 的方向

這源自一個實際的需求,在某個需求當中,要求容器內的內容,在豎直方向上超出容器會被裁剪,而在水平方向上超出容器,則不會被裁剪。類似這樣:

1 上午10.26.03.gif

有意思,第一個想到的解法當然是在上述黃色背景元素本身之外再套用一層父元素,然后父元素才是實際設置 overflow: hidden 的元素,父元素的范圍就是實際才是控制是否裁剪的范圍。類似這樣:

2 上午10.26.03.gif

實際的父元素才是設置了 overflow: hidden 的元素。

當然,如果實際情況就是這么簡單,也沒什么問題。

但是如果元素處于一個復雜的布局流內,那么可能就沒有那么多的空間,讓我們再去包裹一層父容器了:

3 上午10.26.03.png

類似上圖的情況,還是中間黃色元素,要求只有豎直方向超出裁剪。此時,包裹父元素不再那么容易施展。所以,我們需要另辟蹊徑。

利用 clip-path 進行裁剪

好的,這會可以進入正文了。CSS 中,除了 overflow: hidden,還是有其它屬性也可以實現超出容器區域進行裁剪的。clip-path 便是其中翹楚。

使用 clip-path,我們可以方便的控制任意方向上的裁剪。上述的需求則可以這樣解決:

<div class="g-container">
    <div class="sub"></div>
</div>

關鍵的 CSS 代碼如下:

.g-container {
    width: 200px;
    height: 200px;
    clip-path: polygon(-1000% 0, 1000% 0, 1000% 100%, -1000% 100%);
}

這里利用了 clip-path: polygon() 來裁剪一個矩形區域,而利用了 clip-path 支持負坐標的特點,將裁剪的起點定到遠離坐標能畫成一個大矩形的形狀。示意圖:

4 上午10.26.03.png

這樣,我們能夠在正常布局流中,當前容器大小范圍內,畫出任意希望 overflow: hidden 的范圍。

你可以點進 Demo 里面嘗試下:

CodePen -- Clip-path overflow

再舉兩個例子:

{
    // 裁剪出左右兩邊都 overflow:hidden,上下不 overflow:hidden 的區域
    clip-path: polygon(0 -1000% ,100% -1000%, 100% 1100%,0 1100%);

   // 裁剪出左邊、上邊、右邊都 overflow:hidden,下邊不 overflow: hidden 的區域
    clip-path: polygon(100% 0,100% 1000%, 0 1000%, 0 0);
}

當然,上述代碼中的 1000% 是非常靈活的,自己控制,夠用就行。

非 overflow、clip-path 的裁剪方式

那么。通過上面的一個小例子,我們知道了 overflow,clip-path 可以裁剪區域。那么除了這兩個,CSS 中還有沒有可以進行區域裁剪的元素呢?

有,還有一個有意思的元素,就是 -- contain 。

contain 屬性允許我們指定特定的 DOM 元素和它的子元素,讓它們能夠獨立于整個 DOM 樹結構之外。目的是能夠讓瀏覽器有能力只對部分元素進行重繪、重排,而不必每次都針對整個頁面。

這里不具體去介紹它的每個屬性,感興趣的可以翻看下這篇文章 -- CSS新特性contain,控制頁面的重繪與重排

contain: paint 進行內容裁剪

詳細說說 contain: paint,設定了 contain: paint 的元素即是開啟了布局限制,也就是說,此元素的子元素不會在此元素的邊界之外被展示。

contain: paint 屬性產生的目的,即是為加快頁面的渲染,在非必要區域,不渲染元素。因此,如果元素不在屏幕上或以其他方式設定為不可見,則其后代不可見不被渲染。
.g-container {
    contain: paint;
}

看看示例:

5 上午10.26.03.gif

CodePen Demo -- contain: paint Demo

contain: paint 的副作用

contain: paint 的本意是用于提升頁面的渲染,裁剪到容器之外的元素不進行渲染。但是使用它會產生一些副作用:

  1. 它會生成一個自己的新的堆疊上下文(It becomes a stacking context),也就是說,它會改變它的子元素的 absolute 定位和 fixed 定位的基準;
  2. 它會成為新的格式化上下文(It becomes a new formatting context),也就是說,這意味著元素外部的布局不會再影響它的子元素;

更具體的,可以看看這篇文章 -- CSS Containment in Chrome 52

我們解釋下第一點,非常的有意思,它會生成一個自己的新的堆疊上下文,也就是說,它將改變 position: fixed 元素的基準,它會使得設置了 position: fixed 的元素不再相對于視口進行定位,而是相對于該元素進行定位。也就是退化成了 position: absolute。

當然,這個不是本文的重點,我提供了一個 Demo -- contain: paint create a stacking context,這里就不繼續展開。

總結一下

到此,本文提供了 3 種可以實現超出容器范圍裁剪的方法:

  • overflow: hidden
  • clip-path 繪制裁切區域
  • contain: paint 不繪制元素范圍外的內容

這里再提供下 3 個示例的 Demo:CodePen Demo -- Overflow Hidden In CSS

當然,它們之間還是有一些差異:

  1. overflow: hiddencontain: paint 會創建一個 BFC,而clip-path不會,它只是單純的裁剪
  2. 兼容性間的差異

所以也就是說,CSS 不僅僅只有 overflow: hidden 實現 overflow: hidden,很多情況,可以靈活使用。

牛刀小試

再來個有意思的環節,在 一行 CSS 代碼的魅力 中,提到了 CSS Battle 。

這個網站是核心玩法就是:官方給出一張圖形,在給定的 400 x 300 的畫布上,能夠用越短的代碼實現它,分數就越高。

上次講了一題通過一行 CSS 代碼實現,今天,我們再來看看第二題

6 上午10.26.03.png

怎么用最短的代碼實現它呢?想想今天說的 clip-path。

首先,我們利用這一一段代碼,生成這樣一個圖形:

<style>
body {
    margin: 0 50px;
    background: #62374e;
    border: 50px dashed #fdc57b;
}

7 上午10.26.03.png

然后,利用 clip-path,把上下兩部分裁掉即可。

<style>
body {
    margin: 0 50px;
    background: #62374e;
    border: 50px dashed #fdc57b;
  + clip-path: polygon(0 50px, 100% 50px, 100% 250px, 0 250px);
}

6 上午10.26.03.png

這樣就完美實現啦。當然,現在字符數有點多,有 158 個字符這么多。其實對于裁剪矩形區域,clip-path 有更便捷的語法,上述 clip-path:polygon(0 50px, 100% 50px, 100% 250px, 0 250px) 可以替換成 clip-path:inset(50px 0),減少了 20 個字符。

當然,再暴力一點,我們也可以一行實現:

<body bgcolor=62374e style=margin:0+50;border:dashed+50px#fdc57b;clip-path:inset(50px+0>
當然,這里可能用了一些這個網站才允許的語法,不過核心實現還是在于用 clip-path 切割掉多余部分

最后

好了,本文到此結束,希望對你有幫助 :),想 Get 到最有意思的 CSS 資訊,千萬不要錯過我的公眾號 -- iCSS前端趣聞 ??

qrcode.png

更多精彩 CSS 技術文章匯總在我的 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。

如果還有什么疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

查看原文

贊 7 收藏 5 評論 1

chokcoco 發布了文章 · 1月8日

水平垂直居中深入挖掘

在上篇文章 -- 一行 CSS 代碼的魅力 的最后,提到了兩種快速實現水平垂直居中的方式。

當然,CSS 中實現水平垂直居中的方式很多。別看到水平垂直居中就準備右上角 x 掉,本文的重點不是羅列有多少種方式實現水平垂直居中方式,而是探討一下常見的幾種水平垂直居中的方式的利弊。

嗯哼?也就是:

  • 那么多種水平垂直居中的方式,如果真的在業務中需要使用了,你腦海里第一時間會想到哪個?
  • 不同的水平垂直居中方式,它們肯定存在差異,那么最顯著的不同是什么?
  • 有沒有所謂的最完美的水平垂直居中?

本文將討論 4 種水平垂直居中的方式,分別是,并且每個起個名字方面下面看圖:

  1. absolute: position: absolute 配合 top:50%;left:50%;transform:translate(-50%, -50%)
  2. autobot: display:flex 配合 margin:auto
  3. flex: display:flex 配合 align-items:center、justify-content:center
  4. grid: display:grid 配合 place-content:center;

居中單個元素

對于如下簡單的結構:

<div class="g-container">
    <div class="sub"></div>
</div>

居中單個元素而言,上述 4 種方法都很好,沒有問題。

1.png

CodePen Demo -- Centering in CSS

居中多個元素

對于如下稍微復雜點的結構:

<div class="g-container">
    <div class="sub">1</div>
    <div class="sub">123</div>
    <div class="sub">123456</div>
</div>

那么如果是居中多個子元素,上述 4 種方法,就能體現出明顯的不一樣。稍微也修改一下子元素,不給它設定寬度,通過 padding 撐開即可:

.sub {
    border: 1px solid deeppink;
    padding: 10px;
    border-radius: 5px;
}

看看結果如何:

2.png

CodePen Demo -- Centering in CSS 2

簡單分析分析:

  1. absolute 的方法明顯有問題,由于用的絕對定位,其實 3 個子元素都疊在了一起
  2. flexgrid 的方法,如果不手動添加邊距(margin 或者 gap),會貼在一起
  3. 不限制方向的話,flex 默認是水平排列,grid 是豎直排列
  4. 非常重要的一點,grid 布局下的子元素的寬度,所以子元素的寬度會被強行拉伸至最寬的一個子元素的內容的寬度

對于多個子元素,absolute 方法明顯不適用, 接下來主要看剩余 3 個方法在一些細節上的差異。

控制間距

如果我們希望控制每個元素之間的間距呢?我們給 autobot、flex、grid 的容器各自加上 gap: 5px,再看看:

.g-container{
    gap: 5px;
}

3.png

CodePen Demo -- Centering in CSS 3

  1. margin: auto 由于需要均分剩余空間,所以表現并不好,無法按照我們設想的 5px 寬度進行間隔

讓元素多到溢出

OK,接下來,我們讓內容再多一點,多到溢出整個容器,看看有什么不一樣。

4.png

再來一張豎直方向排列的:

5.png

CodePen Demo -- Centering in CSS 4

可以看到:

  1. 非常重要的一點,由于沒有了剩余空間,margin: auto 已經無法做到均勻分配,水平垂直居中了,而是一邊貼著容器邊,另外一邊溢出
  2. flexgrid 都做到了即便超出容器空間,依然是水平垂直居中的

總結一下

經由上述幾個 DEMO 可以看出來,在目前比較常用的水平垂直居中方案當中。flex 方案應該是目前而言最優的選擇,它能夠在各種環境下都保持內部元素的水平垂直居中并且不改變子元素的某些特征:

  1. 便捷的水平垂直居中單個元素
  2. 便捷的水平垂直居中多個元素,無論是橫向、豎向,亦或內容超出
  3. 非常方便控制子元素之間的間距
  4. 不會改變子元素的寬度

當然,美中不足的是,可能相對而言,要敲多幾個字符。

margin: autogrid 則或多或少有一些小問題。absolute 無法應付多個元素。

最后

本文知識點比較細,也表明 CSS 雖然簡單,但是不代表它容易。我們日常工作中用到的很多屬性其實還有很多細節可以挖掘深入。

譬如,可以再比較下在書寫方式 writing-mode 不同的場景下,上述水平垂直居中的方式的異同,等等。

好了,本文到此結束,希望對你有幫助 :),想 Get 到最有意思的 CSS 資訊,千萬不要錯過我的 iCSS 公眾號 ??

QQ20210108-0.png

更多精彩 CSS 技術文章匯總在我的 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。

如果還有什么疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

查看原文

贊 8 收藏 5 評論 0

認證與成就

  • 獲得 812 次點贊
  • 獲得 3 枚徽章 獲得 0 枚金徽章, 獲得 0 枚銀徽章, 獲得 3 枚銅徽章

擅長技能
編輯

(??? )
暫時沒有

開源項目 & 著作
編輯

(??? )
暫時沒有

注冊于 2016-06-28
個人主頁被 8.2k 人瀏覽

一本到在线是免费观看_亚洲2020天天堂在线观看_国产欧美亚洲精品第一页_最好看的2018中文字幕 <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>