styleguide 0.30.11

Frontend Guidelines

HTML

Moving forward we write all our pages using HTML5. The correct doctype is <!DOCTYPE html>. It's important that we use proper semantics in our HTML so dive in and get acquainted with all the new elements in HTML5.

Protocol-relative URLs

To avoid mixing http and https on the same page you can use protocol relative URLs. This is assuming the site you’re pointing to has asset available on both HTTP and HTTPS.

<script src="//dagbladet.com/scripts/app.min.js"></script>

Responsive images

To tackle the current issue regarding images when building a responsive site we have implemented picturefill, a javascript polyfill for the new picture element (and associated features). For now we only use srcset and sizes features on the img element. For an in-depth explanation of how these features work read Eric Portis post Srcset and sizes.

For the sizes attribute we'll be using the same media queries as in our grid specified in the following order; large, medium, small (default). Note that the length value after each media query must be adjusted for each image and breakpoint.

<img sizes="(min-width: 64.063em) 100vw, (min-width: 40.063em) 100vw, 100vw" … >

We create one image for each of the media queries specified in the sizes attribute. Each of these images should have the width of the largest value within the media query.

<img srcset="/test-small.jpg 640w, /test-medium.jpg 1024w, /test-large.jpg 1440w" … >

Putting the pices together.

<img sizes="(min-width: 40.063em) 100vw, (min-width: 64.063em) 100vw, 100vw" srcset="/test-small.jpg 640w, /test-medium.jpg 1024w, /test-large.jpg 1440w" … >

Accessibility

Making content accessible to everyone is encouraged. Good accessibility can help people with disabilities (e.g. blindness and low vision, hearing loss, learning disabilities and limited movement) perceive our content in a meaningful way. There are several things we can do, but the first and most important thing is writing semantically good HTML. We cannot stress that enough.

Universal Design

Universal design means "designing, or accommodating, the main solution with regards to physical conditions, so that the solution may be used by as many people as possible," regardless of disability.

In Norway we have regulations stating new ICT solutions should be universally designed from 1st July 2014. Existing ICT solutions should be universally designed from 2021. Short version – this means that we are required to achieve a AA on WCAG 2.0. The Norwegian Ministry of Government Administration, Reform and Church Affairs has a list of the cirteria required (norwegian) to achieve the AA grade.

In addition, we assign landmark roles using WAI-ARIA to assist navigation.

Schemas

This site [schema.org] provides a collection of schemas that webmasters can use to markup HTML pages in ways recognized by major search providers, and that can also be used for structured data interoperability (e.g. in JSON). Search engines including Bing, Google, Yahoo! and Yandex rely on this markup to improve the display of search results, making it easier for people to find the right Web pages.

For the benefit of search providers we apply schemas where appropriate. Here are a few of the most used schemas you should be familiar with:

Outline Algorithm

The document outlining algorithm is a mechanism for producing outline summaries of Web pages based on how they are marked up. Every Web page has an outline…

There is a great article on Smashing Magazine regarding the HTML5 Outline Algorithm.

So again, writing semantically good HTML, should get us far in creating a good document outline. There is a great litte tool you can use to check the outline made by Geoffrey Sneddon

Loading CSS and Javascripts

Getting content in front of our readers as fast as possible is one of the most important things we do for the overall experience. Google Web Fundementals covers the critical rendering path and is worth a read.

The approach is simple but delicate. Critical CSS is inlined in the head of the document, the rest is loaded after first paint. Fonts are cached in localStorage to prevent FOUC. See examples of how to load CSS and Javascript in a non blocking manner.

Javascript

Writing vanilla javascript is always preferred, but there is no point in reinveting the wheel. jQuery is usually required on all our pages. It covers our most basic needs and fixes browser incompatibilities. In addition we use parts of Foundation that gives us a few helpful utilities like throttle and debounce. Mousetrap is available for binding keyboard shortcuts, but please don't override the browsers default shortcuts. For templating Mustache is always at hand. Moment is usefull for formating and manipulating dates.

Avoid adding any more libraries unless they are used on all pages. Third-party libraries are added using Bower.

Loading scripts

We want our pages to render as fast as possible. Duh! This means that scripts should not block DOM or CSSOM rendering. Loading scripts using the async attribute ensures this.

<body>
    <!-- Your content -->
    <script async src="/scripts/app.min.js"></script>
</body>

Writing components

We try to create all our component using the same basic pattern. Each component is attached to the global db namespace. It must expose at least three public functions, init, reflow and destroy. init is called on each components when the DOM is ready. reflow is meant to be called when you have injected new content into the DOM, and want to attach components to the new content. Call destroy when you want to kill the component.

Our preferred way of attaching components to elements is adding a data-attribute to the element and look for that data-attribute when initializing the component (see example below). If you need to pass options to the component, you can add the options to a data-options attribute as a semicolon delimited set of values, and use Foundation.utils.data_options(); to parse these.

Note how we import globals like jQuery. This allows us to alias these and more easily switch them out in the future.

;(function() {
    'use strict';

    window.db.Mycomponent = (function($){
        function toggle(event){
            //Do some toggle
        }

        function init(){
            $('[data-mycomponent]').each(function(i, el){
                $(el).off('click').on('click', toggle);

                var defaults = {
                    text : '',
                    classes : "fixed overlay"
                };
                options = $.extend({}, defaults, Foundation.utils.data_options( $(el) ));

                $(el).data('options', options);
            });
        };

        function destroy(){
            $('[data-mycomponent]').each(function(i, el){
                $(el).unbind('click');
            });
        };

        //Return public pointers
        return {
            init: init,
            reflow: init,
            destroy: destroy
        };
    })(jQuery);

})();

CSS

Dagbladet is buildt as a customized fork of the Foundation framework with some additional components on top.

Loading CSS

Critical CSS should be inlined in the head of the document. The critical styles can at all times be found at //styleguide.dagbladet.no/stylesheets/critical.css. The main CSS should be loaded after first paint, to make this happen place this script right before the closing body-tag:

var cb = function() {
    var h = document.getElementsByTagName('head')[0];
    var useSSL = "https:" == document.location.protocol;

    var l = document.createElement('link');
    l.rel = 'stylesheet';
    l.href = (useSSL ? "https:" : "http:") + '//styleguide.dagbladet.no/stylesheets/app.css';

    h.parentNode.insertBefore(l, h);
};

var raf = requestAnimationFrame || mozRequestAnimationFrame || webkitRequestAnimationFrame || msRequestAnimationFrame;
if(raf){
    raf(cb);
} else {
    window.addEventListener('domContentLoaded', cb);
};

We also want to load fonts as fast as possible to prevent FOUC. This script should be placed in the head of the page. Fonts are then stored and cahed in localStorage.

! function() {
    function e(e, t, n) {
        e.addEventListener ? e.addEventListener(t, n, !1) : e.attachEvent && e.attachEvent("on" + t, n)
    }

    function t(e) {
        return window.localStorage && localStorage.font_css_cache && localStorage.font_css_cache_file === e
    }

    function n() {
        if (window.localStorage && window.XMLHttpRequest)
            if (t(o)) a(localStorage.font_css_cache);
            else {
                var n = new XMLHttpRequest;
                n.open("GET", o, !0), e(n, "load", function() {
                    4 === n.readyState && (a(n.responseText), localStorage.font_css_cache = n.responseText, localStorage.font_css_cache_file = o)
                }), n.send()
            } else {
            var c = document.createElement("link");
            c.href = o, c.rel = "stylesheet", c.type = "text/css", document.getElementsByTagName("head")[0].appendChild(c), document.cookie = "font_css_cache"
        }
    }

    function a(e) {
        var t = document.createElement("style");
        t.innerHTML = e, document.getElementsByTagName("head")[0].appendChild(t)
    }
    var useSSL = "https:" == document.location.protocol;
    var o = (useSSL ? "https:" : "http:") + "//styleguide.dagbladet.no/stylesheets/fonts.css";
    window.localStorage && localStorage.font_css_cache || document.cookie.indexOf("font_css_cache") > -1 ? n() : e(window, "load", n)
}();

Organizing CSS Rules

CSS rules are categorizes into three parts. Base rules are the defaults. They are always element selectors like body, h1 and p. Layouts are large sections and usually appears only once on each page. Layouts are often wrappers that holds togheter several components. Components are small reusable blocks of content like buttons, tables, panels or forms. They often have several variations and states.

A fourth category, that are not really rules are animations/transitions.

Measurment units

We use rem for font-size with a base of 16px. This allows for better scaling when creating components and layouts. In some cases, like the front page, we use vm to allow flexible scaling of headlines.

Image urls

Images that follow this project must be added to the /assets folder. To ensure that the right image is used with the right version of the stylesheets we use a build in helper in sass image-url(some-awsome-image.jpg). Documentation for image-path.

Naming conventions

Specificity

As a rule of thumb use class names. Try minimizing the depth of your selectors as mutch as possible. Think twice before you go combining element and classes like article.preview{ … }. For elements that can only occur once you should use an ID.

Animations and Transitions

When writing animations and transitions try your best to avoid creating jank. Using the css properties listed below will help you eliminate jank and reach the magical 60fps. Note: The element will need to be on its own composition layer.

Position: transform: translate(npx, npx);
Scale: transform: scale(n);
Rotation: transform: rotate(ndeg);
Opacity: opacity: 0…1;

Althoug not widely supported yet, you should also add the will-change porperty where approprite.

.is-going-to-move{
    will-change: transform;
}

Experimental and deprecated features

When working on experimental new features add a -experimental suffix to your the css namespace.

.button-experimental{
    background: rgb(214, 0, 0);
}

Variation for A/B tesing

When planning a A/B test with multiple variations – add a -variation-# suffix to each variation in the css namespace.

.button-variation-1{
    background: rgb(214, 0, 0);
}

.button-variation-2{
    background: rgb(214, 0, 0);
    text-decoration: underline;
}

.button-variation-3{
    background: rgb(32, 32, 32);
    text-decoration: underline;
}

Writing components

When creating customizable components with multiple variations, we use a simple pattern base/style.

$mycomponent-color: #D60000 !default;

// Create a -base mixin. It contains rules for the default styling of the component.
@mixin mycomponent-base{
    //Base styles for the component
    …
};

// Make the component customizable by creating a -style mixin containing styles for each customizable property. Each of the property values are passed as arguments to the mixin.
@mixin mycomponent-style($color: $mycomponent-color){
    //Add styling like color etc. with values passed as arguments
    //Remember to add defaluts
    …
};

// Optinally you can create a mixin including the -base and -style mixins as a shourtcut.
@mixin mycomponent(){
    @include mycomponent-base;
    @include mycomponent-style;
}

// Finally, include the mixins and create the variations needed.
.some-classname{
    @include mycomponent;
    &.example-1{
        @include mycomponent-style($color: #222222);
    }
    &.example-2{
        @include mycomponent-style($color: #14A8E2);
    }
}