Origami Frontend Components & Services

Sass Specification

Origami component styles are authored in Sass, specifically the SCSS syntax. Sass features should be used only where they result in increased clarity and reuse. Care should be taken that the resulting CSS is not compromised by unnecessary Sass nesting.

Syntax Convention

Sass must validate using the Origami Sass Lint rules, though exceptions may be enabled temporarily within a component using Sass Lint comments.

Component indent type (tabs or spaces) is not standardised: developers must respect whatever indent type is already in use when editing existing components.

In addition, component CSS should not use !important. Valid use cases for !important exist, but usually only at the product level. If !important is used in a component, a comment must be left in code to explain why it was necessary.

Naming Conventions

CSS/Sass has limited encapsulation, so strict adherence to namespacing rules is essential.

CSS selectors should follow the BEM naming convention. They must also be prefixed with the component name and written as hyphen separated, lowercase strings:

Sass variables must be prefixed with the component name and written as hyphen separated, lowercase strings:

Sass variables should also be named by their purpose, rather than their value:

Sass mixins and functions must also be prefixed with the component name, and be written in camel-case:

CSS Selectors

A component must not style an element unless it, or any ancestor element, has a CSS class which starts with the name of the component e.g. o-componentname (see naming conventions).

ID selectors (#) must not be used at all:

Unprefixed tag selectors (e.g. h1) must not be used alone. But tag selectors may be used if prefixed with a correctly namespaced selector:

Combination selectors, those that specify a combination of tag name, class and/or ID in the same selector token must not be used:

Selectors should contain a single operand, with the following exceptions:

High specificity should be minimised. For instance, the pseudo class :not should not be used to avoid high specificity. Increased specificity must not be used to overcome an existing overly-specific selector - make the existing one less specific, or use new class names. Prefer classes and duplicated properties over specificity:

Pseudo selectors such as :focus or :hover should be used to style a component’s state. In the case of :focus, Origami components must enable a focused style that is distinct from its normal style (the focus style is usually provided by o-normalise).

Where an ARIA role is appropriate (no ARIA is better than bad ARIA)), it should be used to style a component’s state. For example aria-expanded, with a correctly namespaced selector, should be used to style an expandable element:

Private Sass

As Sass has limited encapsulation, any Sass (e.g. mixin, function, variable) that is intended for private use by the component only must be prefixed with an underscore character. Private Sass must not be documented in the README but may be documented in code comments.

Sass Includes

If a component contains SCSS files other than the main file listed in bower.json:

Sass Variables

If a variable is public and could be used as a configurable option in products consuming the component, the variable must be defined with !default, and added to the component’s documentation.

Components must not overwrite variables defined by another component. Instead, a component may define a new variable in its own namespace and set it to the value of the dependency’s variable.

Sass Placeholders

Placeholder selectors (%) must not be used to reference other components, but may be used within a component, see Issue #254.

The @extends command must not be used to extend placeholders defined in other components, unless the component can only be consumed via @extends for historical reasons. This is because extending placeholders defined in other components creates unpredictable cascades and unreliable results, as the order components are included is unpredictable. A placeholder may be extended if defined within the same component.

Sass Silent Mode

Silent mode means a component’s Sass will compile to an empty string, but provides mixins or variables which may be used by dependent code. Silent mode enables projects to include styles granularly, and components to include styles from other components.

Components that make use of styles defined in other components which support silent mode must use those styles silently, e.g. for a component o-foo which depends on o-bar:

@import ‘o-bar/main’;

@mixin oFoo {
    .o-foo {
	    @include oBarContent();
	    margin-top: 1em;
    }
}

To support silent mode, components must include a public, silent mode variable which is true by default $o-{componentname}-is-silent: true !default;. That is, no styles are output by default. When silent mode has been turned off and the component’s CSS has been output, the component must reset the silent mode variable:

@if ($o-thing-is-silent == false) {
	@include oThing();

	// Prevent o-thing styles being output again
	$o-thing-is-silent: true !global;
}

This prevents the accidental output of styles if the component is included twice in the same product. For example, given component A and component B both include a dependency of component C.

Branding

Origami components are used by products across the Financial Times Group. Some of these products or product groups require a distinct appearence or feature. To cater for these usecases Origami components may change their appearence by supporting one or more of the following brands:

A brand may be thought of as a theme, in that it uses Sass to change the appearence of a component. But it may also provide unique features with brand specifc Sass. For an example see our component brand documentation.

A project chooses a brand by setting the brand variable, which affects all Origami components included by that project. If no brand is chosen the master brand is used by default.

Register Supported Brands

If a component supports brands, it must register the brands it supports under the brands property in its origami.json file. E.g. to support all three Origami brands add:

"brands" : [
    "master",
    "internal",
    "whitelabel"
],

Create A Brand Sass File

All functions and mixins which delegate to the o-brand component, and brand configuration, should be placed in the component’s src/scss/_brand.scss file.

Include The oBrand Component

Components which support brands must include the o-brand component as a dependency, which provides functions and mixins to customise a component per brand.

The o-brand component must not be used directly by projects, it is intended for use within other Origami components. To provide a public interface for brand mixins like oBrandCustomize, create a component specific mixin which delegates to it. E.g. For a component o-example:

@mixin oExampleCustomize($variables) {
	@include oBrandCustomize($component: 'o-example', $variables);
}

See the o-brand README to learn how to add brand support to a component.

Feature Flags

To support a core and enhanced experience components must render acceptably without JavaScript avalible. Styles which only apply if JavaScript is avalible must be applied with a feature detect such as .o--if-js, and to hide an element of a component when JavaScript is avalible use o--if-no-js. If the component provides its own JavaScript feature flag, it must be named .o-componentname--js.

To detect other features, standardised feature detects should be used as a preference, such as the CSS @supports at-rule. Otherwise a CSS class on the documentElement may be used to indicate feature support. The class name should be configurable, and default to the class name used by Modernizr:

$o-thing-inline-svg-support: ‘.inlinesvg’ !default;
$o-thing-inline-svg-support .o-thing__feature {
    // inline svg
}

Component developers must not use feature flags that need to be set manually by a product developer (i.e. those outside Modernizr or Origami). Component developers must assume that feature flag classes will be set on the documentElement, i.e. the HTML tag.

Browser Targeting

Where a feature flag is not possible, developers may choose to target specific browsers (a graceful degradation technique).

In order of preference, when targeting styles at a specific browser or user-agent, component developers should:

Component developers must not use IE conditional comments to target user agents (use browser hacks instead).