Skip to content

Instantly share code, notes, and snippets.

@xl1
Created December 14, 2012 00:27
Show Gist options
  • Save xl1/4281393 to your computer and use it in GitHub Desktop.
Save xl1/4281393 to your computer and use it in GitHub Desktop.

Revisions

  1. xl1 revised this gist Dec 14, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -81,7 +81,7 @@ sticky な要素が一体どこに配置されるのか計算してみたいと
    あとは `#sticky` にも逆の変形をかけると、あたかも別の方向に、別の速度でスクロールしているかのように見えるわけです。

    (1) で bounding box の left/top (または right/bottom)が、変形前と変わらないように適当に平行移動してやると、(3) と (5) でのずらす処理を考えなくてよく、配置しやすいと思います。
    [sticker.scss]() はそうなっているので気になる方は試してみてください。
    [sticker.scss](https://gist.github.com/4277256) はそうなっているので気になる方は試してみてください。

    ## 注意

  2. xl1 revised this gist Dec 14, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -12,7 +12,7 @@ HTML5Rocks に詳しい解説があるので、「ただしい」使用法につ
    - [Stick your landings! position: sticky lands in WebKit - HTML5Rocks Updates](http://updates.html5rocks.com/2012/08/Stick-your-landings-position-sticky-lands-in-WebKit)

    現在は Chrome (おそらく 23 以上)に実装が載っています。
    `about:flags` で「**試験運用版の WebKit 機能を有効にする**」をオンにする必要があります。
    `about:flags` で「試験運用版の WebKit 機能を有効にする」をオンにする必要があります。

    ## スクロール時エフェクトが CSS でできるよ!

  3. xl1 revised this gist Dec 14, 2012. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -11,6 +11,9 @@ HTML5Rocks に詳しい解説があるので、「ただしい」使用法につ

    - [Stick your landings! position: sticky lands in WebKit - HTML5Rocks Updates](http://updates.html5rocks.com/2012/08/Stick-your-landings-position-sticky-lands-in-WebKit)

    現在は Chrome (おそらく 23 以上)に実装が載っています。
    `about:flags` で「**試験運用版の WebKit 機能を有効にする**」をオンにする必要があります。

    ## スクロール時エフェクトが CSS でできるよ!

    さて、sticky positioned な要素の親要素に、CSS Transforms を適用することを考えます。
  4. xl1 revised this gist Dec 14, 2012. No changes.
  5. xl1 revised this gist Dec 14, 2012. 1 changed file with 92 additions and 1 deletion.
    93 changes: 92 additions & 1 deletion gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -1 +1,92 @@
    # 建設予定地
    # CSS でペライチ

    これは [CSS Programming Advent Calendar 2012](http://www.adventar.org/calendars/2) の 14 日目の記事です。

    ## Sticky Positioning

    8 月の末に、WebKit に `position: sticky` というプロパティが追加されました。
    `position: sticky` が指定された要素は、親要素との位置関係によって、`position: fixed` または `position: relative` が指定されたかのように振る舞います。
    例えば、ある程度スクロールするとサイドバーやナビゲーションが固定されるサイトをたまに見かけますが(例えば [Togetter](http://togetter.com/), [LESS のサイト](http://lesscss.org/), etc.)その動作が CSS で指定できるようになったわけです。
    HTML5Rocks に詳しい解説があるので、「ただしい」使用法についてはそちらを参照してください。

    - [Stick your landings! position: sticky lands in WebKit - HTML5Rocks Updates](http://updates.html5rocks.com/2012/08/Stick-your-landings-position-sticky-lands-in-WebKit)

    ## スクロール時エフェクトが CSS でできるよ!

    さて、sticky positioned な要素の親要素に、CSS Transforms を適用することを考えます。
    すると、親要素との位置関係(より正しくは、親要素の bounding box との位置関係)が変化するため、sticky な要素の動作も変形されます。

    - [Demo 1. sticky の親を transform](http://jsdo.it/xl1/nJVV/fullscreen)

    これは `position: fixed``relative` には見られない特徴的な挙動です。
    この挙動を「ただしくなく」利用して、例えばスクロール時にいろいろな方向に要素が動く効果(いわゆる「高級ペライチ」、「パララックス」)を CSS で実現できます。

    - [Demo 2. Scrolling Effects](http://jsrun.it/xl1/k4fp)
    - 使っている SCSS mixins [sticker.scss](https://gist.github.com/4277256)

    ブラウザが適当に処理してくれるのか、要素が巨大だったり数が多くても、割と軽い動作になっています。
    意図したとおりに動かすには計算がやや煩雑ですので、上のように CSS プリプロセッサを使うのがよいでしょう。
    また、3D Transforms を組み合わせると、スクロールに応じて大きさを変化させたりということも可能です。
    しかしさらに面倒になるので上の mixin にはその機能はありません……。

    sticker.scss では `sqrt()``arctan()` を自前で用意していますが、Sass の [Custom Functions](http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#adding_custom_functions) などで既存の実装を使うほうがよいと思います。
    (ただし、SCSS で自前で書いても、コンパイル時間や精度など特に問題にはなりませんでした。)

    - [Compass](http://compass-style.org/)
    - [scottkellum/Sassy-math · GitHub](https://github.com/scottkellum/Sassy-math)


    ## sticky な要素の位置算出方法

    sticky な要素が一体どこに配置されるのか計算してみたいと思います。
    まず、要素の **bounding box** とは、四辺が水平または垂直な長方形で、その要素を完全に覆うもののうち、最小のものをいうことにします。

    ![definition of bounding box](http://jsrun.it/assets/r/i/1/j/ri1jZ.png)

    以下では、ページは次のような状態になっているとします。

    ```html
    <style>
    #parent {
    transform: ...; /* 実際には vendor prefix がつきます、以下同様 */
    }
    #sticky {
    position: sticky;
    left: ...; /* または right */
    top: ...; /* または bottom */
    }
    </style>
    <div id="parent">
    <div id="sticky"></div>
    </div>
    ```

    親要素(`#parent`)に Transform が設定されたとき、`#sticky` 要素の位置は次の順序で計算できます。

    1. 親要素の Transform 適用後の bounding box を算出する
    2. `#sticky` を、まずは `fixed` だと思って配置する
    3. 1 の bonding box にすっぽり入るまで最短距離で移動する。
    元から入っていれば何もしない。
    4. bounding box 内での座標を調べる
    5. `#sticky` を親要素内のその座標にあらためて配置する
    6. Transform を適用する

    ![sticky 要素の位置算出方法](http://jsrun.it/assets/s/D/e/b/sDebm.png)

    最後の (6) で Transform がかかるために、例えば上のように `#parent` に回転をかければ、スクロールしたときの「移動方向」を変えることができます。
    拡大または縮小をかければ、「移動量」を変えることができます。
    あとは `#sticky` にも逆の変形をかけると、あたかも別の方向に、別の速度でスクロールしているかのように見えるわけです。

    (1) で bounding box の left/top (または right/bottom)が、変形前と変わらないように適当に平行移動してやると、(3) と (5) でのずらす処理を考えなくてよく、配置しやすいと思います。
    [sticker.scss]() はそうなっているので気になる方は試してみてください。

    ## 注意

    以上に述べたことは現在の WebKit の実装ではこういうことができるというだけで、将来にわたって、また他のブラウザで(実装されたとしても)同じことができる保証はもちろんありません。
    スクロールに反応して変なことができそうなので、ぜひこのまま残ってくれると嬉しいのですが。
    めでたし、めでたし……


    ## 15 日目は

    明日は [ksk1015](https://twitter.com/ksk1015) さんです!
  6. xl1 created this gist Dec 14, 2012.
    1 change: 1 addition & 0 deletions gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    # 建設予定地