-
Notifications
You must be signed in to change notification settings - Fork 1
CSS guidance
All components styles will be nested inside a namespaced class and concatenated using BEMIT notation
A useful starting point for BEMIT notation
Stylus can concatenate anything using the & operator, make sure that you use it properly in order to ensure minimal repetition and over-specificity.
This is not acceptable
CSS
.c-product-tags {
text-align: center;
padding-left: 20px;
padding-right: 20px;
}
.c-product-tags__title {
margin-top: 0;
margin-bottom: 35px;
}
This is acceptable
CSS
.c-product-tags {
text-align: center;
padding-left: 20px;
padding-right: 20px;
&__title {
margin-top: 0;
margin-bottom: 35px;
}
}
NOTE: Utilities and objects may occasionally require two classes to work.
e.g.
.o-title {
margin-bottom: 2rem;
&--page {
font-weight: bold;
}
}
<h1 class="o-title o-title--page">Welcome</h1>
If the first 'o-title' is omitted the margin-bottom property will not be applied
All components should be prefixed with a 'c'. All reusable single items (like a button for example) is an object and should be prefixed with 'o' Any class which modifies the behaviour of another item is a utility class and should be prefixed with'u'. Layout Items (which set the general layout of a template) should begin with 'l'. Template items will allow you to define overrides on components for specific templates and will begin with 't'.
e.g.
Component: .c-product-tags
Object: .o-button
Utility: .u-highlight
Layout: .l-primary
Template: .t-primary
In fact...
A raw class is any class that doesn't have a prefix and/or namespace on it and should be avoided at all costs. As this is a wordpress site and wordpress generates it's own classes occasionally, there will be times where it is unavoidable but you should never add a raw class yourself.
Stylus has a plugin called 'Rupture', this makes media queries incredibly simple by slicing the page up into named breakpoints and then referencing that breakpoint by using a mixin:
e.g.
+above(m) {
margin: 0;
}
The Clarity toolkit has 7 breakpoints which are as follows:
-
xxs
:320px
-
xs
:410px
-
s
:500px
-
m
:740px
-
l
:1020px
-
xl
:1280px
-
xxl
:1700px;
Additional breakpoints can be explicity specified if needed but please do this as a last resort.
e.g.
+above('990px') {
display: none;
}
Just like with normal media queries, a mobile-first approach should be used, use of `+below()' or '+between()' is possible but discouraged. Only use these if it's absolutely needed and be prepared to justify it in a code review.
e.g.
This is not acceptable
&__tags {
li {
margin-right: 6px;
margin-bottom: 10px;
display: inline-block;
+below(m) {
margin-right: 0;
}
}
}
This is acceptable
&__tags {
li {
margin-bottom: 10px;
display: inline-block;
+above(m) {
margin-right: 6px;
}
}
}
There is a global print stylesheet file in src/globals/css which should handle most of the possible things that will happen in printing but it does make sense to keep print styles as component-based as the rest. In order to create a print stylesheet for your component, simply create a filed called style.print.styl and add your styles in there, they will be automatically compiled into the main print stylesheet.
Remember. Don't use regular values for print stylesheets, use millimetres. Also print stylesheets should not use jeet or rupture.
IE stylesheets should be created inside each component and be named style.ie.styl. You should also replace any references to the _toolkit file with _ietoolkit as this one is tailored for IE.
Do not duplicate styles. The IE stylesheet should ONLY be used for overrides.
Please note: The use of !important is allowed here but please use it sparingly
If you are using code which is similar to code used in another function, turn that code into an object, utility or mixin and use/extend it. Don't create a new instance of something which is (practically) identical.
e.g.
This is not acceptable
HTML
<a class="o-tag-btn"></a>
CSS
.o-tag-btn {
background-color: $light;
border: 1px solid $border;
color: $gray;
cursor: pointer;
outline: none;
font-size: $innercore;
text-transform: none;
display: inline-block;
&:hover, &:active, &:focus {
text-decoration: none;
color: currentColor;
}
}
.o-btn {
background-color: $dark;
border: 1px solid $border;
color: $gray;
cursor: pointer;
outline: none;
font-size: $innercore;
text-transform: none;
display: inline-block;
&:hover, &:active, &:focus {
text-decoration: none;
color: currentColor;
}
}
This is acceptable
HTML
<a href="o-btn o-tag-btn"></a>
CSS
.o-tag-btn {
background-color: $light;
}
.o-btn {
background-color: $dark;
border: 1px solid $border;
color: $gray;
cursor: pointer;
outline: none;
font-size: $innercore;
text-transform: none;
display: inline-block;
&:hover, &:active, &:focus {
text-decoration: none;
color: currentColor;
}
}
This is also acceptable
HTML
<a href="o-tag-btn"></a>
CSS
.o-tag-btn {
@extend .o-btn;
background-color: $light;
}
.o-btn {
background-color: $dark;
border: 1px solid $border;
color: $gray;
cursor: pointer;
outline: none;
font-size: $innercore;
text-transform: none;
display: inline-block;
&:hover, &:active, &:focus {
text-decoration: none;
color: currentColor;
}
}
If this sort of thing was common, it may be appropriate to create a mixin instead.
The build tool will have auto prefixing enabled via the 'autoprefixer' plugin for Grunt, provided that the software is kept up-to-date then this will ensure that the correct prefixing is always being used for the right browsers. Because of this, don't add prefixing to a project, let the tool do it for you.
This is not acceptable
CSS
-o-transition: background-color .6s ease-out;
-ms-transition: background-color .6s ease-out;
-moz-transition: background-color .6s ease-out;
-webkit-transition: background-color .6s ease-out;
transition: background-color .6s ease-out;
This is acceptable
CSS
transition: background-color .6s ease-out
Screen readers and people who have to use a keyboard, pad to navigate a site can't rely on hover states. However they still need visual feedback.
As this closely follows GDS there is a focus property on every link but ensure that it works visually for the link you have created.
Occasionally, using a custom value is necessary but by default you should use the pre-existing variables to specify things like breakpoints, font-sizes, margin/padding etc...
This is not acceptable
CSS
+above(1024px) {
.c-main-nav {
margin: 10px;
}
}
This is acceptable
CSS
+above(l) {
.c-main-nav {
margin: $spacing;
}
}
If a variable is used all over the place and could conceivable be changed in the future, make sure the variable name doesn't have any non-transferrable meaning to it. Creating an abstract (but memorable) variable name is the better option.
e.g.
These are not acceptable
$16px = 1.6rem
$large = 1.6rem
$header2 = 1.6rem
This is acceptable
$outerCore = 1.9rem
This way, if another level needs to be added or if the font-size changes in the future. We don't have a ton of variables which need to be found and replaced as they no longer make sense.
Unless something has to be a fixed width then don't use Pixel values. Use either em/rem units or percentages (if you are laying something out to the grid then use jeet, see below). Always take the above point into account though, if it's possible to use a variable then use that instead.
This is not acceptable
CSS
.box {
width: 400px;
margin: 20px;
}
This is acceptable
CSS
.box {
width: 20%;
margin: $spacing*2
}
Whilst we are on the subject of widths, wherever possible, widths should be either flexible or set to the grid. As we are using Jeet, you should set the width using that wherever possible.
This is not acceptable
CSS
.box-aligned-to-grid {
width: 400px;
margin: 20px;
}
This is acceptable
CSS
.box-aligned-to-grid {
column(1/4);
}
Don't automatically add box-sizing:border-box
or margin:0
to elements. The reset stylesheet will cover most of these. In fact it is always a good idea to refactor any css class you work on to ensure all properties are actually needed.
This is not acceptable
CSS
.list {
box-sizing: border-box;
margin: 0;
padding: 0;
list-style-type: none;
color: $primary;
}
This is acceptable
CSS
.list {
color: $primary;
}
Contrary to popular believe, the !important
flag is not something which should never be used, however there are only three situations where it can reasonable used in:
1: Active development
Sometimes you want to test something and adding !important
to a property will make it easier, provided you remove it as soon as your testing is done, that's fine.
2: Global classes
Some global classes should never be overwritten by other styles, if this is the case then using !important
can ensure this. This is actually what it was created for.
3: Media Queries
Sometimes, a media query needs to overwrite something that already exists, rather than add undue nesting or referencing other components in order to achieve the override then the use of !important
is acceptable. However if the component is structured correctly, this shouldn't be required.
Note: Even in the above examples. Only use !important
if you absolutely have to, the flag should only be added when you've exhausted all other options.
As we've namespaced all our components (see the first standard) we can be assured that there will be no styling overlaps or conflicts. Each component should only have access to two scopes: Itself and the global namespace. Don't put any styles from other components within the current one and don't put any component related styles in the global namespace. If overrides are required then keep them to the 'Parent overrides' section and use them only when required. (Also ensure they are documented).
Note: There is one exception to this rule and that is layouts if a component CONTAINS a layout (e.g. 'c-footer') then you can reference that component in the layouts.styl file. If a component should change depending on it's parent layout then that is a parent override and belongs in the component stylesheet.
This one is a basic rule, don't add global styles to any stylesheet which isn't a global stylesheet.
ID's may be in the HTML, but these ID's should never be used to attach styles to.
This is not acceptable
HTML
<div id="container"></div>
CSS
#container {
color: $primary;
}
This is acceptable
HTML
<div id="container" class="c-container"></div>
CSS
.c-container {
color: $primary;
}
Javascript classes (prefixed with js-
) should be kept separate from styling classes. Never apply styling to an element using the JS class. This ensures that behaviour and appearance are kept separate from one-another, so if the javascript or style class has to change for any reason, the other class is unaffected.
The naming convention should follow the same process as naming components. So instead of 'c-header', use 'js-header'.
The reverse of this rule is also true, don't use styling classes for JS hooks.
Caveat: If a style is directly attached to a js behaviour and wouldn't be styled at all without that behaviour, then it is acceptable.
This is not acceptable
HTML
<div class="js-header"></div>
CSS
.js-header {
font-weight:bold;
}
This is acceptable
HTML
<div class="js-header c-header"></div>
CSS
.c-header {
font-weight:bold;
}
Universal selectors (*
is a good example of this) are not great for performance as they have to match multiple elements before they can finish their task. In reset stylesheets, this is an acceptable overhead. However they shouldn't be used as a matter of course.
There is a oft-quoted idea that using descendant and child (>
) selectors has a performance impact. Whilst this is true, the impact is negligable.
So if you want to write .list > li a
instead of .list-item-link{}
then go ahead. Just make sure you follow the next rule when you do it.
In the example above, I targeted a link in a list like this .list > li a
, whilst there may be a few valid reasons for doing this (for example you only want to target the links in the top level of a nested list), it's often overkill to specify that much. .list a
will work just find for cases where you don't need the extra specificity.
This one ties to the one above. Don't write css like this:
div.container {
padding: $padding
}
Whilst this will work fine if the HTML looks like this:
<div class="container"></div>
Specifying things at a tag level will add to performance, also what happens to the styling if the HTML changes to this:
<article class="container"></article>
Suddenly that CSS which specified that only div
tags can have a class of 'container' fails as there was nothing to accommodate an article
tag with a container class on it.
Location specific selectors (e.g. :nth-child(n)
, :last-child
etc...) are often useful but extra care must be taken with these to ensure that the future of the document is being taken into consideration. If the HTML structure changes at all, how will that impact your styling?
The performance impact here is minor but as there is no valid reason to specify a unit then it's still good practice to not do so.
This is unacceptable
CSS
margin: 0px;
This is acceptable
CSS
margin: 0;
These instructions apply to the main Intranet website system. Please visit https://github.com/ministryofjustice/intranet-base-docker to view the base system for this website.