Tags : CSS Web 2.0

Modern CSS Techniques

Tags : CSS Web 2.0

Imagine that you wanted to keep the class names in your HTML as simple and functionally-semantic as possible, but you also wanted to have re-usable generic styles, with presentational-semantics, to avoid repetition.

This is where a CSS pre-processor like SASS can come in handy. You can use SASS extends or mixins to create a ‘bridge’ between the generic classes and the module specific class names.

EG:

.latest-blog-posts h3
{
    @include generic-title-1;
}

This allows you to create any kind of new HTML with functionally-semantic class names, while using a library of generic styles. The mixin code looks like this:

@mixin generic-title-1
{
    padding: 10px;
    font-size: 48px;
    color: red;
}

Extends or Mixins?

Some people prefer to only use extends when it describes a relationship between an element and a placeholder. For example, ‘.button-1’ is a ‘%button’. Extends cannot be used inside a media query, unless the placeholder is defined there. This is the biggest limitation for using extends.

Remember that when you use extends, the order in which the code is rendered is based upon the placeholders’ positions, not the extend declarations. As long as you keep this in mind, you should be able to avoid any issues with extends and placeholders.

Mixins will avoid code-ordering issues and can be used inside media queries without having to declare them inside the media query. This is why I prefer mixins - my library of styles can be used anywhere I want them.

Other considerations

I also recommend that you split your SASS into different files. EG, for a small site you could use:

  • _reset.scss
  • _variables.scss
  • _mixins.scss
  • _base.scss
  • Site.scss

Then use Site.scss to import the other files and implement your ‘Bridge’.

Controlled, SASS-based workflow

Typically, over a long period of time, websites start to accrue a lot of unused classes and code repetition. Mistakes are made and bugs appear, mostly because of the time and number of steps required to maintain it properly. Every time you make a significant change or addition to a website, the CSS should be assessed for refactoring. For example, there may be repetition that can logically be abstracted out into a class, or there may be unused classes that are no longer required.

The main benefit of using a SASS-based workflow is the ease of refactoring and the information that can be obtained just by the code organisation. In the above structure example, we can show a relationship between files like this:

Includes / base > mixins > variables

Since each file only contains one SASS feature, it’s easy to spot refactoring opportunities. Take a look at your includes (site.scss) file, what do you see? A bunch of semantic classes that are including mixins. Anything else is easy to spot, as it stands out. If you see any property / value pair being repeated, this could signal an opportunity to refactor your CSS.

For example, if you see this:

.home-news-posts h2
{
    @include generic-title-1;

    padding-top: 30px;
    font-size: 20px;
}

You know that these properties – padding-top and font-size - are an override of a mixin value, meant only for this widget. You can easily search the file to see if there are any other instances of these properties being used for another heading. If there are, you can decide to make a new mixin to represent this new style. Then you can remove the overrides from the includes file and change the code to use the new mixin instead.

Then you can take a look at the mixins file and do essentially the same thing – except with property values:

@mixin generic-title-1
{
    padding: 10px;
    font-size: 48px;
    color: red;
}

These values are hard-coded – are they being repeated anywhere? For example, the colour may be a branding colour and may be better represented as a variable - $color-brand-primary. You can now add a variable to the variables file and refactor the mixins file so that each instance of ‘red’ uses the variable instead.

Mixin Categories

I briefly touched upon this in the previous CSS article, but I will expand on it here as I believe that a good standard in this area is crucial to maintainability.

Your mixins should be separated into different categories, each using a different prefix:

Structure s-

Think of this as your grid framework. These mixins or classes should only contain what is necessary to provide a layout. If you use Bootstrap grids, you don’t need to worry about this and they won’t have a prefix.

Since HTML is structured content, with no separation between content and structure, there’s no point in avoiding presenation-semantic classes. If you change the structure, you will most likely be changing your HTML anyway. So I have no problem with using these class names in my HTML.

However, I do recommend that you use DIVs with your grid framework and that you don’t use grid classes on semantic elements.

For example, if you have a label and an input element that are to be displayed side by side, I would not put the grid classes directly on those elements. I would instead create DIVs around those elements. This would avoid any conflicting styles and make the form easy to change in the future.

Positioning p-

These mixins can be used to change the positioning of an element. For example:

@mixin p-pin-top-right-with-padding
{
    position: absolute;
    top: $padding-generic;
    right: $padding-generic;
    z-index: 1;
}

Component c-

This is the main category that will be used to create your widgets. Everything that affects the look of a component in a black & white context will be here. EG:

@mixin c-button-bordered
{
    padding: 10px;
    border-width: 2px;
    border-style: solid;
 
    font-size: 16px;
    text-transform: uppercase;
}

Theme t-

This will only be used to define colours. EG:

@mixin t-button-brand
{
    border-color: $color-brand;
    color: $color-brand;
}

Since these exist as a separate category, it’s easy to swap one theme for another in the includes file, or change the theme depending on the state.

Tooling

This idea now opens the door for tooling. With such a logically separated structure, we can imagine a world where a simple plugin can do the following:

  • Detect repetition in your includes file, suggest a new mixin and even suggest the name for it.
  • Detect repetition in a variables file, suggest a new variable and the name for it.
  • Provide autocomplete / suggestions within your includes file.
  • Warn you if you break what you consider to be a ‘best practice’, such as:
    • Including more than one of a type of mixin (theme, component, layout etc.)
    • Using nesting for anything other than states.

If you name your mixins and variables logically, a plugin could understand what you’re trying to do and help you out.

I would recommend this naming scheme for component mixins: prefix-component-differentiation. An example would be:

  • c-button-bordered
  • c-button-large
  • c-button-small

And something similar for theme mixins:

  • c-button-brand
  • c-button-brand-inverted

And for positioning mixins:

  • p-pin-top-right
  • p-pin-top-right-with-padding

For vairables, I would start with the property name:

  • $color-text
  • $color-brand
  • $font-size-text
  • $padding-button

Repetition

So what type of repetition are we looking to avoid? Repetition of ideas within the source files. Not necessarily repetition of values. It’s fine to repeat values if they are not theoretically related.

If a heading has 10px of padding and a link has a font size of 10px, then they have the same value – But they are not the same idea. You wouldn’t use the same variable to represent both values. This example is obvious, but sometimes we get into the habit of trying to over-DRY everything and we start to find relationships in values where there are none.

If my heading has 10px of padding and my buttons have 10px of padding, is there a relationship? Should this be a generic-padding variable? This is where the decision gets difficult. You will need to assess the entire design to see if this is a common theme and how many elements may use this idea.

You need to ask yourself:

If the client wants to change the padding of a heading, should the button padding also change? Should all other elements that use this padding value change as well?

In this case, I would say ‘no’. It was easy for me to fantasise about a generic-padding variable. It seemed so DRY, so beautiful, so warm and cuddly. But in a practical sense, it doesn’t work.

Variables and placeholders are not really ‘generic’, they have a specific purpose. They should still maintain a loose relationship with how they will be used. A heading style will always be used for headings; a button style will always be used for buttons.

For this reason, all of my variables and mixins always contain the name of the widget that they will be used with. EG:

c-button-bordered
t-heading-brand
$padding-button
$padding-heading

Conclusion

The point of this article is that defining and using an approach, with processes and standards, is the best way to do things. As long as you have documented what you’re doing, how it all works and how to refactor when things change, then you’re going to be successful.