Order.less is a library of Less mixins for precise control over typographic contrast, rhythm and layout. It was designed to fit seamlessly into any project and does not put any restrictions on your stylesheet structure. You set the number of columns, the gutter and baseline sizes, your font size scale, and use the same offset and size property names as you do in CSS. The library does all computations and adjustments — no extra HTML markup required!
Order.less is made of three loosely coupled modules:
- Column grid mixins enable you to define a uniform grid with fixed inner gutters, and set elements' padding, margin, offset and width in columns.
- Baseline grid mixins let you control vertical rhythm of the document by setting padding, margin, offset and height in baseline rows. It can also automatically shift elements to sit on baseline.
- Font size scale mixins let you define a custom font size scale and set elements' font size to a value from that scale.
Requirements: Less v2.2.0; calc()
support.
NPM: npm install --save order.less
Bower: bower install --save order.less
Column grid mixins let you define a uniform grid with fixed inner gutters, and set elements' padding, margin, offset and width in columns. At the moment, only uniform grids with inner gutters are supported, e.g. a 3-column grid will have 2 gutters between 3 columns of equal width.
Here is an example of a basic layout implemented using this module:
HTML code (see full listing):
<div id="content">
<div class="primary">Main content</div>
<div class="secondary">Secondary content</div>
<div class="secondary">Secondary content</div>
</div>
<div id="sidebar">Sidebar</div>
<ul id="grid"><!--
We must bust the whitespace around all items, because
they will be rendered as inline blocks. You don't have
to do this, if you are using floated or flexible boxes.
--><li>Item 1</li><!--
--><li>Item 2</li><!--
--><li>Item 3</li><!--
--><li>Item 4</li><!--
--><li>Item 5</li><!--
--><li>Item 6</li><!--
--><li>Item 7</li><!--
--><li>Item 8</li><!--
--><li>Item 9</li><!--
--></ul>
Less code (see full listing):
@default-grid-width: 840px;
@default-grid-gutter: 24px;
@default-grid-columns: 3;
@items-grid-width: @default-grid-width;
@items-grid-gutter: @default-grid-gutter;
@items-grid-columns: 5;
.use-column-grid(default);
#content {
float: left;
.width(2);
> .secondary {
float: left;
.width(1, 2);
& + .secondary {
.margin-left(@grid-gutter, 2);
}
}
}
#sidebar {
float: right;
.width(1);
}
#grid {
.use-column-grid(items);
> * {
display: inline-block;
.width(1);
.margin-right(@grid-gutter);
vertical-align: top;
&:nth-child(5n) {
.margin-right(0);
}
}
}
As you can see, the library only sets width
and margin
properties and leaves it up to you which layout module to use.
Defines the grid and exports other mixins.
- pixel
@width
– optimal grid width - pixel
@gutter
- number
@columns
Or:
- keyword
@name
- pixel
@grid-width
- pixel
@grid-gutter
- number
@grid-columns
.use-column-grid(940px, 20px, 12);
Alternatively, you can define a grid as a set of variables and reference it by name:
@desktop-grid-width: 940px;
@desktop-grid-gutter: 20px;
@desktop-grid-columns: 12;
.use-column-grid(desktop);
Sets background
property of an element to show grid columns and/or gutters.
- (optional) number
@span
– number of columns - (optional) color
@color
– base fill color
main {
.show-columns(3, blue);
.show-gutters(5, green);
}
It should render like this in the browser:
These mixins let you set the respective CSS property in grid columns.
- number
@span
– number of columns - (optional) pixel
@nudge
– amount of pixels to nudge - (optional) number
@base
– parent width in columns - (optional) pixel
@base-nudge
– amount of pixels parent width was nudged by
div {
.width(6); // set width to 6 columns
.width(3, 6); // set width to 3 columns in a 6 column grid
.width(1, -10px, 6); // same as above, but decrease width by 10px
}
These mixins let you set the respective CSS property in grid columns.
- (optional) number
@span
– number of columns the property spans - (optional) pixel
@nudge
– amount of pixels to nudge - (optional) number
@base
– parent width in columns - (optional) pixel
@base-nudge
– amount of pixels parent width was nudged by
NB! You must specify either @span
or @nudge
!
div {
.left(20px); // set left to 20px
.left(1, 6); // set left to 1 column in a 6 column grid
.left(1, -10px, 6); // same as above, but nudge element 10px left
}
These mixins let you control vertical rhythm of the document by setting padding, margin, offset and height in baseline rows. It can also automatically shift elements to sit on baseline, if their font size, line height and/or font family is changed.
A body of copy is set in three typefaces, with vertical rhythm and baseline alignment preserved throughout:
HTML code (see full listing):
<h1>Eu vim fugit constituto sadipscing</h1>
<blockquote>
<p>Lorem ipsum dolor sit amet, mel sumo salutandi ea, et dolorem similique vel. Graeco percipit repudiare eum ut, per aeque graecis id. Per eu euismod euripidis, mel no oratio recteque. Sumo aliquid ea his, ad ius autem expetenda.</p>
</blockquote>
<p>No semper omnesque duo, ex mea abhorreant scribentur. Pro nemore comprehensam at. In praesent assentior mea, id decore dolore nam. Ea nec diam errem primis, id pro dolores forensibus instructior, alii natum adipiscing ne vis. Stet movet audiam ad his, an mel omittam persequeris.</p>
<p>Cu omnis delectus nam, eu atqui minimum eum, numquam equidem scaevola te mea. Cum ut probo clita, vivendo accumsan sententiae et eum. Eos no eros repudiandae, ex sit vidit meliore invenire. Nibh mentitum consulatu ei nam. Sed ad scripserit suscipiantur, duo ut case omnis evertitur:</p>
<ul>
<li>Id eum paulo appareat, ex cum habeo molestiae, eum nullam aliquam no. Possit delenit definitiones ad est, tollit tamquam malorum ea sit.</li>
<li>Id ignota habemus urbanitas vis.</li>
<li>Ne his alia imperdiet evertitur, est quas eripuit verterem ad. Mei ex iusto urbanitas scripserit. Malorum meliore postulant ut nam.</li>
<li>Ut quas erant tractatos vis. At timeam corrumpit dissentiunt ius, vel ei erat laboramus, est no graeco eloquentiam. Alii feugait sed an.</li>
<li>Eu vim fugit constituto sadipscing. Usu quot aliquip volutpat id, ut veritus vituperatoribus pro.</li>
</ul>
<p>Sed labitur pertinacia constituam in, eu graeco meliore instructior sit, nominati efficiendi theophrastus nec et.</p>
Less code (see full listing):
@main-font-family: 'Verdana', sans-serif;
@main-font-variation: 400;
@main-font-offset: 0.898;
@heading-font-family: 'Helvetica Neue', sans-serif;
@heading-font-variation: 700;
@heading-font-offset: 0.879;
@quote-font-family: 'Didot', serif;
@quote-font-variation: italic 400;
@quote-font-offset: 0.85;
.use-baseline-grid(16px, 1.5, main);
.use-column-grid(680px, 24px, 3);
html {
.font-baseline();
}
h1 {
.font-align(36px, 1.25, heading);
.padding-top(1);
.padding-bottom(0.5);
border-bottom: 2px solid;
.margin-bottom(1.5, -2px);
}
p {
.margin-bottom(1);
}
blockquote {
float: right;
.width(1.5);
.margin-left(@grid-gutter);
.font-align(24px, (5/6 * @baseline-height), quote);
p {
.margin-bottom(1);
}
}
ul {
position: relative;
list-style: none;
.margin-bottom(1);
li {
.margin-bottom(0.25);
.padding-left(@grid-gutter);
&:before {
position: absolute;
left: 0;
content: "\2013";
}
}
}
Baseline row height is a product of base font-size
and base line-height
of the document. For example, if the base font-size
equals 20px and base line-height
equals 1.5, then baseline row height is 30px.
Whenever you change any of font property of a block element, its baseline drifts off the parent baseline. In order to preserve baseline alignment you could manually adjust relative position of the element:
h1 {
font: 700 36px / 1.25 'Helvetica', sans-serif;
position: relative;
top: -16px;
}
These mixins can help automatically shift the element back to baseline. The offset is primarily a function of font-size
, line-height
and font-family
, and in many cases of font-variant
, font-weight
and font-style
. If we abstract the variability of each typeface variation via special ratio referred to as baseline offset, the actual offset is simply a function of font-size
, line-height
and baseline offset
.
Here are baseline offset values for a few popular typefaces:
Font | Offset |
---|---|
Arial | 0.847 |
Arial Black | 0.895 |
Comic Sans MS | 0.905 |
Courier New | 0.766 |
Georgia | 0.849 |
Impact | 0.899 |
Tahoma | 0.897 |
Times New Roman | 0.837 |
Trebuchet MS | 0.858 |
Verdana | 0.898 |
You can find offset values for many other typefaces (and their variations) including popular Google fonts in HTML source of the test suite.
When you are fine-tuning font size and line height, some combinations would make the library align text onto the previous baseline, potentially colliding with other copy. This can be fixed by adding additional margin to the target element or its siblings.
When you have multiple one-liners of different height stacked below each other you should also explicitly set their bottom margin, even if it's zero. .margin-bottom()
mixin automatically realigns the baseline for the next element, if the current element uses an odd value.
Defines baseline and exports other mixins.
- pixel or number
@size
- number
@height
- number
@offset
or keyword@name
- pixel
@baseline-size
- number
@baseline-height
- number
@baseline-offset
You can set baseline size in pixels:
.use-baseline-grid(16px, 1.5, 0.898);
Or as a scale step:
.use-custom-scale(16px, 8px 12px 13px 16px 20px 24px 30px 36px 42px 50px 74px 90px);
.use-baseline-grid(0, 1.5, 0.898);
You can also define baseline offset by referencing a font definition:
@verdana-font-family: 'Verdana', sans-serif;
@verdana-font-variation: italic 400;
@verdana-font-offset: 0.898;
.use-baseline-grid(16px, 1.5, verdana);
You must set font-size
and line-height
properties of html
element to the same values using font-baseline()
mixin:
html {
.font-baseline();
}
Sets background
property of an element to show baselines.
- (optional) number
@offset
- (optional) color
@color
main {
.show-baselines();
}
.font()
just changes the font-*
and line-height
properties of the element, while .font-align()
adjusts the element's offset to sit on the baseline as well.
- pixel or number
@size
- (optional) number
@height
- (optional) keyword
@name
or number@offset
NB! You can specify @size
in pixels or as a step on a font size scale, if you are using one (see below).
Provided we define the document baseline as follows:
@helvetica-font-family: 'Helvetica', sans-serif;
@helvetica-font-variation: italic 400;
@helvetica-font-offset: 0.845;
@verdana-font-family: 'Verdana', sans-serif;
@verdana-font-variation: normal 400;
@verdana-font-offset: 0.898;
.use-baseline-grid(16px, 1.5, verdana);
...we can set the font properties like this:
h1 {
.font-align(30px, 1.25, helvetica);
}
h1 + p {
.font(20px, 1.45);
}
...which, once compiled, looks like this...
h1 {
position: relative;
top: -10.732px;
top: -0.67075rem;
font: italic 400 30px / 1.25 'Helvetica', sans-serif;
font-size: 1.875rem;
}
h1 + p {
font: normal 400 20px / 1.45 'Verdana', sans-serif;
font-size: 1.25rem;
}
.height()
, .min-height()
, .max-height()
, .top()
, .bottom()
, .margin-top()
, .margin-bottom()
, .padding-top()
, .padding-bottom()
These mixins let you set the respective CSS property in baseline rows.
NB! When combining multiple elements with line heights that are not evenly divisible by your baseline, you should explicitly set .margin-bottom()
, even if it's zero. This mixin would take into account the difference and add it to the element's margin, preserving baseline alignment for its next sibling.
- number
@span
– number of rows - (optional) pixel
@nudge
div {
.max-height(5);
.padding-top(2, -1px);
border-top: 1px solid;
}
...which compiles to...
div {
max-height: 120px;
max-height: 7.5rem;
padding: 48px;
padding: calc(3rem - 1px);
border-top: 1px solid;
}
Calculates pixel and rem values for a number of baseline rows.
- number
@span
- pixel
@baseline-height-px
- rem
@baseline-height-rem
div {
.get-baseline-height(2);
height: @baseline-height-px;
height: @baseline-height-rem;
}
...compiles to...
div {
height: 48px;
height: 3rem;
}
Font size scale mixins let you define a custom scale and set elements' font size to a value from that scale. You can learn more about modular scales in More Meaningful Typography by Tim Brown. He also made this handy tool that you can use to generate modular scales.
Defines a custom scale and exports other mixins.
- pixel
@base
– base value - list
@values
– list of pixel values (must include@base
value)
- pixel
@scale-base
- list
@scale-values
You can define an arbitrary scale by passing a list of valid step values as the second argument:
// Scale steps: -3 -2 -1 0 +1 +2 +3 +4 +5 +6 +7 +8
.use-custom-scale(16px, 8px 12px 13px 16px 20px 24px 30px 36px 42px 50px 74px 90px);
After that, you can use .font-size()
mixin to set font-size
property of an element:
h1 {
.font-size(+6); // font-size: 50px; font-size: 3.125rem;
}
h2 {
.font-size(+5); // font-size: 42px; font-size: 2.625rem;
}
h3 {
.font-size(+4); // font-size: 36px; font-size: 2.25rem;
}
h1 + p {
.font-size(+2); // font-size: 24px; font-size: 1.5rem;
}
p {
.font-size(+0); // font-size: 16px; font-size: 1rem;
}
footer {
.font-size(-1); // font-size: 13px; font-size: 0.8125rem;
}
You must explicitly set font-size
property of html
element to @scale-base
, otherwise rem values may not evaluate to the same amount of pixels:
html {
font-size: @scale-base;
}
Sets font-size
property to a scale value.
- number
@step
h1 {
.font-size(4); // 4th step
}
Given the definition above, it will compile to:
h1 {
font-size: 36px;
font-size: 2.25rem;
}
Gets a scale value:
- number
@step
– scale step
- pixel
@scale-size
h1 {
.get-scale-size(4);
font-size: @scale-size;
}
...compiles to...
h1 {
font-size: 36px;
}