scale according to scroll position

by rodneyrehm

HTML

<header> <h1>foo bar baz</h1> </header>
<p style="height:0; padding-bottom: 10000px; margin-bottom: -10000px">scrollbars</p>
<p style="margin-top: 100px">scroll down and watch the header become smaller</p>
<p style="margin-top: 100px">scroll down and watch the header become smaller</p>
<p style="margin-top: 100px">scroll down and watch the header become smaller</p>
<p style="margin-top: 100px">scroll down and watch the header become smaller</p>
<p id="offset">0px</p>
<!--
    define the scroll range you want to resize within 
        (scroll.min, scroll.max)

    define the minimum size to shrink to

    use font-size as the one property to set, 
    so each "em"-specified element inherits the new size

    use transitions to make things smoother
-->

CSS

header {
    position: fixed;
    top:0; right:0; left: 0;
    background: #333;
    padding: 0;
    font-size: 20px;
}

header > h1 {
    color: #EEE;
    padding: 0.5em;
    font-size: 2em;
    
    /* making things smoother */
    -webkit-transition: font-size linear 0.5s,
                        padding   linear 0.5s;
       -moz-transition: font-size linear 0.5s,
                        padding   linear 0.5s;
            transition: font-size linear 0.5s,
                        padding   linear 0.5s;
}

#offset {
    position: fixed;
    bottom: 0; left: 0;
}

JavaScript

var $header = $('body > header'),
    $offset = $('#offset'),
    $document = $(document),
    scroll = {
        min: 100,
        max: 200
    },
    current = null,
    size = {
        min: 10,
        max: parseInt($header.css('font-size') || "0", 10)
    };

// make sure min < max
if (size.min > size.max) {
    var t = size.min;
    size.min = size.max;
    size.max = t;
    delete t;
}

// calculate ranges
size.range = size.max - size.min;
scroll.range = scroll.max - scroll.min;

// bind scroll handler
$(window).on('scroll', function(e) {
    // get current scroll offset
    var so = $document.scrollTop(),
        // reversed percentage scrolled withing scroll.range
        p = 1 - (so - scroll.min) / scroll.range,
        s;
    
    // respect boundaries
    if (so < scroll.min) {
        p = 1;
        $offset.text(so +"px (below bounds)");
    } else if (so > scroll.max) {
        p = 0;
        $offset.text(so +"px (above bounds)");
    } else {
        $offset.text(so +"px (within bounds)");
    }
    
    // calculate font-size according to scroll offset
    s = Math.round(size.min + p * size.range);
    // abort if that's our current value, no need to access DOM
    if (s == current) {
        return;
    }
    
    // update font-size
    current = s;
    $header.css('font-size', s);
});