You have a deadline, you need to deliver something approximating the design before you fully implement even a part of the design.
So you'd use a framework that creates css... usually something like Foundation or Bootstrap.
<div class="hero row">
<div class="columns small-12 medium-4 hero-image">
<img src="/static/images/hero-image.png" />
</div>
<div class="columns small-12 medium-8 hero-content">
<h3>People don't buy what you do; they buy why you do it.</h3>
<p>
We are drawn to leaders and organizations that are good at communicating
what they believe. Their ability to make us feel like we belong, to make
us feel special, safe and not alone is part of what gives them the ability
to inspire us.
</p>
</div>
</div>
Great. It gets delivered and people get off your back.
Now you begin implementing the design. You rationalise that your framework has structured your page layout so all you need to do is fill in with colours and font sizes.
So you end up with something like:
.hero {
background-color: $lightblue;
}
.hero-image {
margin: 0 auto;
}
.hero-content {
padding: 1rem;
}
.body.home-page .hero {
background-color: $lightyellow;
}
.body.home-page .hero .hero-image {
margin-top: 10rem;
}
It works. you ship it. deadline is near or just passed by.
You rationlise the following choices:
- atomised classes so client requests to change
You've probably seen it around. .block__element--modifier
.
It .Has_Various-Styles
.
It also proposes a re-usable component way of controlling the css cascade.
A simple example of what we typically implement in our forms.
export default function TextFormField ({
id = cuid(),
label,
name,
type = 'text',
value
}) {
const classnames = (...parts) => parts.filter(part => !!part).join(' ')
return (
<div className={classnames(
'form-field',
'form-field--text',
type && `form-field--${type}`
)}>
<input className="form-field__input"
type={type}
id={id}
name={name}
required
value={value}>
<label className="form-field__label"
htmlFor={id}>
{label}
</label>
</div>
);
}
And reusing this amounts to:
import FormField from 'component-library/form-field';
import FormAction from 'component-library/form-action';
export default class App extends React.Component {
render() {
return (
<form
className="login-form"
onSubmit={this.handleSubmit}
>
<FormField
id={`login-form-${cuid()}`}
name="email"
value={this.state.email}
type="email"
/>
<FormField
id={`login-form-${cuid()}`}
name="password"
value={this.state.password}
type="password"
/>
<div className="form-field-group form-field-group--horizontal login-form__form-field-group">
<FormAction type="submit">login</FormAction>
</div>
</form>
);
}
}
Then to style it you need to write:
.login-form .form-field {
margin-bottom: 1rem;
}
.login-form .form-field__input {
border-color: grey;
}
.login-form .form-field__label {
color: grey;
}
Instead lets use BEM mixes:
export default function TextFormField ({
id = cuid(),
label,
name,
classNames,
mixClassName,
type = 'text',
value
}) {
const classnames = (...parts) => parts.filter(part => !!part).join(' ')
return (
<div className={classnames(
TextFormField.CONST__BASE_CLASSNAME,
`${TextFormField.CONST__BASE_CLASSNAME}--text`,
type && `${TextFormField.CONST__BASE_CLASSNAME}--${type}`,
mixClassName,
mixClassName && `${mixClassName}--text`,
mixClassName && type && `${mixClassName}--${type}`,
classNames && classNames
)}>
<input className={classnames(
`${TextFormField.CONST__BASE_CLASSNAME}__input`,
mixClassName && `${mixClassName}__input`,
)}
type={type}
id={id}
name={name}
required
value={value}>
<label className={classnames(
`${TextFormField.CONST__BASE_CLASSNAME}__label`,
mixClassName && `${mixClassName}__label`,
)}
htmlFor={id}>
{label}
</label>
</div>
);
}
TextFormField.CONST__BASE_CLASSNAME = 'form-field';
Now our app will look like :
import FormField from 'component-library/form-field';
import FormAction from 'component-library/form-action';
export default class App extends React.Component {
render() {
return (
<form
className="login-form"
onSubmit={this.handleSubmit}
>
<FormField
mixClassName="login-form__form-field"
classNames="login-form__email-form-field"
id={`login-form-${cuid()}`}
name="email"
value={this.state.email}
type="email"
/>
<FormField
mixClassName="login-form__form-field"
classNames="login-form__password-form-field"
id={`login-form-${cuid()}`}
name="password"
value={this.state.password}
type="password"
/>
<div class="form-field-group form-field-group--horizontal login-form__form-field-group">
<FormAction
mixClassName="login-form__form-action"
classNames="login-form__submit-form-action"
type="submit"
>
login
</FormAction>
</div>
</form>
);
}
}
Now our css can minimise the specificity score of our css.
.login-form {
border: 1px dashed silver;
}
.login-form__form-field {
margin-bottom: 1rem;
}
.login-form__form-field__input {
border: 1px dashed silver;
}
.login-form__form-field__label {
color: darkgrey;
}
.login-form__email-form-field {
/* some inspiring css */
}
.login-form__password-form-field {
/* some inspiring css */
}
.login-form__submit-form-action {
/* some inspiring css */
}
- It's an approach to minimising impact on the maintenance story, where time is more critical than initial development phase.
- Changes to particular implementations to
login-form
can be quarantined from each other.