Building the interface for wearecolony.com

samloomes@gmail.com

@samloomes

Background

What is We Are Colony?

  • VOD platform for independent film
  • Content organised into "Companions"
  • Startup that has been invested in by the Zone exec
  • Part of the Seedcamp family
  • Won Technology Strategy Board SMART Award
  • Won NESTA Digital R&D Fund for the Arts

Back-end platform

  • .NET application
  • IIS
  • Razor templates
  • AWS EC2/Cloudfront/Elastic Beanstalk

Front-end templates

  • Separate repository
  • No database/building/back-end devs free from me!
  • Easy to keep src/img directories in sync with main repository
  • Keeping markup in sync slightly harder

PHP


# Start a PHP server from a directory, optionally specifying the port
# (Requires PHP 5.4.0+.)
function phpserver() {
    local port="${1:-4000}"
    local ip=$(ipconfig getifaddr en4) #ensure correct interface with ifconfig
    sleep 1 && open "http://${ip}:${port}/" &
    php -S "${ip}:${port}"
} 

Grunt

  • Compass
  • LiveReload
  • RequireJS
  • Webfont

Styling

Modules!

Current Sass file breakdown

  • 3 Utility
  • 14 Generic
  • 2 Interfaces
  • 51 Modules (!)
  • 5 Pages

Functions

Units/Typography

My brain doesn't work in ems/rems/ratios

@function em($target, $context: $font-size) {
    @return ($target / $context) * 1em;
}

@function rem($target, $context: $font-size) {
    @return ($target / $context) * 1rem;
}

@function lh($target, $context: $font-size) {
    @return $target / $context;
}

// Global variables set in _config.scss: $font-size: 16px;

// Example
.example-selector {
    font-size: em(22px);
    line-height: lh(50px, 22px);
    margin-bottom: em(20px, 22px);
}

Functions

Grid

  • We're (sort of) not using one
  • Found I was overriding grid styles more often than not
  • Really I just wanted something to calculate width


@function cw($columns, $context: $font-size) {
    @return ($columns * em($width-column, $context)) + (($columns - 1) * em($space-s, $context));
}

// Global variables set in _config.scss: $font-size: 16px; $space-s: 20px; $width-column: 60px;// Examples
.example-selector {
    width: cw(8);
}

.example-heading-selector {
    font-size: em(22px);
    max-width: cw(6, 22px);
}

Mixins

Breakpoints

  • Included inside selectors
  • Works great with modular approach
  • Also great with cw function


@mixin bp($point) {
    @media (max-width: ($point + em(2 * $space-s))) {
        @content;
    }
}

// Global variables set in _config.scss: $space-s: 20px;

// Example
.example-selector {
    position: absolute;

    @include bp(cw(6)) {
        position: relative;
    }
}

Priorities and alternatives

Got the idea from mailchimp

Use classes to denote (and style appropriately) element variations in a similar manner to heading tags h1 to h6

More important elements have a higher priority, variations within priority levels are alternatives

<button class="p1">Buy now</button><button class="p2">Not so important button</button><button class="p2 a1">Not so important button variation</button>

Alternative classes became my default go-to class name

JavaScript

jQuery

  • Using it
  • Didn't think I would be ditching IE8
  • gzipped and minified ~34kb
  • Probably would try to avoid it if doing it again
  • Old-school server-side rendering

    Tried a few different approaches: Angular, JSON api with Mustache templates


    Settled on server side rendering of page templates progressively enhanced with JavaScript because Colony is all about the content


    Twitter found it cut load times to 1/5th:

    https://blog.twitter.com/2012/improving-performance-on-twittercom


    URLs point directly to the right content, Paul Irish talked about the effect of Imgur using JSON APIs on their (slow) page speed in Fluent 2014 keynote:

    https://www.youtube.com/watch?v=R8W_6xWphtw

    Data behaviors (are awesome)

    Technique I got turned on to when working at AREA17

    • JavaScript functionality split into separate 'behaviors' (carousel, slider, asset)
    • Behaviors linked to markup by data-behavior attribute

    // Example markup
    <div class="asset-bucket" data-behavior="slider">
        <h2 class="heading-p4">Video &amp; Audio</h2>
    
        <div class="items assets">
            <div class="item-wrapper">
                <a href="/pages/companion-explore-vod.php" class="item asset" data-behavior="asset">
                    ...
                </a>

    I put it into the AMD pattern for RequireJS:

    Data behaviors

  • Clear modular pattern, behaviors are clearly defined in the markup, obvious where to find logic
  • Separate from HTML classes
  • behaviors.init function parses markup for behaviors and JS downloaded as needed (with RequireJS)
  • New markup (e.g. AJAX response) can be parsed and interpreted in the same way

  • Pub Sub

    • Sometimes behaviors need to talk to each other
    • Behaviors loaded in the order they appear in the markup not necessarily the order you want/expect
    • Want to keep things modular and loosely coupled
    • Pub Sub pattern is essentially custom events
    • 'Topics' (names of the events) are published when you want to notify the app that something has happened/something should happen
    • Can optionally pass associated data
    • I used jQuery Tiny Pub Sub (12 lines of code)


    // asset.js: In asset behavior, it's possible to hit the paywall instead of getting the asset
    $.publish('/paywall/hit', data);
    
    // paywall.js: In paywall behavior we subscribe/handle the topic, call displayPaywall
    function handleTopics() {
        $.subscribe('/paywall/hit', function(e, data) {
            displayPaywall(data);
        });
    }
    

    Animations

    • Tested animations using jQuery, GSAP, CSS
    • jQuery worst frames per second
    • GSAP and CSS comparable
    • Settled on CSS with no fallback
    • Already using CSS transitions throughout the site
    • Less JS overhead

    Further information



    Fin

    Building the interface for wearecolony.com

    By Sam Loomes

    Building the interface for wearecolony.com

    • 704