1.2.1 • Published 4 years ago

@vrugtehagel/mcss v1.2.1

Weekly downloads
-
License
ISC
Repository
github
Last release
4 years ago

MCSS

The ultimate preprocessor for semantic and clean output CSS.

What is MCSS and why?

Let's face it, CSS is a horrible language. It is almost impossible to write nice, readable CSS because of the way CSS is structured. Selector, declarations, selector, declarations, at-rule, selector, declarations.

The major issue here, is the format. A CSS file is just a really long list of properties and values with no structure whatsoever. SASS tries to improve on this by introducing nesting. A great idea! It provides a little more structure, but it still ends up being a long list of (possibly differently indented) list of properties and values.

A lot of the CSS we write already has some structure. We often use width, height, padding, margin, display, position, and properties like these. They are the core properties of most elements. But, in a CSS file, they are all seperate and unrelated properties. We can't do anything about that, that's just how it is, but a preprocessor could very well group these together to make the file more readable and maintainable.

At-rules. For any responsive design, we will use @media rules - specifically max-width ones. It would be nice to have your at-rules right with the properties you're changing, but in CSS, we're more-or-less forced to throw them all at the bottom of the file. This is horrible for readability, because now you don't know what values change where.

MCSS tries to solve a lot of these things. It tries to make it possible to write CSS in a less vertically oriented format, while still outputting high-quality, clean CSS like a real human wrote it.

Installing MCSS

You can install MCSS using npm - simply run

npm install -g @vrugtehagel/mcss

and you're good to go! You can check if everything installed correctly by running mcss version. To compile a .mcss file to CSS, simply run

mcss filename.mcss

and it will output your gorgeous CSS to filename.css. Enjoy!

Feature list

Enough time wasted selling MCSS. Let's get to the good stuff!

Syntax

The first thing you should know, is that MCSS doesn't use { and }. CSS never really needed them, and they only contribute to the lengthy nature CSS has, so MCSS just got rid of them. For the rest, MCSS is almost identical to CSS in nature.

Nesting

Of course, no good preprocessor without this

p
  text-indent: 5em;
  color: black;
  a
    color: inherit;

MCSS uses the indentation to decide what property belongs to what selector. The above would output to

p {
  text-indent: 5em;
  color: black;
}

p a { color: inherit; }

MCSS allows properties and selectors to be on the same line, and it assumes that they would belong to the same selector. For example,

p
  text-indent: 5em; color: black;
  a color: inherit;

still has the same output as the previous example.

if statements

SASS has the & syntax for psuedoclasses and the like. MCSS uses a different syntax, more accurately representing what it does:

a
  color: blue;
  if(:visited)
    color: purple;

Which outputs to

a { color: blue; }
a:visited { color: purple; }

inside the if(), you're only allowed to filter the element with classes, an ID, attribute selector, or a pseudoclass. This syntax has some more benefits regarding transformations and transitions - more about those later.

Shortening margin and padding forever

Sometimes, you want to set the padding-left and padding-right properties without touching the padding-top and padding-bottom. With MCSS, you can use a period . to tell MCSS that you don't actually want to set this side of padding or margin.

div
  margin: . auto;
  padding: 10px 20px .;

Outputs

div {
  margin-right: auto;
  margin-left: auto;
  padding-top: 10px;
  padding-right: 20px;
  padding-left: 20px;
}

The model property

MCSS introduces a new property: model. It bundles all the properties related to the box model. The syntax is as follows:

model: [display | ]? [width] [height] [ | padding [ | margin [ | box-sizing]?]?]?;

So, here's a few examples:

section model: inline-block | 100% 500px | 50px | 0 auto . | border-box;
article model: 100vw 100vh | . | 50px 0;

will output

section {
  display: inline-block;
  width: 100%;
  height: 500px;
  padding: 50px;
  margin-top: 0;
  margin-right: auto;
  margin-left: auto;
  box-sizing: border-box;
}

article {
  width: 100vw;
  height: 100vh;
  margin: 50px 0;
}

The place property

Similar to the model, property, place bundles some related CSS properties. However, the place property is not as straight-forward as the model property. The syntax is

place: [position]? | [place-vertical] | [place-horizontal];

where

place-vertical: [anchorParent] [anchorThis]? [offset]?;
place-horizontal: [anchorParent] [anchorThis]? [offset]?;

Essentially, you have control over the anchor point of the element you're placing, as well as the position relative to the parent. Let's do an example:

button
  place: top bottom 18px | left left 0;

This means that the bottom of the placed element is an 18px distance from the parent's top edge, while the left side of the placed element has a distance of 0 relative to the left of its parent. The output results in

button {
  position: absolute;
  top: 18px;
  left: 0;
  transform: translateY(-100%);
}

If the position value is omitted, it will default to absolute. If you don't want to set the position property at all, don't fret! Like with margin and padding, you can give it a period . as value to ignore setting it.

anchorThis can also take percentage values; if you would like to anchor it to 20% below the top of the placed element, you can simly use place-vertical: top 20% 0;. If anchorThis is omitted, it will default to the value of anchorParent.

If offset is omitted, it will default to 0. Note that when setting anchorThis to a percentage value, setting offset is required. Otherwise, it will assume the value given is for offset, and it will assume anchorThis was omitted.

You may set place-vertical or place-horizontal directly. It also allows for a position property to be set, so valid syntax would be

place-vertical: absolute | top 40% 10em;

Lastly, there's some spice for you: centering elements has never been easier. You can now use the following syntax:

place-vertical: center [anchorThis]?;
place-horizontal: center [anchorThis]?;

Where if anchorThis is omitted, it will default to center as well, allowing for code like

button
  place: center | center right;

which would result in

button {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-100%, -50%);
}

Lastly, very often you will want to simply set place: top | left; or something similar (only setting the achorParent): therefore, you can omit the | as to make your life a little easier. Thus, we might write

button
  place: top left;

to get

button {
  position: absolute;
  top: 0;
  left: 0;
}

The palette property

The pallete property is a shorthand for color and background-color. The syntax is

palette: [color] on [background-color];
palette: [color] | [background-color];
palette: [color] [background-color];

So for example, we could do

button
  palette: white on rgb(20, 20, 40);
  if(:hover)
    palette: black white;

which will output

button {
  color: white;
  background-color: rgb(20, 20, 40);
}

button:hover {
  color: black;
  background-color: white;
}

Setting declarations for :root

In MCSS, you can write declarations on the top-most level, and MCSS will interpret them as being for the :root element. Useful for setting global CSS variables, as well as things like font-size.

--text-color: rgba(0, 0, 0, 0.3);
font-size: 18px;

outputs

:root {
  --text-color: rgba(0, 0, 0, 0.3);
  font-size: 18px;
}

Easy at-rules

You can set an at-rule inside a declaration by appending it to the value. For example:

font-size: 24px;
font-size: 18px @media (max-width: 1000px);

and this will compile to

:root { font-size: 24px; }

@media (max-width: 1000px) {
  :root { font-size: 18px; }
}

You can use multiple at-rules by simply listing them out:

section
  display: flex;
  display: grid @media (min-width: 1000px) @supports (display: grid);

which yields

section { display: flex; }

@media (min-width: 1000px) {
  @supports (display: grid) {
    section { display: grid; }
  }
}

Since using max-width and min-width is so common, MCSS has a shorthand for it: instead of writing @media (max-width: value) you can write @<value, and similarly for min-width. Note that this is only a shorthand for setting the value inside a declaration.

font-size: 30px @>2000px;
font-size: 24px;
font-size: 18px @<1000px;

outputs

:root { font-size: 24px; }

@media (min-width: 2000px) {
  :root { font-size: 30px; }
}

@media (max-width: 1000px) {
  :root { font-size: 18px; }
}

Easy transitions

MCSS allows you to define a transition for elements inside the declaration itself. It uses the following syntax:

property: value @ [transitionValue];

The whitespace after the @ is mandatory, or it will be interpreted as an at-rule. For transitionValue, you can give it anything you can give the transition property except the transition-property value. MCSS is smart about this though; it will never overwrite the transition you already set, but rather append this one to the existing transition property (or create it if no transition property has been set). For example:

button
  transition: all .2s;
  background-color: grey @ .5s linear;

compiles to

button {
  transition: all .2s, background-color .5s linear;
  background-color: grey;
}

Here's where the if() syntax really shines; setting a transition on a property selected using if(), MCSS will find the transition property of the original element, and set the transition property using all the values previously set as well. That means you can do:

button
  transition: all .2;
  border-radius: 10px;
  background-color: grey @ .5s;
  if(:hover)
    background-color: darkgrey @ 1s;
    border-radius: 0 @ 0s;
    border-width: 5px;

results in

button {
  transition: all .2, background-color .5s;
  border-radius: 10px;
  background-color: grey;
}

button:hover {
  background-color: darkgrey;
  transition: all .2,
    background-color 1s,
    border-radius 0s;
  border-radius: 0;
  border-width: 5px;
}

This way, the transitions won't be reset unless you actually want them to. Want to use this functionality, but without setting the transition using the @-notation? No worries! MCSS has got your back.

The add-transition property

You can use the add-transition property to, well, add transition properties if there already exists a transition property but you'd rather not touch it or you want to add to them in if() statements. That would work as follows:

button
  add-transition: color 1s 1s;
  transition: opacity .5s;
  if(:hover) add-transition: border-width .2s, border-radius .2s;

becomes

button { transition: opacity .5s, color 1s 1s; }

button:hover {
  transition: opacity .5s,
    color 1s 1s,
    border-width .2s,
    border-radius .2s;
  }

The add-transform property

Like the add-transition property, MCSS allows you to add transforms to an already-existing transform. So, you can do this now:

svg
  transform: scale(2) @ .5s;
  if(:hover)
    add-transform: rotate(360deg);

and that would look like

svg {
  transform: scale(2);
  transition: transform .5s;
}

svg:hover { transform: rotate(360deg) scale(2); }

Animations using @keyframes

There is a slight improvement on how you use @keyframes in MCSS. You now got the via keyword, that linearly interpolates between the last absolute value set before it and the first one after it. That means, you can do

@keyframes blinkOutInOut
  from opacity: 1;
  via opacity: 0;
  via opacity: 1;
  to opacity: 0;

outputting

@keyframes blinkOutInOut {
  from { opacity: 1; }
  33.333% { opacity: 0; }
  66.667% { opacity: 1; }
  to { opacity: 0; }
}

It will round floats to 3 decimals. You can also use via between any percentage values, for example:

@keyframes colorDance
  0%
    color: red;
    background-color: blue;
  10% color: green;
  via background-color: pink;
  via
    color: purple;
    background-color: tomato;
  40% color: blue;
  100%
    color: red;
    background-color: blue;

will become

@keyframes colorDance {
  0% {
    color: red;
    background-color: blue;
  }
  10% { color: green; }
  20% { background-color: pink; }
  30% {
    color: purple;
    background-color: tomato;
  }
  40% { color: blue; }
  100% {
    color: red;
    background-color: blue;
  }
}

Pseudoelements

The syntax in CSS, but in SASS even more, always has been a bit odd when it comes to psuedoelements. For example, the div::after element would be a child of the div, so it would make sense for it to have that structure when nesting properties. Thus, in MCSS, you can do:

span.asterisk
  font-weight: bolder;
  ::before content: "*";
  ::after content: "*";

will result in

span.asterisk { font-weight: bolder; }
span.asterisk::before { content: "*"; }
span.asterisk::after { content: "*"; }

Variables

MCSS doesn't have its own variables for the sake of keeping the CSS itself dynamic and easy to use. However, it slightly improves on CSS variables by eliminating the need for var(). You can now simply write the variable itself. For example:

--main-color: #FF9700;
--text-color: black;

body
  palette: --text-color on --main-color;

outputs

:root {
  --main-color: #FF9700;
  --text-color: black;
}

body {
  color: var(--text-color);
  background-color: var(--main-color);
}
1.2.1

4 years ago

1.2.0

4 years ago

1.1.12

4 years ago

1.1.9

4 years ago

1.1.11

4 years ago

1.1.10

4 years ago

1.1.8

4 years ago

1.1.7

4 years ago

1.1.6

4 years ago

1.1.5

4 years ago

1.1.4

4 years ago

1.1.3

4 years ago

1.1.2

4 years ago

1.1.1

4 years ago

1.1.0

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago