Separate layout from content
Tags: css, styles, layout, singleresponsibility
Published: 2019-04-22 09:55:01

---
title: Separate layout from content
published: true
description: How I applied the 'single responsibility principle' to choosing where to put layout styling.
tags: css, styles, layout, single-responsibility
cover_image: https://thepracticaldev.s3.amazonaws.com/i/1325laraoa4ykgztw99l.jpg
---

Just a quick post, to share a simple styling practice I've been applying for some time now: always separate layout styling from other styling.

Suppose I want to render a layout with one large item and two smaller ones:

```
  +-------------------------------------------------------+
  | #item-name            | #edit-button | #delete-button |
  +-------------------------------------------------------+
```

## The bad way

I could style the elements like this:

```
#container { display: flex; }
#item-name { flex: 1; /* ...other styles */ }
#edit-button { flex: .2; /* ...other styles */ }
#delete-button { flex: .2; /* ...other styles */ }
```

Notice how in the above snippet, layout styling is spread out between the container and the chidren. There are at least two practical maintainability issues with this:

* If I decide to swap out one of the children for another, then I have to remember to style the new element with the same `flex` as the previous one, in order to maintain the layout. For example, if I delete `#item-name` and its styling and create a new element in its place, e.g. `#item-image`, then I have to remember to apply `flex: 1` to `#item-image`.

* If I ever want to change the layout, I potentially have to modify many different elements in different parts of the code. For example, if I want to change the layout so that all the elements have an equal width, then I may have to hunt through many lines of code, in order to find and change the `flex` properties of the `#item-name`, `#edit-button` and `#delete-button` selectors.

The basic issue is that code concerned with layout is mixed in with code concerned with individual elements. This code has poor separation of concerns. Each "module" or style declaration forces me to think about multiple concerns at once (i.e. layout and component-specific concerns), so that it's difficult to make a change without impacting multiple modules. This is an example of a violation of the [Single responsibility principle](https://en.wikipedia.org/wiki/Single_responsibility_principle), which tells us that we should design our modules so that they hide "design decisions which are likely to change" from eachother.

## The better way

A better way is to **keep all the layout concerns together**, separate from the other concerns.

This can be done using the CSS [direct-descendent](https://www.w3schools.com/Css/css_combinators.asp) child selector, to select just immediate children, and the [`:first-child`](https://www.w3schools.com/cssref/sel_firstchild.asp) pseudo-selector, to make just the first child fill, while the rest of the children take up 20%.

```
/* layout styles on container ⬇️ */

#container {
  display: flex;

  > * {
    flex: .2;

    &:first-child {
      flex: 1;
    }
  }
}


/* non-layout styles on individual elements ⬇️ */

#item-name {
  /* item-name styles */
}

#edit-button {
  /* edit-button styles */
}

#delete-button {
  /* delete-button styles */
}
```

(Note: The above code snippet assumes support for nested styling, using a pre-processor such as [Less](http://lesscss.org/) or [SASS](https://sass-lang.com).)

Now I can re-order, swap and alter my child components, without having to remember to set their individual widths. That's all taken care of for me by the layout component. I can look at each component's style block and focus just that component's styles, without thinking about the layout.

Likewise, I can change the way the layout looks, without having to review the individual component styles. I could change the orientation to vertical, or make one child larger, or even change the whole layout to use [CSS Grid Layout](https://www.w3schools.com/css/css_grid.asp), all without modifying the styling of the individual children.

In the words of [Bob Martin](https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html), we want to "gather together the things that change for the same reasons ... separate those things that change for different reasons".