Skip to content

Instantly share code, notes, and snippets.

@seeliang
Last active July 16, 2021 00:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seeliang/e610bc7b3790309b4560a5e5fe77e869 to your computer and use it in GitHub Desktop.
Save seeliang/e610bc7b3790309b4560a5e5fe77e869 to your computer and use it in GitHub Desktop.
Style composition, the better way to organise your styling

Find me on medium

https://seeliang.medium.com

Style composition

Back in the good old days, when I started my career, styling was easy. You put framework on, modify a bit, all done. For short term projects, not a problem.

When I switched to building product / service, this approach led to large amount of technical debits in many cases

That is because the "cascade" in CSS.

It means, by default, we inherit styling from elements (tag) and attributes (class,id). Thus, in styling, we are facing the same old banana and gorilla problem in OO programing.

Struggling with the problem for few years, finally I found out how to improve code quality in styling.

Composition over inheritance can provide the quality you need for your product / service building process

Gain flexibility and robustness

When you started the project, CSS inheritance covers some deep issues in scaling up.

Here is a sample code of inheritance styling

CSS

p {
	font-size: 12px;
	line-height: 1.5
}

.heading {
	color: blue
}

HTML

<p class="heading"> this is heading style </p>

In this inheritance styling, the element .heading styling has two parts:

  1. has inherited font-size: 12px; line-height: 1.5 from p
  2. its own styling color: blue.

This would be fine for initial development, but could become an issue when we need to update the HTML.

Let's say we have a new SEO requirement: update tag to h2 (instead of p) in HTML. Based on the code above, the style will break (missing font style), since the .heading is relying on p tag to provide font style.

To solve this problem, we could use style composition.

(We are using sass as sample, it can be done in others solutions like Styled-components as well)

@mixin p {
	font-size: 12px;
	line-height: 1.5
}

p {
	@include p;
}

.heading {
	@include p;
	color: blue
}

Now, our .heading has all required style, when html p tag change to h2, nothing will change.

In the composition code, styling code is relatively more independent from HTML, as a flexible and robust styling should be.

This flexibility and robustness of coding could dramatically reduce code reconstruction in the process of scaling up, since styling sections are independent from others.

Improve code readability

To explain this point, let's take one step back and put our initial inheritance code in a more realistic folder structure file-a.scss

p {
	font-size: 12px;
	line-height: 1.5
}

file-b.scss

.heading {
	color: blue
}

When we are maintaining file-b.scss, since we could not see p styling, we may NOT be able to aware the base style from p. This visibility issue had create many technical debts (like unnecessary duplications) in my team, and it gets even worse the team were having a tight deadline. Besides, it is also harder to be noticed in code review process like pull request, since our file-a is could be untouched.

On the contrary, our composition code could present full picture of how things are styled.

bass.scss

@mixin p {
	font-size: 12px;
	line-height: 1.5
}
```css
**file-a.scss**
```css
p {
	@include p;
}

file-b.scss

.heading {
	@include p;
	color: blue
}

With @include p, this composition styling code is more readable and is self-documented.

Reduce side effects in styling

Now, we just received a new design update, the default p tag will need extra spacing, while .heading should be untouched.

Since our code is not fully following the composition style, all we need to do is

file-a.scss

p {
	@include p;
	margin-top: 8px; // the actual design update
}

file-b.scss

.heading {
	@include p;
	margin-top: 0; // the reset design update
	color: blue
}

HTML

<p class="heading"> this is heading style </p>

Noticing that the margin-top: 0; is NOT the styling that is required by .heading, but it is needed to cover the side effects from p. That is because .heading still inherited unnecessary styling from p via HTML.

Here is the better composition code to rescue

file-a.scss

p:not([class]) {
	@include p;
	margin-top: 8px; // the actual design update
}

file-b.scss

.heading {
	@include p;
	color: blue
}

By adding :not([class]) for p, our margin-top: 8px; is now only relevant to p styling with no class. Thus there will be no styling inherited from p when we have a class.

Now .heading has way better of its styling.

NOTE: this is sample of classes based styling solution like BEM or SMACSS


Summary

The main idea of using style composition is try to limit the inheritance between elements / components.

Compare to inheritance, style composition is:

  • more flexible and robust
  • more readable code
  • less likely to have side effects

style composition is still consistent (which is the main reason, we use inheritance), as long as we are using the same sharing code base like @include p.

All of above made style composition a better candidate for building high quality code base.

Extra

I would like to address one thing before we close the topic:

that is Choosing third party library/plugin/framework wisely:

Composition over inheritance is main reason many experienced developers are NOT using styling frameworks (like bootstrap) for their scalable project.

Because using OOCSS framework as the base, we will have to start our project with override framework (the design will never be the same as third party framework style) in inheritance styling. Following with layers of change requests, the styling of project will be extremely difficult to maintain very soon.

Try it out and let me know what do you think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment