Skip to content

Instantly share code, notes, and snippets.

@luke-john
Last active April 17, 2018 14:44
Show Gist options
  • Save luke-john/b62e7343fd7859f5fd100afd9a3bccb6 to your computer and use it in GitHub Desktop.
Save luke-john/b62e7343fd7859f5fd100afd9a3bccb6 to your computer and use it in GitHub Desktop.
SWM - Glamorous Styleguide

Glamorous Styleguide

This is a simplified version of the Code Styleguide used at Seven West Media where we use Glamorous for styles on https://thewest.com.au and http://www.perthnow.com.au

Setup

All styled items should have a separate file in the componets folder named according to the component name e.g. heading.styled.tsx Sub-components should exist in a separate folder with the components folder called component If there is more than one component, components should be put into their own files

Component Structure

  • ./Foo
    • /components
    • /Bar
      • Bar.glamorous.tsx
      • Bar.tsx
    • Foo.glamorous.tsx
    • Foo.tsx
// ./Foo/components/Bar/Bar.glamorous.tsx
import * as React from 'react'
import glamorous from 'glamorous'

export const StyledBar = glamorous.div({
    /* styles */
})

// ./Foo/components/Bar/Bar.tsx
import * as React from 'react'

import { StyledBar } from './Bar.glamorous.tsx'

export const Bar: React.SFC<object> = (props) => {
    ...
    return (
        <StyledBar>
            ...
        </StyledBar>
    )
}

// ./Foo/Foo.glamorous.tsx
import * as React from 'react'
import glamorous from 'glamorous'

export const StyledFoo = glamorous.div({
    /* styles */
})

export const StyledBaz = glamorous.span({
    /* styles */
})

// ./Foo/Foo.tsx
import * as React from 'react'

import { StyledFoo } from './Foo.glamorous.tsx'

export const Foo: React.SFC<object> = (props) => {
    ...
    return (
        <StyledFoo>
            ...
            <StyledBaz>
                ...
            </StyledBaz>
        </StyledFoo>
    )
}

How we add typesafety to glamorous withTheme

Typed withTheme

import { withTheme as oldWithTheme } from 'glamorous'
import { Theme } from '.. /__styling/themes'

export interface WithTheme {
    <Props>(component: React.ComponentClass<Props & { theme: Theme }>): React.ComponentClass<Props>
}

export interface WithTheme {
    <Props>(
        component: React.StatelessComponent<Props & { theme: Theme }>
    ): React.StatelessComponent<Props>
}

const withTheme: WithTheme = oldWithTheme

export { withTheme }

withTheme Example

import { Theme } from '.. /__styling/themes'


import { withTheme } from '.. /__styling/glamorous-v4'

export interface Props {
    theme: Theme
}

const InternalComponentName: React.SFC<Props> = () => (
    ...
)

export const ComponentName = withTheme<Props>(InternalComponentName)

How to use props

// ./Foo/Foo.tsx
import { StyledFoo } from './Foo.glamorous.tsx'

export const Foo: React.SFC<object> = (props) => {
    ...
    return (
        <StyledFoo isBar={isBar}>
            ...
        </StyledFoo>
    )
}

// ./Foo.glamorous.tsx
export interface StyledFooProps {
    isBar: boolean
}

export const StyledFoo = glamorous.span<StyledFooProps>(
    {
         width: '100%',
    },
    (props: StyledFooProps) => ({
        display: props.isBar ? none : block
    })
)

Formatting and Structure

  • Settings, mixins, global variables should be imported after components
  • Use one level of indentation for each declaration
  • Add a line break between declarations
  • Grouping
    • States (e.g. hover) should be grouped and come after base theme styles
    • Breakpoints should be included after states and grouped under the breakpoint name (these should increase based on size, e.g. sm, md, lg)
  • Themes are optional
    • If you define a theme you must specify the same keys in all themes, even if they are undefined

Ordering

The following outlines the order for writing your glamorous files in a way that will be easier for you to manage.

  1. Global Styles (e.g. Mixins ) Knowing that you are inheriting a bunch of styles from somewhere else is important, and listing first means you can override the inherited set if you need to.

  2. Component Styles Adding regular styles after allows us to properly override those properties if needed (Overriding styles should be limited as much as possible)

  3. Dynamic Theming ( Product themes / Component themes) Dynamic theming refers to theme based styling - there are two types of styling - Product themes such as fonts or global margins which are applied across the entire project and local themes which are relevant just to the specific component you are working on. Global themes should come before local themes.

  4. Media Queries Media queries typically affect regular styles or includes so we nest them before any pseudo elements of selectors

  5. Pseudo-classes and pseudo-elements Pseudo elements and pseudo classes are directly related to the element itself so, for that reason, we nest them first before other selectors.

  6. Nested components Nested selectors should be avoided where possible, if needed they should come after pseudo-classes and pseudo-elements

Additional usage guidelines

The css prop

Please do not be afraid to use the CSS prop on glamorous components, this does not create inline styles on the component, it pulls the styles out with the rest of the component styles.

Colours

  • Should reference a pre-defined colour variable
  • If it doesn't exist in __styling > settings > colors it speak with design to discuss adding a new colour to the styleguide
  • Once it exists add it to the __styling > settings > colors file under the relevant theme
    • Note: black and white are defined separately
  • It should be given a unique name and prefixed with the base colour e.g. greyKoala or blueSapphire

Z-indexing Management

All z-indexes must be defined in the global z-index file under __styling > settings > z-index.ts

Absolutely no hardcoded z-indexes allowed in the codebase

Functions

Functions can be used in replacement of some scss mixins & functions e.g. calcRem & calcEm

JavaScript Hooks

If needed for third parties, javascript hooks can be added as classes, they should be prefixed e.g. gtm-track, gemini-card etc

This is to ensure we don't remove classes that are used by other scripts

Naming Conventions

All glamorous components should be prefixed with "Styled" and the name should be based on item you are extending e.g. if extending the styles on a Link component it should be StyledLink not StyledTotallyAwesomeThing

export const StyledOrderedList = glamorous.ol(
    {
        padding: `0 ${calcRem(16)}`
    },
    componentTheme(theme => ({
        margin: theme.list.margin
    }))
)

export const StyledUnorderedList = glamorous.ul(
    {
        padding: `0 ${calcRem(16)}`
    },
    componentTheme(theme => ({
        margin: theme.list.margin
    }))
)

CSS Entities for Pseudo-elements

As we are using a JS based solution for our css you need write css entities slightly different

content: '\\002f', // instead of content: '/002f',

To help, here is a handy conversion table: https://brajeshwar.github.io/entities/

Glamorous Display names

DO NOT rely on Glamrorous display names in your css - as they are not added in production only in dev.

Declaration Order

[[TODO: SUPPORT WITH LINTING]] While this would be great we do not expect you to do this without linting so don't get hung up on it, no one's going to pull you up on it!

Grouping your properties will help to create consistent stylesheets.

Grouping order:

  • Positioning - Positioning comes first because it can remove an element from the normal flow of the document and override box model related styles.
  • Layout - Dictates a components dimensions and placement.
  • Text
  • Visual

Typography and visual comes last because it takes place inside the component or without having an impact on positioning and box model.

// positioning
position: 'absolute'
top: 0
right: 0
bottom: 0
left: 0
zIndex: 1

// Layout
display: 'block'
float: 'right
width: 100
height: 100
padding: 1em
margin: 1em

// Text
fontFamily: fonts.sansSerif
fontSize: calcRem(16)
lineHeight: 1.5
color: colors.black
textAlign: 'center'

// Visual
backgroundColor: colors.white
border: 1px solid colors.black
borderRadius: 3px

// Misc
opacity: 1

Created by the awesome frontend team at Seven West Media

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment