Info

Classes are undoubtedly the most powerful and dynamic concept in ctr. In comparative terms, all other features in ctr are more or less sugary abstractions over CSS to that of classes. But before you jump off this cliff with me it’s essential to learn why you would want to jump in the first place.

The idea of “classes” is the same, or similar, to that of extend depending on your definition. For many years it’s been an elusive dream for legions in the CSS community. In fact, way back in 2013 before I even knew what CSS was, Philip Walton wrote an article titled “The Future of OOCSS: A Proposal” in which he posed two fundamental questions. What if CSS had Object Oriented functionality built in? Further, what if there was a way to create a rich hierarchy of inherited CSS components that didn’t require listing each class in the HTML every single time? Only recently did I have the pleasure to learn about Philip’s work and I’m happy to report I have an answer to these two questions.

The Problem

It’s age old wisdom that a multi-class CSS pattern in HTML is a superior approach to maintainable scalability compared to that of a single-class approach. The principal reason can be demonstrated through a good old fashion button dilemma. It’s a common dilemma that we all face: there are three different types of buttons we need to create for our money-making website all of which share common properties but none of which are the same.

For the sake of simplicity, we have a .hook, .line, and .sinker button, and they all share the following CSS dimension properties.

.button {
width: 125px;
height: 75px;
}

Now comes the dilemma; each button will have a different background. One solution is to create a separate class for each button like so.

.hook-button {
width: 125px;
height: 75px;
background: green;
}

However, since we are astute developers practiced in the dark arts of CSS wizardry we recognize this solution is repetitive, and it violates the DRY (don’t repeat yourself) CSS principal. As such, we decide to leverage class inheritance to inherit the .button class and then create a separate background class for each style.

<body>
<!-- hook content -->
<div class="button hook"></div>
<!-- line content -->
<div class="button line"></div>
<!-- sinker content -->
<div class="button sinker"></div>
</body>

Things are looking great, but then we realize the design is a bit too edgy for our tastes do we decide to add a border-radius property to .line and .sinker. Here’s where things get tricky because one solution is to add border-radius directly to .line and .sinker. Another valid and multi-class solution is to create a separate border-radius class and apply it to .line and .sinker. Nonetheless, once the border-radius dilemma is figured out, we then decide the color of the text is not fitting, and then, and then, and then. This is the crux of the button dilemma, it’s the inevitability of the next “and then(s)” compounded with the desire to not repeat yourself.

The Solution

I believe good design comes from iterations of decent design, which is why I find a single-class approach very enticing compared to that of a multi-class approach. With a single class, I can quickly target and alter any element without having to worry about potential side effects. Yet, as exemplified in the button dilemma, it’s an ill-advised pursuit. Cue the lights and grab the popcorn because the stage is set for extend — aka classes.

The core concept of extend is the ability to “extend” the properties of one class into another. For instance, we could extend the .button into .hook thus mitigating our button dilemma and achieving the same result as stacking classes in HTML: class="button hook". The origins of this concept stem from a principle characteristic in classical Object Oriented programming that allows a base class to be extended into a target class. In doing so, the target class inherits all of the properties and methods of said base class. In short, classes are a way to extend a “base” ctr class into any ctr instance. Hence, instead of stacking CSS classes in HTML, ctr classes are designed to be stacked in ctr instances to create a CSS-centric multi-class pattern rather than an HTML-centric one.

The relationship shift that ctr classes introduce streamlines the design process in a manner that eliminates the inevitable fragmentation that occurs in an HTML multi-class design pattern. Not only do classes centralize styles but they also eradicate the pains of CSS priority rules since what you see is what you get. In that, a ctr instance scope can only have a single background property. However, the party does not stop there: multiple classes can rely on shared variables while retaining fine grain control and extensibility on an individual level. The abstraction provided by classes, combined with everything else ctr has to offer, creates an absurd amount of flexibility and control which is nothing short of delicious. So to answer your question Philip, it’s delicious, it’s really fucking delicious. In fact, I would go so far as to say it’s in the same league as my Mother’s baking.

A Word of Caution

Classes are the one feature in ctr that give me pause because they can quickly turn against you. Admittedly, classes are a half-baked idea that I implemented during the latter part of the development, but by that time the core data structure of ctr was beyond rewriting. As a consequence, I was not able to implement various controls which I believe are needed to a large extent. For example, classes can extend other classes but I recommend you shy away from doing so as of right now. With the rewrite of ctr, classes will be treated as a first-class citizen and not as an afterthought and will include debugging and control features which are currently lacking. That being said, I’m not your Mother and you can do as you please, but if things go awry don’t tell me I didn’t warn you.

Syntax

Description: ctrSetClass and CtrClass is defined as a method to create a <class> instance of predefined ctr styles.

ctrSetClass('<class>', {
<...>: <...>
})
// longhand
ctr('<#selector>', {
extend: {
// String | List
class: '<class>'
}
})
ctr:::setClass:<class>:
<...>: <...>
# longhand
<#selector>:
extend:
# String | List
class: <class>
ctrSetClass('<class>', {
<...>: <...>
})
// shorthand
ctr('<#selector>', {
// String | List
extend: '<class>'
})
ctr:::setClass:<class>:
<...>: <...>
# shorthand
<#selector>:
# String | List
extend: <class>
// Assigns Stylus Variable
<class> = CrtClass({
<...>: <...>
})
// longhand
ctr('<#selector>', {
extend: {
// String | Literal
class: <class>
}
})
// Assigns Stylus Variable
<class> = CrtClass({
<...>: <...>
})
// shorthand
ctr('<#selector>', {
// String | Literal
extend: <class>
})

Notes

Basic

Description: A ctrSetClass instance creates an internal data reference to the <class> name. This <class> name can then be referenced in a ctr instance through the extend property to merge its data into the ctr instance at the scope level it is defined.

Edit
// create class
ctrSetClass('Box', {
width: 200px
height: 400px
})
ctr('.test', {
extend: 'Box'
})
# create class
ctr:::setClass:Box:
width: 200px
height: 400px
.test:
extend: Box
.test {
width: 200px;
height: 400px;
}
// create class
ctrSetClass('Box', {
  width: 200px
  height: 400px
})

ctr('.test', {
  extend: 'Box'
})
.test {
  width: 200px;
  height: 400px;
}
# create class
ctr:::setClass:Box:
  width: 200px
  height: 400px

.test:
  extend: Box

Notes

With Data

Description: A <class> can can be extended with data and at any scope level.

Edit
ctrSetClass('Box', {
width: 200px
height: 400px
})
ctr('.test', {
width: 200px
components: {
'.blue-box': {
extend: 'Box'
background: blue
}
'.red-box': {
extend: 'Box'
background: red
height: 500px
}
}
})
# create class
ctr:::setClass:Box:
width: 200px
height: 400px
.test:
width: 200px
components:
.blue-box:
extend: Box
background: blue
.red-box:
extend: Box
background: red
height: 500px
.test {
width: 200px;
}
.test > .blue-box {
width: 200px;
height: 400px;
background: #00f;
}
.test > .red-box {
width: 200px;
height: 500px;
background: #f00;
}
ctrSetClass('Box', {
  width: 200px
  height: 400px
})

ctr('.test', {
  width: 200px
  components: {
    '.blue-box': {
      extend: 'Box'
      background: blue
    }
    '.red-box': {
      extend: 'Box'
      background: red
      height: 500px
    }
  }
})
.test {
  width: 200px;
}
.test > .blue-box {
  width: 200px;
  height: 400px;
  background: #00f;
}
.test > .red-box {
  width: 200px;
  height: 500px;
  background: #f00;
}
# create class
ctr:::setClass:Box:
  width: 200px
  height: 400px

.test:
  width: 200px
  components:
    .blue-box:
      extend: Box
      background: blue
    .red-box:
      extend: Box
      background: red
      height: 500px

Notes

Multiple

Description: A List value of classes for the extend property extends the class data into the ctr instance in the order it is received.

Edit
ctrSetClass('Box', {
width: 200px
height: 400px
})
ctrSetClass('Round-Soft', {
border-radius: 4px
})
ctr('.test', {
width: 200px
'component-.blue-box': {
extend: 'Box' 'Round-Soft'
background: blue
}
})
ctr:::setClass:Box:
width: 200px
height: 400px
ctr:::setClass:Round-Soft:
border-radius: 4px
.test:
width: 200px
component-.blue-box:
extend: [Box, Round-Soft]
background: blue
.test {
width: 200px;
}
.test > .blue-box {
width: 200px;
height: 400px;
background: #00f;
border-radius: 4px;
}
ctrSetClass('Box', {
  width: 200px
  height: 400px
})

ctrSetClass('Round-Soft', {
  border-radius: 4px
})

ctr('.test', {
  width: 200px
  'component-.blue-box': {
    extend: 'Box' 'Round-Soft'
    background: blue
  }
})
.test {
  width: 200px;
}
.test > .blue-box {
  width: 200px;
  height: 400px;
  background: #00f;
  border-radius: 4px;
}
ctr:::setClass:Box:
  width: 200px
  height: 400px

ctr:::setClass:Round-Soft:
  border-radius: 4px

.test:
  width: 200px
  component-.blue-box:
    extend: [Box, Round-Soft]
    background: blue

Notes

Extend Class

Description: A <class> can extend another <class>.

Edit
ctrSetClass('Box', {
width: 200px
height: 400px
})
ctrSetClass('Box-Round-Soft', {
extend: 'Box'
border-radius: 4px
})
ctr('.test', {
width: 200px
'component-.blue-box': {
extend: 'Box-Round-Soft'
background: blue
}
})
ctr:::setClass:Box:
width: 200px
height: 400px
ctr:::setClass:Box-Round-Soft:
extend: Box
border-radius: 4px
.test:
width: 200px
component-.blue-box:
extend: Box-Round-Soft
background: blue
.test {
width: 200px;
}
.test > .blue-box {
width: 200px;
height: 400px;
background: #00f;
border-radius: 4px;
}
ctrSetClass('Box', {
  width: 200px
  height: 400px
})

ctrSetClass('Box-Round-Soft', {
  extend: 'Box'
  border-radius: 4px
})

ctr('.test', {
  width: 200px
  'component-.blue-box': {
    extend: 'Box-Round-Soft'
    background: blue
  }
})
.test {
  width: 200px;
}
.test > .blue-box {
  width: 200px;
  height: 400px;
  background: #00f;
  border-radius: 4px;
}
ctr:::setClass:Box:
  width: 200px
  height: 400px

ctr:::setClass:Box-Round-Soft:
  extend: Box
  border-radius: 4px

.test:
  width: 200px
  component-.blue-box:
    extend: Box-Round-Soft
    background: blue

Notes

classLock

Description: For extra safety, the classLock option can be turned on to effectively lock all classes from being modified or overwritten during runtime development.

Edit
// turn on classLock
ctrSetOption({
classLock: true
})
ctrSetClass('Box', {
width: 200px
height: 200px
})
// Will not be able to overwritten or modified
ctrSetClass('Box', {
width: 444444px
height: 44444px
})
// width + height still 200px
ctr('.test', {
extend: 'Box'
})
# turn on classLock
ctr:::setOption:
classLock: true
ctr:::setClass:Box:
width: 200px
height: 200px
# NOTE: In YAML you can't have duplicate keys
# Will not be able to overwritten or modified
# ctr:::setClass:Box:
# width: 444444px
# height: 44444px
# width + height still 200px
.test:
extend: Box
.test {
width: 200px;
height: 200px;
}
// turn on classLock
ctrSetOption({
  classLock: true
})

ctrSetClass('Box', {
  width: 200px
  height: 200px
})

// Will not be able to overwritten or modified
ctrSetClass('Box', {
  width: 444444px
  height: 44444px
})

// width + height still 200px
ctr('.test', {
  extend: 'Box'
})
.test {
  width: 200px;
  height: 200px;
}
# turn on classLock
ctr:::setOption:
  classLock: true

ctr:::setClass:Box:
  width: 200px
  height: 200px

# NOTE: In YAML you can't have duplicate keys
# Will not be able to overwritten or modified
# ctr:::setClass:Box:
#   width: 444444px
#   height: 44444px

# width + height still 200px
.test:
  extend: Box

Notes