Skip to content

Instantly share code, notes, and snippets.

@james-jlo-long
Last active July 11, 2019 08:39
Show Gist options
  • Save james-jlo-long/536a20b9ffac6f04abfb9f1303f3bbeb to your computer and use it in GitHub Desktop.
Save james-jlo-long/536a20b9ffac6f04abfb9f1303f3bbeb to your computer and use it in GitHub Desktop.
CSS Calisthenics - exercises designed to help teach you better CSS.

CSS Calisthenics

Introduction

A series of exercises designed to help you improve your CSS. This are not rules that should be applied to all style sheets and this is not a measure of CSS quality, merely tools to help you learn some of CSS's strengths.

Pre-processors and styled components

These exercises assume that you have 1 style sheet. We're talking about the CSS that is generated after the pre-processors have run. For styled components, extract all styles (even if the component isn't being used on the current view) and put them into a single style sheet. If you have an inline <style> tag for performance, those styles should be in the single style sheet.

You wouldn't be allowed to add styles using JavaScript - JavaScript would only be allowed to toggle state classes/attributes.

The exercises

No CSS shorthand

Exception: When you're defining all properties.

Short-hand property All properties and values
background
  • background-image: none
  • background-position: 0 0
  • background-size: auto auto
  • background-repeat: repeat
  • background-origin: padding-box
  • background-clip: border-box
  • background-attachment: scroll
  • background-color: transparent
border
  • border-width
    • border-top-width: medium (~3px)
    • border-right-width: medium (~3px)
    • border-bottom-width: medium (~3px)
    • border-left-width: medium (~3px)
  • border-style
    • border-top-style: none
    • border-right-style: none
    • border-bottom-style: none
    • border-left-style: none
  • border-color
    • border-top-color: currentcolor
    • border-right-color: currentcolor
    • border-bottom-color: currentcolor
    • border-left-color: currentcolor
font
  • font-style: normal
  • font-variant: normal
  • font-weight: normal (400)
  • font-stretch: normal
  • font-size: medium (~16px)
  • line-height: normal (~1.2)
  • font-family: (depends on user agent, usually "serif")
margin (padding works the same way)
  • margin-bottom: 0
  • margin-left: 0
  • margin-right: 0
  • margin-top: 0
transition
  • transition-delay: 0s
  • transition-duration: 0s
  • transition-property: all
  • transition-timing-function: ease

Designed to teach you the parts of CSS short-hand that you may not be familiar with.

Max 8 rules per selector

/* 1 rule: */
.my-class {
    display: none;
}

/* 4 rules: */
.my-other-class {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
}

Designed to teach you to separate your style and structure, to discard implicit rules (display:block;width:100%; etc.) and embrace the cascade.

No duplicate selectors

Exception for media queries.

.my-class {}
@media (min-width: 40em) {
    .my-class {}
}

Designed to teach you to re-use classes and reduce CSS bloat. It also helps with the previous rule.

Only style classes (except generic styles, states and pseudo-elements)

You're only allowed a maximum of 1 class, 1 state and 1 pseudo-element.

/* Allowed */
.my-class {}
.my-class:hover {}
.my-class::before {}
.my-class::after:focus {}

You can have custom states or treat attributes like a state.

/* Also allowed */
.my-class.is-something {}
.my-class[hidden] {}

You can use 1 :not as part of the state.

/* Allowed as well */
.my-class:not([open]) {}

The universal selector (*) has no specificity but it can create performance issues. For this exercise, we think of the universal selector as an element selector.

Designed to teach you to think in terms of re-usable components and to separate your styling from your markup.

No nested selectors

/* Disallowed */
.my-class a {}
.my-fist-class .my-second-class {}

Designed to teach you to make your CSS modular.

Content only empty, attr() or counter()

.allowed::before {
    content: "";
    content: attr(data-something);
    content: counter(my-counter);
}

You can combine them, but you can't hard-code content.

.disallowed::before {
    content: "Section " counter(my-counter) ":";
    content: " "; /* Same as "." or ":" */
}

Designed to teach you to keep content out of CSS. This also helps with localisation.

No numbers (some exceptions)

  • 100%, 50%, 25%
  • Calculated values: calc((3 / 8) * 100%)

You can use numbers in media queries.

Designed to teach you to avoid magic numbers.

Maximum 2 units

This also includes media queries.

@media (min-width: 40em) {
    .my-class {
        width: 100%;
    }
}

For hard-mode, one of those units can't be px.

Designed to teach you to keep your units consistent.

Maximum number of selectors

NOTE: I need some way to work out a sensible maximum, these numbers are just off the top of my head.

Assuming that your project has a number of different templates:

  • Maximum of 250 selectors as a base.
  • Maximum of 50 selectors for each of the first 10 templates.
  • Maximum of 10 selectors for each of the next 10 templates.
  • No more selectors for any additional templates.

Grand total of 850 selectors.

NOTE: This total needs to be small enough to make the exercise interesting while not being so small that it's impossible.

/* Two selectors: */
.my-class:hover,
.my-class:focus {}

/* Also two selectors: */
.my-first-class,
.my-second-class {}

/* Two selectors as well: */
.my-class {}
@media (min-width: 40em) {
    .my-class {}
}

Designed to teach you to re-use your classes wherever possible.

No use of !important

Designed to teach you that carefully ordering your styles can help against specificity wars. Look up SMACSS and ITCSS if this is new to you.

Limit 10 float, position, font-size

There can only be a maximum of 10 float rules, 10 position rules and 10 font-size rules.

The float and font-size rules were taken from CSS Lint

Designed to teach you to defer to grid systems or abstract out font sizes etc. Separate style from structure.

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