Sass自動化處理CSS動畫執行個體教程

來源:互聯網
上載者:User

有一天,Harry Roberts有一段有關於他網站上的代碼在twitter求教,如果有可能,在某些方面得到改善。Harry Roberts做的是使用keyframes的carousel動畫,所以說使用一些數學計算是有可能得到相應改善。

    “Why do we have to learn algebra, Miss? We’re never going to use it…” —Everyone in my maths class bit.ly/UaM2wf

有什麼好主意?

據我所見,Harry Roberts在他的首頁上使用了一個carousel動畫。可以使用CSS,為什麼要使用JavaScript呢,你說對吧。所以他使用CSS動畫來製作Carousel動畫。這聽起來似乎是一個很好的想法,但直到你需要計算keyframe時,你就不會這麼認為。

下面是有關於Harry Roberts對Carousel動畫做的描述。

滾動Carousel(寫入程式碼,有點讓人覺得噁心!)和使用一個小動畫(這個動畫運動是模糊/動畫)。整個Carousel動畫需要計算過渡和延遲時間(比如100%):

n * x + (n - 1) * y = 100

其中n是指投影片的數量,x是動畫在靜態時的百分比,y是動畫在運動時的百分比。

這個動畫有5張投影片,根據上面描述,可以得到:

5 * x + (5 - 1) * y = 100

如果知道x和n的值,我們就可以計算出y的值:

(100 - (n * x)) / (n - 1) = y

假設x選擇的值為17.5(也就是動畫中17.5%位置),我們知道n=5,這樣可以計算出y=3.125:

(100 - (5 * 17.5)) / (5 -1) = 3.125

幀從17.5%過渡到3.125%等等,直到100%。

如果我們把x設定為15,那麼可以計算出y=6.25:

(100 - (5 * 15)) / (5 -1) = 6.25

如果y運動是從"zero-or-below",這也意味著,我們選擇了x值太大。

注意,我們還有一個中間點,也就是在中間過渡幀,這個數可以這們得來:

(a * x) + ((a - 1) * y) + (y / 2)

問題是在n個幀哪一個幀才是中間幀。一般情況是3和4之間:

(3 * 17.5) + ((3 - 1) * 3.125)+ (3.125 / 2) = 60.3125

這的確很混亂。

最終結果是:

@keyframes carousel {  0% {    transform: translate3d(0, 0, 0);    filter: blur(0);  }  17.5% {    transform: translate3d(0, 0, 0);    filter: blur(0);  }  19.0625% {    filter: blur(2px);  }  20.625% {    transform: translate3d(-20%, 0, 0);    filter: blur(0);  }  38.125% {    transform: translate3d(-20%, 0, 0);    filter: blur(0);  }  39.6875% {    filter: blur(2px);  }  41.25%   {    transform: translate3d(-40%, 0, 0);    filter: blur(0);  }  58.75%   {    transform: translate3d(-40%, 0, 0);    filter: blur(0);  }  60.3125% {    filter: blur(2px);  }  61.875%  {    transform: translate3d(-60%, 0, 0);    filter: blur(0);  }  79.375%  {    transform: translate3d(-60%, 0, 0);    filter: blur(0);  }  80.9375% {    filter: blur(2px);  }  82.5%    {    transform: translate3d(-80%, 0, 0);    filter: blur(0);  }  100%     {    transform: translate3d(-80%, 0, 0);    filter: blur(0);  }}



清潔CSS動畫

之前我考慮過Sass,減少動畫代碼。從上面的代碼塊中,我們不難發現,有一些主要畫面格是相同的。這樣我們可以把代碼清理清理,讓整個動畫變得更簡單:

@keyframes carousel {  0%,  17.5% {    transform: translate3d(0, 0, 0);    filter: blur(0);  }  19.0625% {    filter: blur(2px);  }  20.625%,  38.125% {    transform: translate3d(-20%, 0, 0);    filter: blur(0);  }  39.6875% {    filter: blur(2px);  }  41.25%,  58.75% {    transform: translate3d(-40%, 0, 0);    filter: blur(0);  }  60.3125% {    filter: blur(2px);  }  61.875%,  79.375% {    transform: translate3d(-60%, 0, 0);    filter: blur(0);  }  80.9375% {    filter: blur(2px);  }  82.5%,  100% {    transform: translate3d(-80%, 0, 0);    filter: blur(0);  }}



Sass怎麼玩

主要畫面格通常可以得到最佳化。因為@keyframes中迴圈的幀通常很容易產生重複的動畫。我們可以試試。

首先,為了保持一致性,我們照常使用Harry的變數名:n,x和y。別忘了它們的含義:

    $n是動畫中的幀數
    $x是動畫幀的百分比,邏輯上是小於或等於100% / $n
    $y是動畫中每一幀的比例

$n: 5;
$x: 17.5%;
$y: (100% - $n * $x) / ($n - 1);

現在我們在@keyframes中做一個迴圈:

@keyframes carousel {
    @for $i from 0 to $n { // 0, 1, 2, 3, 4
        //Sass動畫
    }
}

在迴圈中,我們使用Harry的公式計算每一對相同的主要畫面格(比如41.25%和58.75%):

$current-frame: ($i * $x) + ($i * $y);
$next-frame: (($i + 1) * $x) + ($i + $y);

特別聲明:小括弧完全可以略去,這裡只是用它們來讓代碼保持更乾淨。

現在,我們使用這些變數來產生主要畫面格,別忘了在裡面插入正確的CSS(有關於更多的Sass內容,可以點擊這裡):

#{$current-frame, $next-frame} {
  transform: translateX($i * -100% / $frames);
  filter: blur(0);
}

非常簡單,不是嗎?運行第一個迴圈之後,編譯出CSS代碼:

0%, 17.5% {
  transform: translate3d(0%, 0, 0);
  filter: blur(0);
}

剩下的就是Harry說的,在中間幀中添加blur()效果。我們可以使用他的公式計算出:

$halfway-frame: $i * ($x / 1%) + ($i - 1) * $y + ($y / 2);

#{$halfway-frame} {
  filter: blur(2px);
}

這裡出錯了。

    無效的CSS:我們預期的主要畫面格,比如10%,可計算出來的是-1.5625%。

正如你所看到,我們最終得到了一個負的主要畫面格。這在CSS規範中是禁止的,就算在Sass中也認為這是一個錯誤,所以我們需要確保這種事情不會發生。實際上,只有當$i為0才會發生。因此,有一個簡單的方法來阻止這樣的事情發生,根據規則輸出$i的值:

@if $i > 0 {
  #{$halfway-frame} {
    filter: blur(2px);
  }
}

錯誤解決了,這是最後的代碼:

$n: 5;$x: 17.5%;$y: (100% - $n * $x) / ($n - 1);@keyframes carousel {  @for $i from 0 to $n {    $current-frame: ($i * $x) + ($i * $y);    $next-frame: (($i + 1) * $x) + ($i + $y);    #{$current-frame, $next-frame} {      transform: translate3d($i * -100% / $frames, 0, 0);    }    $halfway-frame: $i * ($x / 1%) + ($i - 1) * $y + ($y / 2);    @if $i > 0 {      #{$halfway-frame} {        filter: blur(2px);      }    }  }}

將這一切放在一個mixin中

到目前為止,這一切都好了?Harry的動畫代碼工作的很好,所以他沒有再次計算。如果他想把投影片從5張變成4張,或者說希望動畫時間更快或更慢,這一切以得重新開始。

目前我們的變數會汙染全範圍。同樣的,如果在其他地方需要Carousel動畫,需要重新設定其他變數名,然後將動畫內容複寫到新的動畫中。這絕不是理想的做法。

這就是我們使用mixin的理由。為了讓事情更易理解,我們使用實際的變數名來替代這些字母:

    $n換成$frames
    $x換成$static
    $y換成$animating

另外,為了確保它輸出不同的動,可以利用mixin多次調用不同的參數。所以我們需要再添加一個參數:動畫的名字。

@mixin carousel-animation($frames, $static, $name: 'carousel') {  $animating: (100% - $frames * $static) / ($frames - 1);  // Moar Sass}



由於mixin可以在不同的地方調用,為了阻止選取器包括它,可以使用@at-root確保動畫輸出是在根層級:

@mixin carousel-animation($frames, $static, $name: 'carousel') {  $animating: (100% - $frames * $static) / ($frames - 1);  @at-root {    @keyframes #{$name} {      // Animation logic here    }  }}



在實際中,可以這樣調用:

@include carousel-animation(  $frames: 5,  $static: 17.5%);



編譯出來的CSS:

@keyframes carousel {  0%, 17.5% {    transform: translateX(0%);    filter: blur(0);  }  19.0625% {    filter: blur(2px);  }  20.625%, 38.125% {    transform: translateX(-20%);    filter: blur(0);  }  39.6875% {    filter: blur(2px);  }  41.25%, 58.75% {    transform: translateX(-40%);    filter: blur(0);  }  60.3125% {    filter: blur(2px);  }  61.875%, 79.375% {    transform: translateX(-60%);    filter: blur(0);  }  80.9375% {    filter: blur(2px);  }  82.5%, 100% {    transform: translateX(-80%);    filter: blur(0);  }}



任務完成了。如果我們想在聯絡頁面使用另一個動,可以這樣使用:

@include carousel-animation(  $name: 'carousel-contact',  $frames: 3,  $static: 20%);



是不是十分完美。(^_^)。

總結

這想當的完美。而Harry當初的代碼容易閱讀,但真的不太容易維護。使用Sass的自動化計算和迴圈特性,可以變得更佳方便。當然,它也使代碼變得更為複雜,但這也使得它易於維護和更新。使用起來也非常的簡單。


Sass


// ----// Sass (v3.4.0.rc.1)// Compass (v1.0.0.alpha.20)// ----/** * Generate the carousel animation * based on the number of frames * and the pourcentage of a frame spent static * * @param {Number} $n - number of frames * @param {Number} $x - percentage of the animation spent static per frame * @param {String} $animation-name ('carousel') - animation name */ @mixin carousel-animation($frames, $static, $animation-name: 'carousel') {  // Make `$static` a percentage in case it's unitless  @if unitless($static) {    $static: percentage($static);  }  // Compute the percentage of animation spent animating for each frame  $animating: (100% - $frames * $static) / ($frames - 1);    // Output the animation at root level  // to make sure it doesn't crash if called in a selector  @at-root {        // Create an animation    @keyframes #{$animation-name} {            // Loop over the frames      @for $i from 0 to $frames {        // Compute keyframes        $current-frame: $i * $static + $i * $animating;        $next-frame: ($i + 1) * $static + $i * $animating;        $halfway-frame: $i * $static / 1% + ($i - 1) * $animating + $animating / 2;                // Output halfway styles for blur        // Avoid a negative keyframes by making sure `$i` is at least `1`        @if $i > 0 {          #{$halfway-frame} {            filter: blur(2px);          }        }        // Output styles for each frame        #{$current-frame, $next-frame} {          transform: translateX($i * -100% / $frames);          filter: blur(0);        }      }    }  }}// Generate animation@include carousel-animation(5, 17.5%);




CSS

/** * Generate the carousel animation * based on the number of frames * and the pourcentage of a frame spent static * * @param {Number} $n - number of frames * @param {Number} $x - percentage of the animation spent static per frame * @param {String} $animation-name ('carousel') - animation name */@keyframes carousel {  0%, 17.5% {    transform: translateX(0%);    filter: blur(0);  }  19.0625% {    filter: blur(2px);  }  20.625%, 38.125% {    transform: translateX(-20%);    filter: blur(0);  }  39.6875% {    filter: blur(2px);  }  41.25%, 58.75% {    transform: translateX(-40%);    filter: blur(0);  }  60.3125% {    filter: blur(2px);  }  61.875%, 79.375% {    transform: translateX(-60%);    filter: blur(0);  }  80.9375% {    filter: blur(2px);  }  82.5%, 100% {    transform: translateX(-80%);    filter: blur(0);  }}


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.